Trying to get a sound to play while the app is in the background. My code plays sound correctly if I start the sound in the following method.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self startSilentBackgroundSound]; // works fine
}
If I remove the code above and do it here it does NOT play the sound while the app is in the background.
- (void)applicationDidEnterBackground:(UIApplication *)application {
self.newTaskId = UIBackgroundTaskInvalid;
self.newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
[self startSilentBackgroundSound]; // does NOT work
}
In required background modes I have the following:
App plays audio or streams audio/video using AirPlay
App downloads content from the network
App registers for location updates
App provides Voice over IP services
App downloads content in response to push notifications
If anyone knows of a GitHub project I would very thankful!!!
//// CODE IN MY APP DELEGATE ////////
-(void)startSilentBackgroundSound {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
NSLog(@"Activating audio session");
if (![audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error]) {
NSLog(@"Unable to set audio session category: %@", error);
}
BOOL result = [audioSession setActive:YES error:&error];
if (!result) {
NSLog(@"Error activating audio session: %@", error);
}
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self startAlarmSound];
}
-(void)stopSilentBackgroundSound {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
NSLog(@"Deactivating audio session");
BOOL result = [audioSession setActive:NO error:&error];
if (!result) {
NSLog(@"Error deactivating audio session: %@", error);
}
[self stopSounds];
}
-(void)startAlarmSound {
self.silentAudioController = [[SilentAudioController alloc] init];
[self.silentAudioController tryPlayMusic];
}
-(void)stopSounds {
[self.silentAudioController tryStopMusic];
self.silentAudioController = nil;
}
/// HERE IS MY FILE THAT HANDLES ALL THE SOUNDS STUFF
#import "SilentAudioController.h"
@import AVFoundation;
@interface SilentAudioController () <AVAudioPlayerDelegate>
@property (strong, nonatomic) AVAudioSession *audioSession;
@property (strong, nonatomic) AVAudioPlayer *backgroundMusicPlayer;
@property (assign) BOOL backgroundMusicPlaying;
@property (assign) BOOL backgroundMusicInterrupted;
@property (assign) SystemSoundID pewPewSound;
@end
@implementation SilentAudioController
#pragma mark - Public
- (instancetype)init
{
self = [super init];
if (self) {
[self configureAudioSession];
[self configureAudioPlayer];
[self configureSystemSound];
}
return self;
}
- (void)tryPlayMusic {
// If background music or other music is already playing, nothing more to do here
if (self.backgroundMusicPlaying || [self.audioSession isOtherAudioPlaying]) {
return;
}
// Play background music if no other music is playing and we aren't playing already
//Note: prepareToPlay preloads the music file and can help avoid latency. If you don't
//call it, then it is called anyway implicitly as a result of [self.backgroundMusicPlayer play];
//It can be worthwhile to call prepareToPlay as soon as possible so as to avoid needless
//delay when playing a sound later on.
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];
self.backgroundMusicPlaying = YES;
}
- (void)tryStopMusic {
[self.backgroundMusicPlayer stop];
self.backgroundMusicPlaying = NO;
}
- (void)playSystemSound {
AudioServicesPlaySystemSound(self.pewPewSound);
}
#pragma mark - Private
- (void) configureAudioSession {
// Implicit initialization of audio session
self.audioSession = [AVAudioSession sharedInstance];
// Set category of audio session
// See handy chart on pg. 46 of the Audio Session Programming Guide for what the categories mean
// Not absolutely required in this example, but good to get into the habit of doing
// See pg. 10 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"
NSError *setCategoryError = nil;
if ([self.audioSession isOtherAudioPlaying]) { // mix sound effects with music already playing
[self.audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&setCategoryError];
self.backgroundMusicPlaying = NO;
} else {
[self.audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
}
if (setCategoryError) {
NSLog(@"Error setting category! %ld", (long)[setCategoryError code]);
}
}
- (void)configureAudioPlayer {
// Create audio player with background music
NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:@"background-music-aac" ofType:@"caf"];
NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:nil];
self.backgroundMusicPlayer.delegate = self; // We need this so we can restart after interruptions
self.backgroundMusicPlayer.numberOfLoops = -1; // Negative number means loop forever
}
- (void)configureSystemSound {
// This is the simplest way to play a sound.
// But note with System Sound services you can only use:
// File Formats (a.k.a. audio containers or extensions): CAF, AIF, WAV
// Data Formats (a.k.a. audio encoding): linear PCM (such as LEI16) or IMA4
// Sounds must be 30 sec or less
// And only one sound plays at a time!
NSString *pewPewPath = [[NSBundle mainBundle] pathForResource:@"pew-pew-lei" ofType:@"caf"];
NSURL *pewPewURL = [NSURL fileURLWithPath:pewPewPath];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)pewPewURL, &_pewPewSound);
}
#pragma mark - AVAudioPlayerDelegate methods
- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
//It is often not necessary to implement this method since by the time
//this method is called, the sound has already stopped. You don't need to
//stop it yourself.
//In this case the backgroundMusicPlaying flag could be used in any
//other portion of the code that needs to know if your music is playing.
self.backgroundMusicInterrupted = YES;
self.backgroundMusicPlaying = NO;
}
- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
//Since this method is only called if music was previously interrupted
//you know that the music has stopped playing and can now be resumed.
[self tryPlayMusic];
self.backgroundMusicInterrupted = NO;
}
@end
Aucun commentaire:
Enregistrer un commentaire