Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't control the Speaker on iPad

I have followed method that takes care about my speaker state:

AudioSession.h

enum {
    kAudioSessionOverrideAudioRoute_None    = 0,
    kAudioSessionOverrideAudioRoute_Speaker = 'spkr'
};

MyClass

@synthesize speakerEnabled;

...

- (void)setSpeakerEnabled:(BOOL)enable {
speakerEnabled = enable;
if(enable) {
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;  
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute
                             , sizeof (audioRouteOverride)
                             , &audioRouteOverride);
 } else {
    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;  
    AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute
                             , sizeof (audioRouteOverride)
                             , &audioRouteOverride);
 }
}

However it works on iPhone only, for iPad - nothing happens.

  • When I press on button: Speaker On, I enter to if(enable) and AudioSessionSetProperty receives kAudioSessionOverrideAudioRoute_Speaker;

  • When I press on button: Speaker Off, I enter to else and AudioSessionSetProperty receives kAudioSessionOverrideAudioRoute_None;

I started to debug and din't find difference between to devices.

I have iPad2 iOS 6.1.

Did I miss something?

please, help me

Edit

As LombaX says I added on launch application AVAudioSession category:

NSError *err = nil;
    BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&err];

    if(!success){
        [MyLogger logc:MyLoggerLog format:"%@",[err localizedDescription]];
    }

success = YES

Still doesn't work.

like image 989
Maxim Shoustin Avatar asked Apr 26 '13 07:04

Maxim Shoustin


1 Answers

I think you misunderstand the use of this property. You are hoping to enable/disable your speaker. That is not quite the intent of kAudioSessionProperty_OverrideAudioRoute. Rather, it affects the output sound routing, in a fairly limited manner.

These are the various possible output routes avaiable to the iPhone

extern const CFStringRef kAudioSessionOutputRoute_LineOut           
extern const CFStringRef kAudioSessionOutputRoute_Headphones            
extern const CFStringRef kAudioSessionOutputRoute_BluetoothHFP        
extern const CFStringRef kAudioSessionOutputRoute_BluetoothA2DP      
extern const CFStringRef kAudioSessionOutputRoute_BuiltInReceiver   
extern const CFStringRef kAudioSessionOutputRoute_BuiltInSpeaker    
extern const CFStringRef kAudioSessionOutputRoute_USBAudio            
extern const CFStringRef kAudioSessionOutputRoute_HDMI              
extern const CFStringRef kAudioSessionOutputRoute_AirPlay   

These are only possible routes - what is actually available is context-dependent. Apple severely restricts your ability to determine these routes in-app as it is something that the user needs to control in a device-consistent manner. Most of them are determined implicitly by the user plugging/unplugging hardware (headphone, USB, HDMI, line out), and Apple doesn't want your app to mess with user expectations here.

Airplay can be selected using MPVolumeView's routeButton if the media context is correct (and airplay is available). Bluetooth can be guided by OverrideCategoryEnableBluetoothInput (which controls both input and output)

IN particular, note that kAudioSessionOutputRoute_BuiltInReceiver is the low-level speaker on the iPhone you hold to your ear when making a phone call. This is the default audio output route for the iPhone if an external device (eg headphones) is not plugged in. kAudioSessionOutputRoute_BuiltInSpeaker is the 'handsfree' louder speaker at the bottom of the phone.

You can reroute from whatever the current default is to this BuiltInSpeaker by setting one of these override properties:

key: kAudioSessionProperty_OverrideAudioRoute
values:   kAudioSessionOverrideAudioRoute_Speaker
      :   kAudioSessionOverrideAudioRoute_None

Specifies whether or not to override the audio session category’s normal audio route.

key: kAudioSessionProperty_OverrideCategoryDefaultToSpeaker
values:   TRUE
      :   FALSE

Specifies whether or not to route audio to the speaker (instead of to the receiver) when no other audio route, such as a headset, is connected.

Both of these are only designed to be used with the kAudioSessionCategory_PlayAndRecord Audio Session category.

Notice that in both cases you are not choosing amongst any output route, you are only overriding the "default route" in favour of the built-in (loud)speaker.

The iPad, lacking a phone, does not have a BuiltInReceiver type of speaker. It's default route, in the absence of connected gadgets or airplay, is that very same BuiltInSpeaker. Therefore, overriding doesn't have any effect.

Assuming you are really trying to mute the audio in your app, how you achieve that depends on many other aspects of your app design. If you want to mute the device, Apple would rather the user controls this via the ring/silent switch. It seems they wouldn't have it any other way:

I've had a response from Apple on this. They've said they don't and never have provided a method for detecting hardware mute switch and don't intend to do so. https://stackoverflow.com/a/8009073/1375695

"The speaker setting is an overide for the device, not for a given sound"
http://lists.apple.com/archives/coreaudio-api/2009/Mar/msg00300.html

like image 140
foundry Avatar answered Sep 23 '22 22:09

foundry