I want to stream my voice with my iPhone 4 (iOS 7) to a Bluetooth Speaker Device (this one) with the lowest latency/delay possible.
I managed to capture my voice with almost no latency and broadcast it to my speaker through an audio Jack connector but when I pair my Iphone with my Bluetooth Speaker Device it doesn't work. I don't hear anything.
And when I open Youtube in my iPhone the sound is correctly transmitted to the bluetooth Speaker Device. So the problem is not in the Bluetooth Speaker Device but in my code.
Do you have any suggestions or advices ?
Here's the code I put in the delegate class (didFinishLaunchingWithOptions function) to init the audio session :
// configure the audio session
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = NULL;
// deactivate session
[audioSession setActive:NO error:&err];
if (err) {
NSLog(#"There was an error deactivating the audio session");
}
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&err];
if( err ){
NSLog(#"There was an error creating the audio session");
}
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&err];
if( err ){
NSLog(#"There was an error sending the audio to the speakers");
}
// Activate the session
[audioSession setActive:YES error:&err];
Then I use EZAudio framework to send audio to the audio device:
/**
Start the output
*/
[EZOutput sharedOutput].outputDataSource = self;
[[EZOutput sharedOutput] startPlayback];
Related
I'm working on AppRTC for Audio call, It's working fine when app is open. Audio call is not working when device is locked, If wI un-lock device while call and open app, It's start working normally but while it's locked it's not working. (Audio is not passing or playing).
I already added "App plays audio or streams audio/video using AirPlay" in "Required background modes" of plist.
Audio session is also configured. Please check code below.
- (void)configureAVAudioSession:(BOOL)isSpeakerOn
{
// 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:isSpeakerOn?AVAudioSessionPortOverrideSpeaker:AVAudioSessionPortOverrideNone
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");
}
}
Please let me know if anything is missing or i'd implemented wrongly.
Regards,
I'm working on VOIP with Callkit
It work fine, except audio output source
It always output audio by iPhone speaker
some of so answer said set AvAudioSession Option as AVAudioSessionCategoryOptionAllowBluetooth will work, but still failed
and I tried to set bluetooth headset as preferred, like this, failed
by the way, how to make ringtone broadcast by headset?
below is my code, follow the suggestion in this discussion, I configure AVAudioSession right after dialing and get coming call
- (void)getCall:(NSDictionary *)infoDic {
CXCallUpdate *update = [[CXCallUpdate alloc]init];
// config update
NSUUID *uuid = [NSUUID UUID];
[self.provider reportNewIncomingCallWithUUID:uuid update:update completion:^(NSError * _Nullable error) {
if (error)
NSLog(#"%#", error.localizedDescription);
}];
NSArray *video = #[#(ReceiveVideoReq), #(VideoCalling)];
if ([video containsObject:#(self.client.callStage)])
[ProviderManager configureAudio:true];
else
[ProviderManager configureAudio:false];
}
- (void)dialPhone:(BOOL)isVideo {
CXHandle *handle = [[CXHandle alloc]initWithType:CXHandleTypePhoneNumber value:#"AAAA"];
CXStartCallAction *start = [[CXStartCallAction alloc]initWithCallUUID:uuid handle:handle];
start.video = isVideo;
CXTransaction *trans = [[CXTransaction alloc]initWithAction:start];
[self callControlReq:trans];
[ProviderManager configureAudio:isVideo];
}
+ (void)configureAudio:(BOOL)isVideo {
NSError *error=nil, *sessionError = nil;
AVAudioSession *sess = [AVAudioSession sharedInstance];
[sess setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&sessionError];
if (sessionError)
NSLog(#"ERROR: setCategory %#", [sessionError localizedDescription]);
if (isVideo)
[sess setMode:#"AVAudioSessionModeVideoChat" error:&sessionError];
else
[sess setMode:#"AVAudioSessionModeVoiceChat" error:&sessionError];
if (sessionError) {
NSLog(#"ERROR: setCategory %#", [sessionError localizedDescription]);
}
[sess overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&sessionError];
[[AVAudioSession sharedInstance] setActive:true withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
After research, I found the root case of this issue.
Open setting->Accessibility->Touch->Call Audio Routing, there are three option: Automatic, Bluetooth Headset, Speaker.
Default is Automatic, that means if you answer a phone call(Include callkit), when you answer call by your bluetooth device, audio will route to bluetooth, if you answer the call in iPhone, it will route to receiver.
So this actually not an issue, just system behavior.
And do not try to force switch to bluetooth by using [AVAudioSession setPreferredInput:], it will cause more serious issue.
In my case: I call this force switch to bluetooth after audio connected, it worked, but when the bluetooth device disconnected, my audio completely not work and app not get any audio route change callback, even not work after connected bluetooth device again.
Record audio from BT headset. After record, switch route and play through wireless BT speaker.
i have implemented but audio is recording and playing in same headset or speaker.how record and play viseversa ? any solution.?
Thanks in advance
hey #Rushi i think this code will help you for playing audio viseversa
-(IBAction)RecordButtonPlayed:(id)sender
{
if(player.playing)
{
[player stop];
}
if (!recorder.recording)
{
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:NULL];
[_btnRecord setImage:[UIImage imageNamed:#"player-stop-outline-512.png"] forState:UIControlStateNormal];
[recorder record];
}
else
{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:NULL];
[_btnRecord setImage:[UIImage imageNamed:#"171.png"] forState:UIControlStateNormal];
[recorder stop];
}
}
AVAudioSession can be used to set the default output port for your session.
The first thing to do is set up the category AVAudioSession. There are a couple of options here, since we want to be able to play and record sounds.
AVAudioSessionCategoryPlayAndRecord — Playback and record. The input and output need not occur simultaneously, but can if needed. Use for audio chat apps.
AVAudioSessionCategoryMultiRoute — Playback and record. Allow simultaneous input and output for different audio streams, for example, USB and headphone output. A DJ app would benefit from using the multiroute category. A DJ often needs to listen to one track of music while another track is playing. Using the multiroute category, a DJ app can play future tracks through the headphones while the current track is played for the dancers.
In this situation, it looks like AVAudioSessionCategoryPlayAndRecord would be appropriate. Set it like this:
NSError *setCategoryError = nil;
BOOL success = [[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryPlayAndRecord
error: &setCategoryError];
if (!success) { /* handle the error in setCategoryError */ }
Apple suggests setting the category once, and then modifying the input routes depending on our needs.
Once the category is set to AVAudioSessionCategoryPlayAndRecord, the line below will return a list of available input and output routes.
NSArray <AVAudioSessionPortDescription *> *availableInputs = [AVAudioSession sharedInstance].availableInputs;
From the OP, this port is going to be used for recording.
AVAudioSessionPortBluetoothHFP - A Bluetooth enabled device supporting the Hands-Free Profile (HFP).
Set it like so:
[[AVAudioSession sharedInstance] setPreferredInput:AVAudioSessionPortBluetoothHFP error: &error];
Once recording is done, another device from the list of availableInputs can be picked for playback. Most probably, the playback port for BT speakers would be AVAudioSessionPortBluetoothA2DP, but here is a comprehensive list of all playback ports.
Set it like so:
[[AVAudioSession sharedInstance] setPreferredInput:AVAudioSessionPortBluetoothA2DP error: &error];
Now the sound should play to the BT speaker.
It's important to note here that, [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error]; will revert to the phone's internal speaker, and NOT the BT speaker.
Please use AVAudioSession method.
- (BOOL)setCategory:(NSString *)category
withOptions:(AVAudioSessionCategoryOptions)options
error:(NSError **)outError
and set the following
with category as
AVAudioSessionCategoryPlayAndRecord
or AVAudioSessionCategoryRecord
and options as
AVAudioSessionCategoryOptionAllowBluetooth
Remember it may work for A2DP bluetooth only.
Try then with this
AVAudioSessionCategoryOptionAllowBluetooth
In order to receive bluetooth accessory events you would have to write below code in your view controller:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
and then I think setting the Audio Session Category to MultiRoute could allow for audio to be routed separately.Whereas I tried to do so earlier in iOS7. and it seems that every time you change either the input or output, iOS changes the audio device altogether.I am not sure if its possible with new versions too.
However you can get the list of all currently available inputs using following code:
// portDesc.portType could be for example - BluetoothHFP, MicrophoneBuiltIn, MicrophoneWired
NSArray *availInputs = [[AVAudioSession sharedInstance] availableInputs];
int count = [availInputs count];
for (int k = 0; k < count; k++) {
AVAudioSessionPortDescription *portDesc = [availInputs objectAtIndex:k];
NSLog(#"input%i port type %#", k+1, portDesc.portType);
NSLog(#"input%i port name %#", k+1, portDesc.portName);
}
and outputs as:
AVAudioSession *session = [AVAudioSession sharedInstance];
NSLog(#"Outputs: %#", [[session currentRoute] outputs]);
Good Luck!!
I'm facing an issue using bluetooth for my app on iOS 7.
To be more precise, the bluetooth receiver i'd like to connect to is : http://www.amazon.co.uk/Sony-Bluetooth-Receiver-Enhancement-Smartphone-Black/dp/B00G9YK7LS
Of course the iPhone is paired to the device before I start testing.
My app should just make an audio pass through (from the mic to the speakers) using the EZAudio framework. It works fine using the iPhone headset but not with the bluetooth.
Here's the code I put in the delegate class (didFinishLaunchingWithOptions function) to init the audio session :
// configure the audio session
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = NULL;
// deactivate session
[audioSession setActive:NO error:&err];
if (err) {
NSLog(#"There was an error deactivating the audio session");
}
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&err];
if( err ){
NSLog(#"There was an error creating the audio session");
}
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&err];
if( err ){
NSLog(#"There was an error sending the audio to the speakers");
}
// Activate the session
[audioSession setActive:YES error:&err];
Then I use EZAudio framework to send audio to the audio device:
/**
Start the output
*/
[EZOutput sharedOutput].outputDataSource = self;
[[EZOutput sharedOutput] startPlayback];
Anyone has any idea about this issue please? Have I missed something?
Thanks for your help!
You should set the category to AVAudioSessionCategoryPlayback. When you have it set to AVAudioSessionCategoryPlayAndRecord, the bluetooth device needs to be available for input as well as output. If it is not, the device will default to internal speakers for playback.
I am trying to use AVSpeechSynthesizer when the phone is locked, but the audio stops when I lock the screen. I am using the simulator, not an actual device. I have seen a couple other questions similar to this on this site and I followed their recommendations, but it still does not work.
In the app delegate I set the audio session category to AVAudioSessionCategoryPlayback.
- (void)configureAudioSession{
NSError *error = NULL;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
if(error) {
NSLog(#"Error setting category of audio session: %#",error.description);
}
error = NULL;
[[AVAudioSession sharedInstance] setActive:YES error: &error];
if (error) {
NSLog(#"Error activating audio session: %#",error.description);
}
}
And I checked the 'Audio and Airplay' mode under Project Settings->Capabilities->Background Modes.
Can anyone tell me how to get this to work?
Here's how I got AVSpeechSynthesizer to continue speaking when phone goes idle, if phone gets locked, or if app goes to background. (iOS8)
Step 1) Open up info.plist and add the key "Required background modes". Within this array, add a String called "App plays audio or streams audio/video using AirPlay".
Step 2) Add the following to your app delegate didFinishLaunchingWithOptions:
NSError *error = NULL;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:&error];
if(error) {
// Do some error handling
}
[session setActive:YES error:&error];
if (error) {
// Do some error handling
}
Step 3) Run on your device and test it out!
I was able to follow this post to get it to work about a month ago:
AVAudioPlayer stops playing on screen lock even though the category is AVAudioSessionCategoryPlayback
Basically, you need to make entry in your app's .plist file. I'm not sure this will work on the simulator, so you will probably want to test it on an actual device.