I have an application with App plays audio and App provides Voice over IP services options configured in the .plist.
The application is receiving socket events (even in background) and regarding the events, plays sound. When the application is in foreground, all is ok. When the app is in background, the app is triggered, the play method of the player is called, but without sound.
I have tried many sample code from Internet but nothing is working. I have tried to start playing sound in foreground and then move my app in background and it's working.
What is the problem to start playing a sound when the app is in background?
Here's my code handling an event when my app is triggered in background:
NSError *error;
NSURL *audioFileLocationURL = [[NSBundle mainBundle] URLForResource:#"HeadspinLong" withExtension:#"caf"];
if (audioPlayer != nil) return;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileLocationURL error:&error];
audioPlayer.delegate=self;
if (error) {
NSLog(#"%#", [error localizedDescription]);
}
audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive: YES error: &error];
audioSession.delegate=self;
if (error) {
NSLog(#"");
}
Seems like an obvious question, but are you actually calling the play method on the audioPlayer object in your real-life application? Probably at the end of background event handler?
i.e. [audioPlayer play];
For my understanding it seems not possible to start playing a music when the app is in background... It is only possible to continue playing an existing played music in background
Related
Encountering a very weird issue. I'm trying to use AVAudioPlayer to play a simple sound file from disk. I maintain a strong reference to it via a property so ARC doesn't kill it prematurely. As I said in the title, I get no sound, errors and no delegate methods are called--including didFinishPlaying (which I would expect). The only thing that seems to "happen" is I hear two quiet clicks...
Now this is the weird part...if I set a breakpoint just before [_player play], then step over, the audio plays fine!! This basically confirms to me that I have set things up correctly, and makes me think that something else is stepping on the shared AVAudioSession from another thread? I'm not sure. The total lack of delegate calls is very odd--it seems that something should be called whenever AVAudioPlayer finishes.
I am also using OpenEars for speech recognition, but I call suspendListening on it before attempting to play the audio. I have also tried disabling OpenEars entirely, to try and isolate it as a cause--but this had no effect, either. Very perplexing. Appreciate any help!
-(void)playAudioNoteWithPath:(NSString *)filePath
{
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions:AVAudioSessionCategoryOptionAllowBluetooth
error:&error];
if (error) {
DLog(#"ERROR setting audio session category: %#", [error localizedDescription]);
}
NSURL *URL = [NSURL URLWithString:filePath];
if (!URL) {
DLog(#"No file path!!");
}
_player = [[AVAudioPlayer alloc] initWithContentsOfURL:URL
error:&error];
if (error) {
DLog(#"ERROR initializing audio player: %#", [error debugDescription]);
}
_player.delegate = self;
[_player prepareToPlay];
// Setting a breakpoint here will cause playback to succeed.
if (![_player play]) {
DLog(#"ERROR playing!!");
}
}
Well, I seem to have found a fix, though I'm not sure why...since it's not that much code, I just moved it into the calling class. So the calling class now plays AudioNotes directly, instead of AudioNotes playing themselves. Now it works.
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;
}
I'm currently trying to implement a system like the alarm one to alert the phone when an event occurred (in my case a bluetooth event). I want this alert to occur even if the phone is in silent and in background.
I create a local notification but i can't get sound played if the phone is in silent mode (which seems to be normal since we put the phone in silent).
So i tried to manage the sound by myself and i'm struggling with playing sound in background. So far i implement the "App plays audio or streams audio/video using AirPlay" key in my plist and i'm using this code.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
BOOL result = [audioSession setActive:YES error:&error];
if ( ! result && error) {
NSLog(#"Error For AudioSession Activation: %#", error);
}
error = nil;
result = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
if ( ! result && error) {
NSLog(#"Error For AudioSession Category: %#", error);
}
if (player == nil) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"bell" ofType:#"wav"];
NSURL *url = [NSURL fileURLWithPath:path];
NSError *err = nil;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&err];
if(err)
{
NSLog(#"Error Player == %#", err);
}
else {
NSLog(#"Play ready");
}
}
[player prepareToPlay];
[player setVolume:1.0];
if([player play])
{
NSLog(#"YAY sound");
}
else {
NSLog(#"Error sound");
}
The sound works great in foreground, even in silent mode, but i got no sound at all in background. Any ideas ?
Thanks
EDIT:
Finally i got it working with the above code. The only missing point is that i was trying to play the sound in somewhat appeared to be a different thread, when i play it right in my bluetooth event and not my function call it's working.
An app that plays audio continuously (even while the app is running in the background) can register as a background audio app by including the UIBackgroundModes key (with the value audio) in its Info.plist file. Apps that include this key must play audible content to the user while in the background.
Apple reference "Playing Background Audio"
Ensuring That Audio Continues When the Screen Locks
Found here
I'm not sure if your problem is that you have not configure correctly the audio session output. I had similar problem while playing .wav in my app. I only listened them with earphones. This method helped me:
- (void) configureAVAudioSession {
//get your app's audioSession singleton object
AVAudioSession *session = [AVAudioSession sharedInstance];
//error handling
BOOL success;
NSError* error;
//set the audioSession category.
//Needs to be Record or PlayAndRecord to use audioRouteOverride:
success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
error:&error];
if (!success) NSLog(#"AVAudioSession error setting category:%#",error);
//set the audioSession override
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
error:&error];
if (!success) NSLog(#"AVAudioSession error overrideOutputAudioPort:%#",error);
//activate the audio session
success = [session setActive:YES error:&error];
if (!success) NSLog(#"AVAudioSession error activating: %#",error);
else NSLog(#"audioSession active"); }
Try it out!
You need to make couple of changes in plist file.
for enabling sound when the app enter's Background.
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 in background.
It works fine for me. :)
for more please refer to Playing Audio in background mode and Audio Session Programming Guide
I have to give audio feedback when my app is in foreground and also in background. But when the app enters background audio feedback is not heard. In info.plist I have set background mode to App plays audio or streams audio/video using AirPlay and used the following but the audioPlayerDidFinishPlaying delegate is not called when app enters background and audio is not heard.
AVAudioPlayer *sound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&err];
sound.delegate = self;
///Fixed the issue No audible feedback when main audio is silent
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
// This is necessary if you want to play a sequence of songs, otherwise your app will be
// killed after the first one finishes.
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[soundQueue addObject:sound];
You need to make couple of changes in plist file.
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 in background.
It works fine for me. :)
for more please refer to Playing Audio in background mode and Audio Session Programming Guide
I know this is a question has been asked for many times, and I have checked most of the answers related in SO, but I have no luck finding the right answer to my problem.
Here is the problem:
I tried to play a mp3 file (just 2 seconds at most) in a game when some event is triggered, and I use the AudioPlayer to do so, below is the code blocks:
NSError *error;
AVAudioPlayer *audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource: #"ding" withExtension: #"mp3"] error:&error] autorelease];
if (error) {
NSLog(#"Error creating audio player: %#", [error userInfo]);
}
else {
BOOL success = [audioPlayer play];
// This always is "Play sound succeeded"
NSLog(#"Play sound %#", success ? #"succeeded" : #"failed");
}
When I ran this code in iPhone 4s, iTouch 3/4, the sound always played well and clear, but in iPad 1 or iPad2, there is no sound out from speaker. But when I plugged in my headphone, weird thing happened that there is sound from my headphone! The iPad is not in mute mode and the URL is correct.
I am confused why this happened.
PS: I tried the following code (got from HERE) to output the audio output port type:
CFDictionaryRef asCFType = nil;
UInt32 dataSize = sizeof(asCFType);
AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, &asCFType);
NSDictionary *easyPeasy = (NSDictionary *)asCFType;
NSDictionary *firstOutput = (NSDictionary *)[[easyPeasy valueForKey:#"RouteDetailedDescription_Outputs"] objectAtIndex:0];
NSString *portType = (NSString *)[firstOutput valueForKey:#"RouteDetailedDescription_PortType"];
NSLog(#"first output port type is: %#!", portType);
When I plugged in my headphone, the output was "first output port type is headphone!" and when I unplugged it , the output turned out to be "first output port type is speaker!"
It would be great is someone can offer some help or advice.
There is a code change solution to this, but also an end-user solution: turn the 'Ring/Silent switch' to on. Specifically, the problem is that the default setting of AVAudioSessions, AVAudioSessionCategorySoloAmbient, is to be silent if the phone is in silent mode.
As mentioned by the original poster, you can override this behavior by calling:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
AVAudioSession Reference recommends setting the AVAudioSessionCategoryPlayback category:
For playing recorded music or other sounds that are central to the successful use of your app.
To update #JonBrooks answer above with Swift 2 syntax, I put the following in my viewDidLoad() to override the silent switch and get my sound to play:
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch let error as NSError {
print(error)
}
Solution found!
After I added this line of code before playing, the sound finally is played out from speaker
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
I now still do not understand why, and I will dig into it.:)