2015年10月17日 星期六

iPhone iOS 藍芽 支援 AVAudioSession 音響 切換 耳機


iPhone iOS 藍芽 支援 音響 切換 耳機

AVAudioSession bluetooth support
 December 17, 2014  Nikola Sobadjiev
Adding Bluetooth audio support to an iOS app 

[session setCategory:AVAudioSessionCategoryPlayAndRecord 
         withOptions:AVAudioSessionCategoryOptionAllowBluetooth
               error:&error]; 

Switching to bluetooth

- (AVAudioSessionPortDescription*)bluetoothAudioDevice
{
    NSArray* bluetoothRoutes = @[AVAudioSessionPortBluetoothA2DP, AVAudioSessionPortBluetoothLE, AVAudioSessionPortBluetoothHFP];
    return [self audioDeviceFromTypes:bluetoothRoutes];
}

- (AVAudioSessionPortDescription*)builtinAudioDevice
{
    NSArray* builtinRoutes = @[AVAudioSessionPortBuiltInMic];
    return [self audioDeviceFromTypes:builtinRoutes];
}

- (AVAudioSessionPortDescription*)speakerAudioDevice
{
    NSArray* builtinRoutes = @[AVAudioSessionPortBuiltInSpeaker];
    return [self audioDeviceFromTypes:builtinRoutes];
}

- (AVAudioSessionPortDescription*)audioDeviceFromTypes:(NSArray*)types
{
    NSArray* routes = [[AVAudioSession sharedInstance] availableInputs];
    for (AVAudioSessionPortDescription* route in routes)
    {
        if ([types containsObject:route.portType])
        {
            return route;
        }
    }
    return nil;
}

- (BOOL)switchBluetooth:(BOOL)onOrOff
{
    NSError* audioError = nil;
    BOOL changeResult = NO;
    if (onOrOff == YES)
    {
        AVAudioSessionPortDescription* _bluetoothPort = [self bluetoothAudioDevice];
        changeResult = [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort
                                                     error:&audioError];
    }
    else
    {
        AVAudioSessionPortDescription* builtinPort = [self builtinAudioDevice];
        changeResult = [[AVAudioSession sharedInstance] setPreferredInput:builtinPort
                                                     error:&audioError];
    }
    return changeResult;
}
Wow, that was a lot of code! Well, the important bit is setting the preferred input in the last method. The other code is just to get the right AVAudioSessionPortDescription object for speaker, earphone or bluetooth.

Switching to speaker
While there are other way to do that, this is what I prefer to use:

- (BOOL)switchSpeaker:(BOOL)onOrOff
{
    NSError* audioError = nil;
    BOOL changeResult = NO;
    if (onOrOff == YES)
    {
        changeResult = [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
                                                           error:&audioError];
    }
    else
    {
        AVAudioSessionPortDescription* builtinPort = [self builtinAudioDevice];
        changeResult = [[AVAudioSession sharedInstance] setPreferredInput:builtinPort
                                                                    error:&audioError];
    }
    return changeResult;
}
Switching to earpiece
This one is easy. It’s just the opposite of switching to speaker:

- (BOOL)switchEarphone:(BOOL)onOrOff
{
    return [self switchSpeaker:!onOrOff];
}

AVAudioSession bluetooth support can be a daunting task. And there isn't much information about it in the internet. I hope this article helps you with your task. Thanks for reading!
Share this:
Share
Related Posts:

Text to speech in iOS – AVSpeechSynthesizer tutorial 

UIPageViewController tutorial 

NSURLProtocol tutorial
Tutorials AVAudioSession, bluetooth, ios, Objective-C
Post navigation
← DevMonologue has a new lookTop articles for 2014 →
10 thoughts on “AVAudioSession bluetooth support”

 S
- February 16, 2015 at 4:37 pm
builtinAudioDevice is used in switchSpeaker? And speakerAudioDevice isn’t used. Are you sure this is ok?

Reply
 Nikola Sobadjiev
- February 17, 2015 at 3:22 pm
Yes, it should be OK. We cannot use speakerAudioDevice to go to speaker in switchSpeaker. That’s because we rely on the setPreferredInput:error: method to switch the audio device. However, it sets the preferred input. And the speaker is an output, not input. In fact, the earpiece and the speaker use the same input device – the built-in mic.

In my testing the only reliable way to go to the speaker is via the overrideOutputAudioPort:error: method and AVAudioSessionPortOverrideSpeaker.

Reply
 Jakob Olsen
- March 6, 2015 at 7:11 am
Hi, great post.

Would it be possible to make the audio route from builtin Microphone to bluetooth headset ?
if how yes could ou be so kind and show me in an example ?

Br
Jakob

Reply
 Nikola Sobadjiev
- March 9, 2015 at 11:41 am
Doesn’t the sample code in the article work? It should be something like:

NSArray* bluetoothRoutes = @[AVAudioSessionPortBluetoothA2DP, AVAudioSessionPortBluetoothLE, AVAudioSessionPortBluetoothHFP];
AVAudioSessionPortDescription* _bluetoothPort = [self audioDeviceFromTypes:bluetoothRoutes];
changeResult = [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort
error:&audioError];

Reply
 Stas
- April 7, 2015 at 10:30 pm
Hi
Is it possible to make bluetooth mic for input and device speaker for output?

Or they still didn’t changed this rule?
Moreover, selecting a Bluetooth HFP output using the MPVolumeView’s route picker will automatically change the input to the Bluetooth HFP input. Therefore both the input and output will always end up on the Bluetooth HFP device even though only the input or output was set individually.

Thx

Reply
 Nikola Sobadjiev
- April 10, 2015 at 1:46 pm
I personally haven’t tried to achieve that, but it seems that every time you change either the input or output, iOS changes the audio device altogether.

Reply
 Subrata Laha
- August 4, 2015 at 5:12 am
Hi , anyone have tried the same problem (bluetooth mic for input and device speaker for output) ? Please let me know , thanks in advance .

Reply
 Nikola Sobadjiev
- August 4, 2015 at 8:23 am
I don’t think you’ll be able to achieve this with AVAudioSession. If you really need to implement that feature, you’ll probably have to use CoreBluetooth and handle things from a really low level.

Reply
 raja
- April 20, 2015 at 2:45 pm
i am doing music app.

this is my stackoverflow link about my problem

http://stackoverflow.com/questions/29740589/ios-how-to-play-buffering-audio-in-bluetooth-headset-in-my-music-app

i applied your code. now my doubt is

when we need to call these below methods?
– (BOOL)switchBluetooth:(BOOL)onOrOff
– (BOOL)switchEarphone:(BOOL)onOrOff
– (BOOL)switchSpeaker:(BOOL)onOrOff


Reply

Nikola Sobadjiev
- April 22, 2015 at 8:30 am
Normally, you’d call one of these methods in response to a user action. When you support multiple audio sources, you’d want to allow your users to choose between them at runtime.

You can call them reliably even after playback has started. They’ll still change the audio device.

In your case, provided that you always what the audio to go through the bluetooth headset, you’d want to call switchBluetooth: before starting your audio, but after you activate the audio session and set the category via the setCategory: method of AVAudioSession

Reply

沒有留言: