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");
}
}
Related
In my situation, when I pressed play button sound comes low at starting and after some time it comes louder for speaker. In my project too many audio files are available. When I pressed first then it starts with low sound and when I pressed second and third it starts and all played in loud sound from speaker. Every time when I pressed play button, it executed below code.
- (SWYAudioBoardPlayer*) initWithMediaKey:(NSString *) mediaKey{
self.session = [AVAudioSession sharedInstance]; // Object declare above
NSError *error = nil;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:#"audioUrl" error:&error];
[audioPlayer setDelegate:self];
isPause = false;
audioPlayer.volume = 1.0;
defaultAVAudioSessionCategory = [self.session category]; // Object declare above
[self loudSpeakerOn:true];
return [self init]; }
- (void) loudSpeakerOn:(BOOL)isLoudSpeaker{
[self.session setActive:NO error:nil];
BOOL success;
NSError* error;
success = [self.session overrideOutputAudioPort:isLoudSpeaker?AVAudioSessionPortOverrideSpeaker:AVAudioSessionPortOverrideNone error:&error];
if (!success) NSLog(#"AVAudioSession error setting category:%#",error);
[self.session setActive:YES error:nil];}
I am using in my
viewDidLoad:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *setCategoryError = nil;
BOOL success = [audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
if (!success) { /**handle the error condition */ }
NSError *activationError = nil;
success = [audioSession setActive:YES error:&activationError];
if (!success) { /**handle the error condition */ }
NSURL *SoundURL1 = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"music1" ofType:#"caf"]];
and have initialized in the interface
AVAudioPlayer *playSoundURL1;
and called in my method
[playSoundURL1 play];
Sound plays perfectly fine when I'm using headphones when ringer is silent or not silent. However, without any headphones I can only hear the sound when the ringer is not silenced.
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.
I am using AVAudioPlayer in my application.my problem is, it is not playing when the device gets locked.
Follow the steps in the image below. It should work.
I use this code:
- (void)playAudio:(NSString *)path {
NSError *error;
NSURL *audioURL = [NSURL fileURLWithPath:path];
self.notificationPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:audioURL error:&error];
self.notificationPlayer.delegate = self;
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
NSError *errorSession = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:nil];
[audioSession setActive:NO error:&errorSession];
[self.notificationPlayer prepareToPlay];
[self.notificationPlayer setVolume:1.0];
[self.notificationPlayer play];
if (error) {
NSLog(#"error %#",[error localizedDescription]);
}
NSLog(#"Should play music");
}
- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[player stop];
[[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}
Reference Link
Hope this code useful for you.
Using AVAudioPlayer I'm trying to play sounds while the iphone player is playing. Also when device is locked.
The thing is, that in iPhone 4s ios 7 - works fine.
But on iPhone 5 with 6 and 7 ios nothing happens.
In the -Info.plist in Required background modes I wrote
App plays audio or streams audio/video using AirPlay
in Player.h implemented:
#property (nonatomic, strong) AVAudioPlayer *notificationPlayer;
<AVAudioPlayerDelegate, AVAudioSessionDelegate> with
#import <AVFoundation/AVFoundation.h> included
Also in Player.m
//this is called on viewDidLoad
-(void) prepareSound{
[[AVAudioSession sharedInstance] setDelegate:self];
}
//overriden function
- (void)playAudio:(NSString *)path{
[[AVAudioSession sharedInstance]
setCategory: AVAudioSessionCategoryAmbient
withOptions: AVAudioSessionCategoryOptionDuckOthers
error: nil];
NSError *error;
NSURL *audioURL = [NSURL fileURLWithPath:path];
self.notificationPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:audioURL error:&error];
self.notificationPlayer.delegate = self;
[self.notificationPlayer prepareToPlay];
[self.notificationPlayer setVolume:1.0];
[self.notificationPlayer play];
if (error) {
NSLog(#"error %#",[error localizedDescription]);
}
}
- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[player stop];
[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient
withOptions: 0
error: nil];
[[AVAudioSession sharedInstance] setActive:YES withOptions: 0 error:nil];
}
//Call from here
-(void) customMethod{
[self playAudio:[[NSBundle mainBundle] pathForResource:#"3" ofType:#"wav"]];
}
Regards.
Another Really important thing to note while playing sounds in background is whether or not you have permission to the file. If you are playing a bundle file, you have permission, and presumably some file streamed from the internet, but if you've downloaded media into the documents directory, then you must set permissions appropriately, especially if your application natively locks files.
This tends to match with what many people see as a symptom where the file will continue to play for a couple of seconds, 5-15, then stop. If you're listening for the finished method, you'll see an error flag. Why: AVAudioPlayer won't load the entirety of your audio file into memory when you first play it.
Example:
NSURL url = [NSURL URLWithString:#""];
NSError *error = nil;
[[NSFileManager defaultManager] setAttributes:#{NSFileProtectionKey :
NSFileProtectionCompleteUntilFirstUserAuthentication} ofItemAtPath:[url path] error:&error];
Your options are as follows:
NSFileProtectionComplete;
NSFileProtectionCompleteUnlessOpen;
NSFileProtectionCompleteUntilFirstUserAuthentication;
NSFileProtectionNone;
I should use the following code
- (void)playAudio:(NSString *)path {
NSError *error;
NSURL *audioURL = [NSURL fileURLWithPath:path];
self.notificationPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:audioURL error:&error];
self.notificationPlayer.delegate = self;
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
NSError *errorSession = nil;
[audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:nil];
[audioSession setActive:NO error:&errorSession];
[self.notificationPlayer prepareToPlay];
[self.notificationPlayer setVolume:1.0];
[self.notificationPlayer play];
if (error) {
NSLog(#"error %#",[error localizedDescription]);
}
NSLog(#"Should play music");
}
- (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[player stop];
[[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
}