I know how to set the AVAudioSession to be able to read audio input from a bluetooth device. I accomplish this by the following code:
NSError *error;
[[AVAudioSession sharedInstance] setActive:NO error:&error];
[self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
NSError *errorTwo;
[self.audioSession setActive:YES error:&errorTwo];
By setting the options to AVAudioSessionOptionAllowBlueTooth I am able set this up. However, I'm trying to get this to work with a video recorder and I'm struggling to get this to work.
I'll post what I have starting from the AVCaptureSession:
self.captureSession = [AVCaptureSession new];
NSError *error;
[[AVAudioSession sharedInstance] setActive:NO error:&error];
self.captureSession.automaticallyConfiguresApplicationAudioSession = YES;
self.captureSession.automaticallyConfiguresApplicationAudioSession = true;
[self.audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
NSError *errorTwo;
[self.audioSession setActive:YES error:&errorTwo];
[self addAudioCapture];
AVCaptureDevice *audioInputDevice = [self audioDevice];
- (BOOL)addAudioCapture
{
AVCaptureDevice *audioInputDevice = [self audioDevice];
DLog(#"AUDIO INPUT DEVICE: %#", [audioInputDevice description]);
AVCaptureDeviceInput *audioIn = [[AVCaptureDeviceInput alloc] initWithDevice:audioInputDevice error:nil];
if ([self.captureSession canAddInput:audioIn])
{
[self.captureSession addInput:audioIn];
}
else
{
return NO;
}
self.audioOut = [[AVCaptureAudioDataOutput alloc] init];
dispatch_queue_t audioCaptureQueue = dispatch_queue_create("Audio Capture Queue", DISPATCH_QUEUE_SERIAL);
[self.audioOut setSampleBufferDelegate:self queue:audioCaptureQueue];
if ([self.captureSession canAddOutput:self.audioOut])
{
[self.captureSession addOutput:self.audioOut];
}
else
{
return NO;
}
self.audioConnection = [self.audioOut connectionWithMediaType:AVMediaTypeAudio];
return YES;
}
- (AVCaptureDevice *)audioDevice
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
if ([devices count] > 0)
{
return [devices objectAtIndex:0];
}
return nil;
}
However, the problem I'm facing is the audioInputDevice is always the iPhone microphone. I've confirmed that my bluetooth device is paired with my phone and I've written a separate application to test what input / output I'm currently using and I can confirm the the bluetooth device is readable by the iPhone. However, in the main app I'm working in I'm unable to set this. Any tips or advice on how to achieve this would be appreciated.
Related
Whilst, I have been unable to replicate this issue on my test devices / simulator, I'm getting a few crash reports from some users, but not all. EXC_BAD_ACCESS KERN_INVALID_ADDRESS at this line. Why is this and what steps can I take to resolve? The crash reports are from users on iOS 14.4.0 and 14.3.0 and from a variety of devices (iPhone 6s plus, iPhone 8 Plus, iPhone SE (2nd generation), iPhone XS, iPhone 7, iPhone 7s, iPhone 11, iPhone 12, iPhone X)
In PageViewController.m
// Voice Recording - Needed as workaround as there is a bug in AudioKit
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
defaultVoiceRecording,
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session to play through loud speakers
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if(error){
NSLog(#"AVAudioSession Sing the Note error tuner:%#",error);
}
// Setup audio session to play through loud speakers
if (![MenuViewController areHeadphonesPluggedIn]){ // EXC_BAD_ACCESS KERN_INVALID_ADDRESS here
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
if(error)
{
NSLog(#"Error: AudioSession cannot use speakers");
}
}
In MenuViewController.h
+(BOOL)areHeadphonesPluggedIn;
In MenuViewController.m
+(BOOL)areHeadphonesPluggedIn {
#try{
NSArray *availableOutputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
for (AVAudioSessionPortDescription *portDescription in availableOutputs) {
if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones]) {
return YES;
}
}
return NO;
}
#catch(id Exception){
return NO;
}
}
+(BOOL)areHeadphonesPluggedIn {
#try{
NSArray *availableOutputs = [[AVAudioSession sharedInstance] currentRoute].outputs;
for (AVAudioSessionPortDescription *portDescription in availableOutputs) {
if ([portDescription.portType isEqualToString:AVAudioSessionPortHeadphones]) {
return YES;
}
}
return NO;
}
#catch(id Exception){
return NO; // Not sure it will work as you exect
}
return NO; // move return here!
}
This issue was down to a 'dangling' pointer somewhere up the stack, in this case it was the autorelease array pathComponents. Needed to change that to non-autorelease array.
The full solution PageViewController.m
// Change from autorelease to normal non-autorelease
NSArray *pathComponentsSN = [[NSArray alloc] initWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],defaultVoiceRecording,nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponentsSN];
// Setup audio session to play through loud speakers
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if(error){
NSLog(#"AVAudioSession Sing the Note error creating session");
}
// Setup audio session to play through loud speakers
if (![MenuViewController areHeadphonesPluggedIn]){ // Crash logs from this line
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
if(error)
{
NSLog(#"Error: AudioSession cannot use speakers");
}
}
I am capturing the video from the device camera and than storing that video into the device local memory and than in the next screen I am playing that video using AVPlayer but I am not getting sound from video.Here is code of video playback
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
_avPlayer=[[AVPlayer alloc]initWithURL:url]; //URL of my recorded video
_avPlayerLayer =[AVPlayerLayer playerLayerWithPlayer:_avPlayer];
[_avPlayerLayer setFrame:CGRectMake(0, 0, self.videoview.frame.size.width, self.videoview.frame.size.height)];
[_avPlayerLayer setBackgroundColor:[[UIColor blackColor]CGColor]];
_avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.pictureview.layer addSublayer:_avPlayerLayer];
[_avPlayer seekToTime:kCMTimeZero];
_avPlayer = [self rotateVideoPlayer:_avPlayer withDegrees:0.0];
_avPlayer.volume = 1.0;
[_avPlayer play];
Note:- Video has sound because After preview, I am uploading the video on server and in that I can hear a sound from recorded video.
I am using AVCaptureSession to record video and has added AVMediaTypeVideo and AVMediaTypeAudio as AVCaptureDevice. So will it make any problem at a time of playback. Before Playback I am removing AVCaptureDevice devices from the AVCaptureSession and than playing the captured video.
I got same issue a time ago, and adding this code to AppDelegate method helped me:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSError *err;
AVAudioSession *session = [AVAudioSession sharedInstance];
bool success = [session setCategory:AVAudioSessionCategoryPlayback
error:&err];
if (!success) {
DLog(#"error changing audio mode %#", err);
[session setCategory:AVAudioSessionCategoryPlayback
error:&err];
if (err) {
DLog(#"error changing audio mode %#", err);
}
}
}
Also if it doesn't help, try to turn off the "mute" button on your device.
Also check error description if it does exist.
UPDATE:
Do you initialize your audio input something like this?
AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (error)
{
NSLog(#"%#", error);
}
if ([session canAddInput:audioDeviceInput])
{
[session addInput:audioDeviceInput];
}
You can easily play video with MPMoviePlayerController. In one my project I am playing like,
self.videoController = [[MPMoviePlayerController alloc] init];
[self.videoController setContentURL:videourl];
[self.videoController.view setFrame:CGRectMake (0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:self.videoController.view];
UIButton *closeButton = [[UIButton alloc]initWithFrame:CGRectMake(self.view.frame.size.width-60, 20, 60, 30)];
[closeButton addTarget:self action:#selector(cancel:) forControlEvents:UIControlEventTouchUpInside];
[closeButton setTitle:#"Cancel" forState:UIControlStateNormal];
[self.videoController.view addSubview:closeButton];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(videoPlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.videoController];
[self.videoController play];
I am adding close button and observer, you not need to do that if not required.
And don't forget to import <MediaPlayer/MediaPlayer.h>
Update :
audioSession = [AVAudioSession sharedInstance];
NSError *err;
NSError *error;
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error: &err];
if (err) {
NSLog(#"ERROR occured %#",[err localizedDescription]);
}
[audioSession setActive:YES error: &error];
[audioSession setActive:NO error:nil];
// [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:nil];
[audioSession setActive:YES error:nil];
audioPlayer = nil;
//NSError *error;
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:self.audioRecorder1.url
error:&error];
// audioPlayer.volume = 1.0;
audioPlayer.delegate = self;
[audioPlayer prepareToPlay];
[audioPlayer play];
You use avplayer instead of audio player! main concern is session!
Hope this will help:)
I'm using AV to record video via my app, and I have a button that swaps between the camera view being front and back camera, with back being the default. Switching from back to front works just fine. However, switching then from front to back causes the app to crash.
- (IBAction)btnSwapCamerasClicked:(id)sender {
//Change camera source
if(session)
{
//Indicate that some changes will be made to the session
[session beginConfiguration];
//Remove existing input
AVCaptureInput* currentCameraInput = [session.inputs objectAtIndex:0];
[session removeInput:currentCameraInput];
//Get new input
AVCaptureDevice *newCamera = nil;
if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)
{
newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
}
else
{
newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
}
//Add input to session
NSError *err = nil;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];
if(!newVideoInput || err)
{
NSLog(#"Error creating capture device input: %#", err.localizedDescription);
}
else
{
//THIS IS THE SPOT THAT CRASHES.
[session addInput:newVideoInput];
}
//Commit all the configuration changes at once
[session commitConfiguration];
}
}
The crash occurs under [session addInput:newVideoInput]; and I am returned the following error text:
2015-03-03 11:25:59.566 The SWAT App Beta[1769:365194] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* Multiple audio/video AVCaptureInputs are not currently supported.'
*** First throw call stack:
(0x185c002d4 0x1975c80e4 0x1843ad39c 0x1843accd4 0x10004ac14 0x18a818fb4 0x18a80201c 0x18a818950 0x18a8185dc 0x18a811a74 0x18a7e57f0 0x18aa85274 0x18a7e3d04 0x185bb8250 0x185bb74f4 0x185bb55a4 0x185ae1404 0x18f4eb6fc 0x18a84a2b4 0x10004bb70 0x197c6ea08)
libc++abi.dylib: terminating with uncaught exception of type NSException
I'm not entirely sure why there seems to be multiple inputs, since in the code I listed I removed the old input, and it works just fine for back to front. Not sure why front to back is making the app kill itself.
Any ideas?
I solved my issue by rewriting the code for switching cameras to something I wrote proprietarily. I created an NSString named currentCam that I change the text to between "Back" and "Front" depending on the current situation. Code below:
- (IBAction)btnSwapCamerasClicked:(id)sender {
[session beginConfiguration];
if ([currentCam isEqualToString:#"Back"])
{
NSArray *inputs = [session inputs];
for (AVCaptureInput *input in inputs)
{
[session removeInput:input];
}
//Video input
AVCaptureDevice *newCamera = nil;
newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
//Audio input
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput * audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
NSError *err = nil;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];
if(!newVideoInput || err)
{
NSLog(#"Error creating capture device input: %#", err.localizedDescription);
}
else
{
[session addInput:newVideoInput];
[session addInput:audioInput];
newVideoInput = nil;
audioInput = nil;
audioDevice = nil;
newCamera = nil;
inputs = nil;
}
currentCam = #"Front";
}
else if ([currentCam isEqualToString:#"Front"])
{
NSArray *inputs = [session inputs];
for (AVCaptureInput *input in inputs)
{
[session removeInput:input];
}
//Video input
AVCaptureDevice *newCamera = nil;
newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
//Audio input
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput * audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
NSError *err = nil;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];
if(!newVideoInput || err)
{
NSLog(#"Error creating capture device input: %#", err.localizedDescription);
}
else
{
[session addInput:newVideoInput];
[session addInput:audioInput];
newVideoInput = nil;
audioInput = nil;
audioDevice = nil;
newCamera = nil;
inputs = nil;
}
currentCam = #"Back";
}
else
{
//Camera is some weird third camera that doesn't exist yet! :O
NSLog(#"wat");
}
[session commitConfiguration];
}
only this much code can work
- (IBAction)switchCamera:(id)sender {
[captureSession beginConfiguration];
NSArray *inputs = [captureSession inputs];
//Remove all inputs
for (AVCaptureInput *input in inputs)
{
[captureSession removeInput:input];
}
//Video input
AVCaptureDevice *newCamera = nil;
if ([currentCam isEqualToString:#"Back"]){
newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
currentCam = #"Front";
}else{
newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
currentCam = #"Back";
}
//Audio input
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
AVCaptureDeviceInput * audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
NSError *err = nil;
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:newCamera error:&err];
if(!newVideoInput || err)
{
NSLog(#"Error creating capture device input: %#", err.localizedDescription);
}
else
{
[captureSession addInput:newVideoInput];
[captureSession addInput:audioInput];
}
[captureSession commitConfiguration];
}
I am using below code to capture sound. It works fine on all devices expect iPhone5 ios7.
Please help.
AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
if (audioInput)
{
[CaptureSession addInput:audioInput];
}
Try setting the below code in before getting the AVCaptureDevice instance
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error: nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
UInt32 doChangeDefault = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefault), &doChangeDefault);
I've been making this app that includes recording a video together with audio. The videorecording works as it should, and on most devices, so does the audo recording.
Except, on an iPad 2 (iOS 6.1.3) the audio recording does not work. In the official "Camera" app, the audio recording works flawlessly, so it's not a device-dependent problem.
This is the code:
NSURL *outputFileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#%#", NSTemporaryDirectory(), #"output.mov"]];
NSError *error;
AVCaptureDevice *device = [self frontCamera];
AVCaptureDeviceInput *inputVideo = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
self.session = [[AVCaptureSession alloc] init];
[self.session beginConfiguration];
if([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720]){
[self.session setSessionPreset:AVCaptureSessionPreset1280x720];
} else if([device supportsAVCaptureSessionPreset:AVCaptureSessionPresetiFrame960x540]){
[self.session setSessionPreset:AVCaptureSessionPresetiFrame960x540];
} else if([device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]){
[self.session setSessionPreset:AVCaptureSessionPreset640x480];
}
self.recorder = [[AVCamRecorder alloc] initWithSession:self.session outputFileURL:outputFileURL];
[self.recorder setDelegate:self];
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *audioError;
AVCaptureDeviceInput *inputAudio = [[AVCaptureDeviceInput alloc] initWithDevice:audioDevice error:&audioError];
NSLog(#"AudioError: %#", audioError);
NSLog(#"InputAudio: %#", inputAudio);
[self.session addInput:inputVideo];
[self.session addInput:inputAudio];
[self.session commitConfiguration];
[self.session startRunning];
In the log, "audioError" is null and "inputAudio“ seems to be a valid variable.
Any idea on how to fix this?