This is the code I have right now for pausing a recording when a user receives a phone call and resuming it after they hang up.
- (void)handleAudioSessionInterruption:(NSNotification *)notification
{
NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
switch (interruptionType.unsignedIntegerValue) {
case AVAudioSessionInterruptionTypeBegan:{
_currentAudioSessionMode = EXAVAudioSessionModeInactive;
if (_audioRecorder.recording) {
[_audioRecorder pause];
[self demoteAudioSessionIfPossible];
}
} break;
case AVAudioSessionInterruptionTypeEnded:{
_currentAudioSessionMode = EXAVAudioSessionModeActive;
if (_audioRecorder && !_audioRecorder.recording) {
if (_allowsAudioRecording) {
[self promoteAudioSessionIfNecessary];
_audioRecorderShouldBeginRecording = true;
[_audioRecorder record];
}
_audioRecorderShouldBeginRecording = false;
}
} break;
default:
break;
}
What I would like to achieve is to keep recording, but capture pure silence while a user is on a phone call. This is how it works on Android and we care about the correct duration of the recording. Any idea how to do it?
#import <AVFoundation/AVFoundation.h>
Set up the audio session to use the AVAudioSessionCategoryPlayAndRecord category and activate it:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
Set up the audio recorder using the AVAudioRecorder class, specifying the URL where the audio file will be saved and the audio settings for the recording:
NSURL *url = [NSURL fileURLWithPath:#"/path/to/audio/file.m4a"];
NSDictionary *settings = #{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVSampleRateKey: #44100.0f,
AVNumberOfChannelsKey: #1,
};
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:nil];
Start the recording by calling the record method on the audio recorder:
[recorder record];
To stop the recording, call the stop method on the audio recorder:
[recorder stop];
To record silence while the user is on a phone call, you can use the audioRecorderDidFinishRecording:successfully: delegate method to detect when the recording has stopped due to the phone call and start a new recording.
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
// Check if the recording was stopped due to a phone call
if (!flag) {
// Start a new recording
[recorder record];
}
}
So i tried by all guides that provided here to play at same time 2 sounds by AVAudioplayer + AVA , AVA + System Sound and it didn't worked.
Second sound never sounds.
So i decided to stop main audio before i play 2. audio (the bell audio)
and it didn't worked.
I need to play 2 sounds at the same time or when 1. audio will be paused.(I have delegate in my h file)
Here is code , this method called by a NSTimer every 0.5 seconds:
if(!(bellint == -0.5)){
bellint = bellint+0.5;
}
if(!(self.loaderAudioView.fakeDuration == secondsTime)){
secondsTime = secondsTime +0.5;
self.loaderAudioView.fakeTimer = secondsTime ;
NSLog(#"fakedur %f , secondsOfTimer : %f" ,self.loaderAudioView.fakeTimer,secondsTime);
}
else{
self.loaderAudioView.fakeTimer = secondsTime = 0 ;
[self.timer invalidate];
self.playOrPauseButton.on = NO;
}
if((int)secondsTime % self.bellsInt == 0.0){
[self.loaderAudioView pausePlayer];
bellint = bellint+0.5;
NSURL *path = [[NSBundle mainBundle] URLForResource:#"bell_start" withExtension:#"mp3"];
// I've putted here AVAudioplayer initialization cause you can see. It's in another method realized.Here I just call [objAudio play];
AVAudioPlayer* objAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:path error:nil];
objAudio.delegate = self;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[objAudio prepareToPlay];
[objAudio play];
NSLog(#"BANG");
}
if(bellint == 5.0){
[self.loaderAudioView playPlayer];
bellint = -0.5;
}
So after i placed my objAudio to h file and initialized
self.objAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:path error:nil];
Everything became as should be.
I don't know why it didn't worked like that.
Is it bug or there a certain reason.
If anyone knows why or have a theory I welcome.
I'm using this code to load and begin playing a sound:
- (void) buzz {
if (buzzSound == nil) {
[[AVAudioSession sharedInstance] setActive: YES error: nil];
NSError *error;
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *soundFile = [[NSURL alloc] initFileURLWithPath: [mainBundle pathForResource: #"buzzer_8"
ofType: #"wav"]];
buzzSound = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFile error: &error];
buzzSound.delegate = self;
if (DEBUG_BLE && error != nil)
printf("Error loading sound: %s\n", [[error localizedDescription] cStringUsingEncoding: NSUTF8StringEncoding]);
}
// Play the sound.
buzzSound.numberOfLoops = -1;
[buzzSound prepareToPlay];
[buzzSound setVolume: 1.0];
if (![buzzSound play]) {
self.buzzSound = nil;
[self buzzSound];
}
}
This code is triggered by a touch down event on a button. When the button gets a touch up event (on or off of the button), it stops the sound with:
[buzzSound stop];
The buzz sound itself is a short .wav file.
The first time buzz is called, the sound plays once. It does not repeat. On subsequent calls it does repeat. Why?
Intermittently, if I play the sound for a short period of time that is about the same length of time as one cycle through the sound file, the sound fails on subsequent calls to buzz, and play returns NO. Thereafter, play will always return NO until the sound is reloaded, after which is plays the sound once as noted above and then starts working correctly until the sound is played for a short time, again.
I do have audioPlayerDecodeErrorDidOccur:error: set up; no error is reported.
I have an app mostly based around Core Bluetooth.
When something specific happens, the app is woken up using Core Bluetooth background modes and it fires off an alarm, however I can't get the alarm working when the app is not in the foreground.
I have an Alarm Singleton class which initialises AVAudioPlayer like this:
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:soundName
ofType:#"caf"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[self.player prepareToPlay];
self.player.numberOfLoops = -1;
[self.player setVolume:1.0];
NSLog(#"%#", self.player);
This is the method that is called when my alarm code is called:
-(void)startAlert
{
NSLog(#"%s", __FUNCTION__);
playing = YES;
[self.player play];
NSLog(#"%i", self.player.playing);
if (vibrate) {
[self vibratePattern];
}
}
Now when the app is in the foreground, self.player.playing returns 1 however when the app is in the background self.player.playing returns 0. Why would this be?
All the code is being called, so the app is awake and functioning.
The vibrate works perfectly which uses AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
Any idea why this sound won't play?
Thanks
Apple has a nice Technical Q&A article about this in its documentation (see also Playing and Recording Background Audio).
I think one big thing missing is that you haven't activated the Audio Background Mode in the Xcode settings:
Maybe also adding [self.player prepareToPlay] in your alert method is helpful.
I have an App than also needs background audio but my App works with the App background mode "Voice over IP" as it needs to record sometimes. I play background audio telling the App singleton I need to play audio in background:
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
if([thePlayer play]){
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
EDIT: You must call [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL]; before your app goes to background. In my app, it is at the same time you start playing, in yours, if the player might be started in background, you should do:
- (void)applicationDidEnterBackground:(UIApplication *)application{
// You should retain newTaskId to check for background tasks and finish them
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
Apple docs
Either enable audio support from the Background modes section of the Capabilities tab
Or enable this support by including the UIBackgroundModes key with the audio value in your app’s Info.plist file
I take it you have the audio background mode specified for the app. Even so, I'm not sure you can set an audio session to be active while in the background. You need to have activated it before going into the background. You may also need to play some silent audio to keep this active, but this is seems like bad practice (it may drain the battery). Looking at the docs for notifications there seems to be a way to have a local notification play an audio sample that's included in your bundle, which seems to be what you want to do, so maybe that's the way to go.
Try this :
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
link
Try this http://www.sagorin.org/ios-playing-audio-in-background-audio/
You need to enable your app to handle audiosession interruptions (and ended interruptions) while in the background. Apps handle audio interruptions through notification center:
First, register your app with the notification center:
- (void) registerForMediaPlayerNotifications {
[notificationCenter addObserver : self
selector: #selector (handle_iPodLibraryChanged:)
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];
}
Now save player state when interruption begins:
- (void) audioPlayerBeginInterruption: player {
NSLog (#"Interrupted. The system has paused audio playback.");
if (playing) {
playing = NO;
interruptedOnPlayback = YES;
}
}
And reactivate audio session and resume playback when interruption ends:
-(void) audioPlayerEndInterruption: player {
NSLog (#"Interruption ended. Resuming audio playback.");
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (interruptedOnPlayback) {
[appSoundPlayer prepareToPlay];
[appSoundPlayer play];
playing = YES;
interruptedOnPlayback = NO;
}
}
Here's Apple's sample code with full implementation of what you're trying to achieve:
https://developer.apple.com/library/ios/samplecode/AddMusic/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008845
I was also facing the same problem, but i was only facing it only during initial time when i was trying to play a sound while app was in background, once the app comes in foreground and i play the sound once than it works in background also.
So as soon as app is launched/ login is successful in my case, i was running this code:
[self startRingcall];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self stopRingcall];
});
- (void)startRingcall
{
if( self.audioPlayer )
[self.audioPlayer stop];
NSURL* musicFile = [NSURL fileURLWithPath:[[[UILayer sharedInstance] getResourceBundle] pathForResource:#"meetcalling" ofType:#"caf"]];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&error];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
if (error != nil) {
NSLog(#"meetringer sound error -> %#",error.localizedDescription);
}
self.audioPlayer.volume = 0;
[self.audioPlayer play];
self.audioPlayer.numberOfLoops = 1;
}
- (void)stopRingcall
{
if( self.audioPlayer )
[self.audioPlayer stop];
self.audioPlayer = nil;
}
Record something to the specified file by
[[ AVAudioRecorder alloc] initWithURL:_fileURL settings:settings error:&_error];
Need to play the recorded file immediately once stop the recorder and save file successfully.
Question is how to when is okay to read the file and playback it. Which delegate api could be used ?
set the delegate of your AVAudioRecorder instance
AVAudioRecorder* test = [[AVAudioRecorder alloc] initWithURL:_fileURL settings:settings error:&_error];
then implement
- (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
// play the recorded audio here
if (flag)
{
NSError* error;
AVAudioPlayer* player = [[[AVAudioPlayer alloc] initWithContentsOfURL:[recorder url] error:&error] autorelease];
if (!error)
{
[player play];
}
}
}
Have you tried using
- (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
// Play the audio
}