0

I need to record a video with AVCaptureSession in an iOS app.

When I add AVCaptureDeviceInput to my current AVCaptureSession, it always adds the iphone microphone. I have the bluetooth microphone connected to the device. But it is not recording from the external microphone.

I'm doing this:

- (BOOL)prepareAudioSession {

// deactivate session
BOOL success = [[AVAudioSession sharedInstance] setActive:NO error: nil];
if (!success) {
    NSLog(@"deactivationError");
}

// Bluetooth support enable
UInt32 allowBluetoothInput = 1;
AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput);
// set audio session category AVAudioSessionCategoryPlayAndRecord options AVAudioSessionCategoryOptionAllowBluetooth

success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth|AVAudioSessionCategoryOptionMixWithOthers error:nil];
//success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];

if (!success) {
    NSLog(@"setCategoryError");
}

// activate audio session
success = [[AVAudioSession sharedInstance] setActive:YES error: nil];
if (!success) {
    NSLog(@"activationError");
}
return success;
}

But it's still not working. Anyone have any idea? Thanks

Drakes
  • 23,254
  • 3
  • 51
  • 94
Pablo Martinez
  • 1,573
  • 12
  • 31

2 Answers2

1

The solution is this:

In your AppDelegate

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];

in your AVCaptureSession after add your AVCaptureDeviceInput

self.captureSession.usesApplicationAudioSession = true;
    self.captureSession.automaticallyConfiguresApplicationAudioSession = false;

My setup for Audio:

/* Audio */
    AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];


    audioIn = [[AVCaptureDeviceInput alloc] initWithDevice:audioDevice error:nil];
    if ( [_captureSession canAddInput:audioIn] ) {
        [_captureSession addInput:audioIn];
    }

    audioOut = [[AVCaptureAudioDataOutput alloc] init];
    // Put audio on its own queue to ensure that our video processing doesn't cause us to drop audio
    dispatch_queue_t audioCaptureQueue = dispatch_queue_create( "com.apple.sample.capturepipeline.audio", DISPATCH_QUEUE_SERIAL );
    [audioOut setSampleBufferDelegate:self queue:audioCaptureQueue];


    if ( [self.captureSession canAddOutput:audioOut] ) {
        [self.captureSession addOutput:audioOut];
    }
    _audioConnection = [audioOut connectionWithMediaType:AVMediaTypeAudio];

    //AVAudioSessionRouteDescription *current =[[AVAudioSession sharedInstance] currentRoute];*/
    if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")){
        self.captureSession.usesApplicationAudioSession = true;
        self.captureSession.automaticallyConfiguresApplicationAudioSession = false;
        //[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
    }
Pablo Martinez
  • 1,573
  • 12
  • 31
0

I think there is a problem with how you are forming the AVCaptureSession while setting the category with options. Try something like this to make AVCaptureSession:

    // 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);

NSError *error = nil;

audioRecorder = [[AVAudioRecorder alloc]
                 initWithURL:soundFileURLRef
                 settings:recordSettings
                 error:&error];
if (error)
{
    NSLog(@"error: %@", [error localizedDescription]);
} else {
    [audioRecorder prepareToRecord];
}

I took the code from here because it always works for me.

NOTE: This code will re route the audio while playing back to your headset itself. To use speaker while playing back, look at the comment section of accepted answer.

Community
  • 1
  • 1
blancos
  • 1,576
  • 2
  • 16
  • 38
  • Do I have to put this before add this lines? AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; – Pablo Martinez Apr 24 '15 at 06:09
  • I guess you have less experience with AVFoundation. So I gave you whole snippet. Check the edited answer. – blancos Apr 24 '15 at 06:22
  • The problem is that I'm not using AVAudioRecorder for record. I'm using the apple sample project, Rosy Writer, and you have to add AVCaptureDeviceInput and write with AVAssetWriter. – Pablo Martinez Apr 24 '15 at 06:58
  • 1
    That can be modified easily. You don't have to use AVCaptureDeviceInput. Just look around for the problems you are facing when you modify. Because I don't think AVCaptureDeviceInput will enlist bluetooth device, so just try to modify that project. – blancos Apr 24 '15 at 07:09
  • Thanks for your help, then if I don't have to use AVCaptureDeviceInput, Do I have to use AVCaptureAudioDataOutput? Thanks a lot! – Pablo Martinez Apr 24 '15 at 07:26
  • Well that depends on your requirements. If all you are doing is recording audio and playing them back, then you don't need AVCaptureAudioDataOutput. AVCaptureAudioDataOutput is used to process audio sample buffers i.e. if you want do some kind of processing or editing. – blancos Apr 24 '15 at 08:30
  • Hello, Actually I'm processing the audio sample buffers. Can You take a look to this? http://stackoverflow.com/questions/29868892/method-captureoutputavcaptureoutput-captureoutput-didoutputsamplebuffercms – Pablo Martinez Apr 25 '15 at 19:33
  • The problem is some devices are working perfect and other devices not. The device is not faulty because I tested this in other apps and is working. – Pablo Martinez Apr 25 '15 at 19:36
  • I am also facing this problem @PabloMartinez, can you share your experience about how you solved it? – Syed Ali Salman Jul 14 '17 at 07:27
  • @SyedAliSalman yes, you have to add this category to be able to use bluetooth mics. AVAudioSessionCategoryOptionAllowBluetooth – Pablo Martinez Jul 14 '17 at 07:30
  • @PabloMartinez I already added it but didn't work for me. can you show me how you did it in capture session of rosywriter? – Syed Ali Salman Jul 14 '17 at 09:42
  • @PabloMartinez it says that media data could not be decoded. – Syed Ali Salman Jul 14 '17 at 09:55
  • I have edited my solution with the whole setup! @SyedAliSalman – Pablo Martinez Jul 14 '17 at 11:04
  • Thanks @PabloMartinez but believe me I am doing exactly the same. Same RosyWriterProcessor but I am not getting it working. – Syed Ali Salman Jul 14 '17 at 11:32