How Do I Route Audio to Speaker without using AudioSessionSetProperty?
On each release of iOS, more of the audioSession properties are migrated to AVFoundation, so you should use those in preference whenever available.
Since iOS 6 kAudioSessionProperty_OverrideAudioRoute
is represented in AVAudioSession by the method
- (BOOL)overrideOutputAudioPort:error:
Available values are AVAudioSessionPortOverrideNone
and AVAudioSessionPortOverrideSpeaker
Here is an example audio session configured entirely via AVFoundation:
- (void)configureAVAudioSession
{
// Get your app's audioSession singleton object
AVAudioSession *session = [AVAudioSession sharedInstance];
// Error handling
BOOL success;
NSError *error;
// set the audioSession category.
// Needs to be Record or PlayAndRecord to use audioRouteOverride:
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
error:&error];
if (!success) {
NSLog(@"AVAudioSession error setting category:%@",error);
}
// Set the audioSession override
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if (!success) {
NSLog(@"AVAudioSession error overrideOutputAudioPort:%@",error);
}
// Activate the audio session
success = [session setActive:YES error:&error];
if (!success) {
NSLog(@"AVAudioSession error activating: %@",error);
}
else {
NSLog(@"AudioSession active");
}
}
UPDATE
Since iOS 7.0, the Audio Session Services C API is now fully deprecated in favour of AVAudioSession.
UPDATE 2
- (BOOL)overrideOutputAudioPort:error:
is a method, not a property, and it sets an underlying write-only UInt32 value. You can't get the current value, and you should treat the method as setting a temporary state. If the audio route changes or is interrupted, the property resets to its default (AVAudioSessionPortOverrideNone
). You can get interruption notifications via AVAudioSessionDelegate
.
How to route to kAudioSessionProperty_OverrideCategoryEnableBluetoothInput without using AudioSessionSetProperty
To expand on my previous answer and comment:
You would use the AVAudioSession method
- (BOOL)setCategory:(NSString *)category
withOptions:(AVAudioSessionCategoryOptions)options
error:(NSError **)outError
with category
asAVAudioSessionCategoryPlayAndRecord
or AVAudioSessionCategoryRecord
and options
asAVAudioSessionCategoryOptionAllowBluetooth
In your reply you say
that is not the same because that would allow A2DP bluetooth only
But according to the Apple docs
AVAudioSessionCategoryOptionAllowBluetooth
Allows Bluetooth handsfree devices to appear as available input routes.
I understand that to mean bluetooth HFP, which I presume is what you are after. As regards "forcing", Apple is not too keen on apps forcing/overriding OS control of a user's experience of device behaviour.
It may be that this does not work in practice - I have not been able to test it. Presumably you have, and it fails (you don't indicate in your question). But you are hitting the limits of Apple's documentation on this issue. If you really can't get it to work I would be inclined to go with the deprecated C interface, and be prepared to make changes for iOS8.
Routing iPhone Audio Sound
To do this you have to add property listener when you setup audio session:
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audioSessionPropertyListener, nil);
Where
void audioSessionPropertyListener(void* inClientData, AudioSessionPropertyID inID,
UInt32 inDataSize, const void* inData) {
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
if (!isHeadsetPluggedIn())
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
}
BOOL isHeadsetPluggedIn() {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route
);
if (!error && (route != NULL) && ([(NSString*)route rangeOfString:@"Head"].location != NSNotFound)) {
NSLog(@"HeadsetPluggedIn");
return YES;
}
NSLog(@"Headset_NOT_PluggedIn");
return NO;
}
So when headphones are plugged in or out you get a notification and change audio output direction.
Routing iPhone Audio Sound
To do this you have to add property listener when you setup audio session:
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audioSessionPropertyListener, nil);
Where
void audioSessionPropertyListener(void* inClientData, AudioSessionPropertyID inID,
UInt32 inDataSize, const void* inData) {
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
if (!isHeadsetPluggedIn())
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
}
BOOL isHeadsetPluggedIn() {
UInt32 routeSize = sizeof (CFStringRef);
CFStringRef route;
OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
&routeSize,
&route
);
if (!error && (route != NULL) && ([(NSString*)route rangeOfString:@"Head"].location != NSNotFound)) {
NSLog(@"HeadsetPluggedIn");
return YES;
}
NSLog(@"Headset_NOT_PluggedIn");
return NO;
}
So when headphones are plugged in or out you get a notification and change audio output direction.
AVAudioPlayer via Speakers
I used the AudioToolbox framework that's why I initialized my audio session as following:
AudioSessionInitialize(NULL, NULL, NULL, NULL);
Here's the rest of my code that I used to configure the audio session. I didn't override the audio route and I also think this is not necessary.
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
OSStatus err = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
sizeof(sessionCategory),
&sessionCategory);
AudioSessionSetActive(TRUE);
if (err) {
NSLog(@"AudioSessionSetProperty kAudioSessionProperty_AudioCategory failed: %d", err);
}
how to route iPhone audio to the bluetooth headset
This little test worked for me... it involves setting up the bluetooth headset as the input also (not sure if that's what you want). Sorry about the crappy formatting on the code...
// create and set up the audio session
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setDelegate:self];
[audioSession setCategory: AVAudioSessionCategoryPlayAndRecord error: nil];
[audioSession setActive: YES error: nil];
// set up for bluetooth microphone input
UInt32 allowBluetoothInput = 1;
OSStatus stat = AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
sizeof (allowBluetoothInput),
&allowBluetoothInput
);
NSLog(@"status = %x", stat); // problem if this is not zero
// check the audio route
UInt32 size = sizeof(CFStringRef);
CFStringRef route;
OSStatus result = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &route);
NSLog(@"route = %@", route);
// if bluetooth headset connected, should be "HeadsetBT"
// if not connected, will be "ReceiverAndMicrophone"
// now, play a quick sound we put in the bundle (bomb.wav)
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef soundFileURLRef;
SystemSoundID soundFileObject;
soundFileURLRef = CFBundleCopyResourceURL (mainBundle,CFSTR ("bomb"),CFSTR ("wav"),NULL);
AudioServicesCreateSystemSoundID (soundFileURLRef,&soundFileObject);
AudioServicesPlaySystemSound (soundFileObject); // should play into headset
Hope that helps!
Related Topics
How to Dismiss Viewcontroller in Swift
How to Convert a String to an Md5 Hash in iOS Using Swift
In Swift, How to Avoid Both Optionals and Nil Object References
How to Log a Method's Execution Time Exactly in Milliseconds
Xcode 9 - "Fixed Width Constraints May Cause Clipping" and Other Localization Warnings
How to Release a Cgimageref in iOS
Custom Init for Uiviewcontroller in Swift with Interface Setup in Storyboard
Findobjectsinbackgroundwithblock: Gets Data from Parse, But Data Only Exists Inside the Block
Loading a Reusable Uitableviewcell from a Nib
How to Play a Sound Using Swift
Rsa Implementations in Objective C
Insert CSS into Loaded HTML in Uiwebview/Wkwebview
Uitableview Load More When Scrolling to Bottom Like Facebook Application
iOS - Uiimageview - How to Handle Uiimage Image Orientation
Method Overloading in Objective-C