AVCaptureSession addInput causing glitch in background audio - ios

I'm making a video capturing iOS app and I want to be able to record audio from the microphone while allowing background music to play. I can do all of this but the background audio skips (pauses briefly) whenever the view with the camera enters and exits the foreground. I have isolated the bug to AVCaptureSession addInput:
AVCaptureSession session = [[AVCaptureSession alloc] init];
session.automaticallyConfiguresApplicationAudioSession = NO;
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
// this line causes the background music to skip
[session addInput:audioDeviceInput];
How can I prevent adding microphone input from affecting the background audio?
fyi - in didFinishLaunchingWithOptions I set the AVAudioSession Category:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDefaultToSpeaker
error:nil];

Apparently there is no workaround.
https://forums.developer.apple.com/message/74778#74778

Related

Use Bluetooth device to record audio in AVCaptureSession

I am using Apple's RosyWriter sample to record video and audio. Now I need to record audio using Bluetooth headset but it is not working for me. I am doing the below work for this
captureSession = [[AVCaptureSession alloc] init];
/*
* Create audio connection
*/
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")){
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
captureSession.usesApplicationAudioSession = true;
captureSession.automaticallyConfiguresApplicationAudioSession = true;
}
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
// AVCaptureDeviceInput *audioIn = [[AVCaptureDeviceInput alloc] initWithDevice:[self audioDevice] error:nil];
AVCaptureDeviceInput *audioIn = [[AVCaptureDeviceInput alloc] initWithDevice:audioDevice error:nil];
if ([captureSession canAddInput:audioIn])
[captureSession addInput:audioIn];
I have also followed this question
I was able to do this by changing audio out settings like below.
_audioCompressionSettings = [[audioOut recommendedAudioSettingsForAssetWriterWithOutputFileType:AVFileTypeQuickTimeMovie] copy];

App-recorded videos sometimes play no audio when played on phone

Our app records and plays (those) videos. But somehow some of the videos are played without sound.
If i copy the video files to the mac via iTunes it plays the videos with sound, so the videos do have sound.
I checked the videos with a tool (called GSpot) and they all have the same audio codec and bitrate.
I tried about everything i found on SO but some of the videos dont play audio and the code is always the same and the videos do have sound as on a mac you can hear it.
This is how i setup the player
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
[audioSession setActive:YES error:&setCategoryError];
[audioSession setCategory:AVAudioSessionCategoryPlayback
error:&setCategoryError];
_mpviewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:moviepath]];
_mpviewController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
_mpviewController.moviePlayer.controlStyle = MPMovieControlStyleNone;
[_mpviewController.moviePlayer setScalingMode:MPMovieScalingModeAspectFill];
_mpviewController.moviePlayer.shouldAutoplay = YES;
[_mpviewController.moviePlayer prepareToPlay];
_mpviewController.view.frame = CGRectMake(0, 0, _screenWidth, _screenHeight);
[self addSubview:_mpviewController.view];
some time later, on a button press, it starts playing.
The record settings
[_session beginConfiguration];
[_session setSessionPreset: AVCaptureSessionPreset640x480];
AVCaptureDevice * videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
BOOL lock = [videoDevice lockForConfiguration:&error];
if(lock) videoDevice.focusMode = AVCaptureFocusModeContinuousAutoFocus;
[videoDevice unlockForConfiguration];
if(videoDevice == nil){
assert(0);
}
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
if(error){
assert(0);
}
[_session addInput:input];
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput * audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
if(audioInput != nil) {
[_session addInput:audioInput];
}
[_session commitConfiguration];
I dont know if it is related but the audio seems to not play on videos that had a different view overlayed during the recording. It is possible to overlay a fullscreen view over the video preview while recording and it records fine and the file itself has audio and they play fine on a pc/mac... only on the device within our app those videos (again, not sure if related) have no audio. App uses same code for every video, so i can rename them, swap them etc, the behaviour has something to do with the audio channel of the video.
edit
Additional observation:
The vids where there is no sound, quicktime (only on mac) also plays no audio. QT on windows does play audio and all other players on windows do play audio as well.
Somehow the phone corrupts its own recording so that afterwards it doesnt recognize the audio channel it just recorded
edit 2
iPhone 6, iOS 8.1beta 2 -> as described
iPhone 4S, iOS 7.1.2 -> NO issue
iPad mini, iOS 8.0.2 -> always has the issue, not one videos audio channel can be read, but always exists and windows can play audio
I want to wrap this up.
The file was saved as ".mp4" and this causes the sporadic error.
Saving the file as ".mov" works. Same codec etc but without errors.
NSString *path = [[documentsDirectoryPath stringByAppendingPathComponent:
[NSString stringWithFormat:#"/%#", name]] stringByAppendingString:#".mov"];
outputURL = [[NSURL alloc] initFileURLWithPath:path];
[mAVCaptureMovieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];

Play MPMoviePlayerController audio stream in background

So I have this app where I play videos and when you exit the app I would like the user to continue to listen to the audio of the video. I use MPMoviePlayerController to play the video and it works in the app perfectly fine. I also setup AVAudioSession up before I play the video and I get no error.
NSError *audioSessionError;
NSError *activationError;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&audioSessionError];
[audioSession setActive:YES error:&activationError];
I also set in plist background modes audio. But the video with the audio both stop playing when you close the app. I've also imported the AVFoundation framework.
Simply set Application does not run in background to NO in .plsit file
You need to make couple of changes in plist file.i.e.
1) Set Required background mode to App plays audio
2) set Application does not run in background to YES.
NSError *setCategoryErr = nil;
NSError *activationErr = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:&setCategoryErr];
[[AVAudioSession sharedInstance] setActive:YES error:&activationErr];
Then, you need to write these much code in AppDelegate
Now, you can easily run audio while phone screen locks or goes in background.
This code worked for me, first you must to give your app permissions to keep playing music in the background (In your .plis), after that go to the wished class and implement this code, first the imports and the the method to play the music.
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPMediaItem.h>
#import <AVFoundation/AVFoundation.h>
---- o ----
-(void) playMusic{
[[AVAudioSession sharedInstance] setDelegate: self];
NSError *myErr;
// Initialize the AVAudioSession here.
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
// Handle the error here.
NSLog(#"Audio Session error %#, %#", myErr, [myErr userInfo]);
}else{
// Since there were no errors initializing the session, we'll allow begin receiving remote control events
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
//initialize our audio player
audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:#"http://www.cocoanetics.com/files/Cocoanetics_031.mp3"]];
[audioPlayer setShouldAutoplay:NO];
[audioPlayer setControlStyle: MPMovieControlStyleEmbedded];
audioPlayer.view.hidden = YES;
[audioPlayer prepareToPlay];
[audioPlayer play];
}//end playmusic
You need to turn on Background Modes in capabilities.

AVCaptureSession record audio from bluetooth microphone

From searching today I think it is still not possible to use a Bluetooth headset microphone as the audio input for an AVCaptureSession (video recording) on an iOS device even with the audio changes made in iOS7. However in case I just haven't looked hard enough has anyone found a way to achieve this?
According to the apple docs kAudioSessionProperty_OverrideCategoryEnableBluetoothInput can be set for the kAudioSessionCategory_RecordAudio or kAudioSessionCategory_PlayAndRecord categories. However the AudioSessionSetProperty method required to do this has been depreciated. Ignoring that and just using it I still can't find a way to utilize this to get the bluetooth audio passed to a video recording.
I was able to get this to work in iOS7+ by configuring the audio session associated with my AVCapture session:
AVCaptureSession *cs = [[AVCaptureSession alloc] init];
self.captureSession = cs;
self.captureSession.usesApplicationAudioSession = true;
self.captureSession.automaticallyConfiguresApplicationAudioSession = true;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
Good Luck.
I solved same problem by setting 'automaticallyConfiguresApplicationAudioSession' to 'NO'.
But it would cause background music very low without airpods. And i fixed it by adding 'AVAudioSessionCategoryOptionDefaultToSpeaker' to options.
This is my code:
self.captureSession = [[AVCaptureSession alloc] init];
self.captureSession.usesApplicationAudioSession = YES;
self.captureSession.automaticallyConfiguresApplicationAudioSession = NO;
BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
|AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
if (!success) {
NSLog(#"setCategory error:%#", error);
return NO;
}

IOS Audio Recording, How to Check if Mic / Playback is Busy Before Taking Mic

If anything is playing, recording, how to we check to see if the MIC is available (idle) for recording? Currently using
AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureSession *captureSession = [[AVCaptureSession alloc] init];
VCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice : audioCaptureDevice error:&error];
AVCaptureAudioDataOutput *audioOutput = [[AVCaptureAudioDataOutput alloc] init];
[captureSession addInput : audioInput];
[captureSession addOutput : audioOutput];
[captureSession startRunning];
Need to check before grabbing the MIC / Playback from something that is already has it.
The mic device can not be busy/access to it can not be locked, even if you call [AVCaptureDevice lockForConfiguration] on a mic device it will not lock it and it is still accessible to the foreground application.
To see if other audio is playing you can check kAudioSessionProperty_OtherAudioIsPlaying e.g.:
UInt32 propertySize, audioIsAlreadyPlaying=0;
propertySize = sizeof(UInt32);
AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &audioIsAlreadyPlaying);
Additionally on Audio Session Programming Guide it is stated: "There is no programmatic way to ensure that an audio session is never interrupted. The reason is that iOS always gives priority to the phone. iOS also gives high priority to certain alarms and alerts"

Resources