我的应用主要基于Core Bluetooth。 当某些特定事件发生时,应用程序会使用核心蓝牙背景模式唤醒并触发警报,但是当应用程序不在前台时,我无法使闹钟正常工作。
我有一个Alarm Singleton类,它会像这样初始化AVAudioPlayer
:
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);
这是调用我的警报代码时调用的方法:
-(void)startAlert
{
NSLog(@"%s", __FUNCTION__);
playing = YES;
[self.player play];
NSLog(@"%i", self.player.playing);
if (vibrate) {
[self vibratePattern];
}
}
现在,当应用位于前台时,self.player.playing
会返回1
但是当应用在后台self.player.playing
时会返回0
。为什么会这样?
正在调用所有代码,因此应用程序清醒且运行正常。
振动效果很好,使用AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
知道为什么这个声音不会播放?
由于
答案 0 :(得分:13)
Apple在其文档中对此有一个很好的Technical Q&A article(另请参阅Playing and Recording Background Audio)。
我认为缺少的一件事是你没有在Xcode设置中激活音频背景模式:
也许在警报方法中添加[self.player prepareToPlay]
也很有帮助。
答案 1 :(得分:9)
我有一个应用程序,但也需要背景音频,但我的应用程序使用应用程序后台模式“IP语音”,因为它有时需要记录。我播放背景音频告诉应用程序单例我需要在后台播放音频:
UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;
if([thePlayer play]){
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
编辑:您必须在应用转到后台之前致电[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
。在我的应用程序中,它是在您开始播放的同时,在您的应用中,如果播放器可能在后台启动,您应该这样做:
- (void)applicationDidEnterBackground:(UIApplication *)application{
// You should retain newTaskId to check for background tasks and finish them
newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}
答案 2 :(得分:3)
答案 3 :(得分:2)
我认为你有为应用指定的音频背景模式。即便如此,我也不确定您是否可以将音频会话设置为在后台处于活动状态。你需要在进入后台之前激活它。您可能还需要播放一些静音以保持此功能,但这似乎是不好的做法(可能会耗尽电池电量)。查看通知文档似乎有一种方法可以让本地通知播放包含在您的包中的音频样本,这似乎是您想要做的,所以也许这就是方式去吧。
答案 4 :(得分:1)
您需要启用应用以在后台处理音频中断(并结束中断)。应用通过通知中心处理音频中断:
首先,在通知中心注册您的应用:
- (void) registerForMediaPlayerNotifications {
[notificationCenter addObserver : self
selector: @selector (handle_iPodLibraryChanged:)
name: MPMediaLibraryDidChangeNotification
object: musicPlayer];
[[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];
}
现在在中断开始时保存玩家状态:
- (void) audioPlayerBeginInterruption: player {
NSLog (@"Interrupted. The system has paused audio playback.");
if (playing) {
playing = NO;
interruptedOnPlayback = YES;
}
}
重新启动音频会话并在中断结束时恢复播放:
-(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;
}
}
这是Apple的示例代码,完全实现了您尝试实现的目标:
答案 5 :(得分:1)
试试这个:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
试试这个http://www.sagorin.org/ios-playing-audio-in-background-audio/
答案 6 :(得分:0)
我也遇到了同样的问题,但是我只在应用程序在后台运行时才尝试面对声音,一旦应用程序出现在前台并且我播放声音的次数超过了正常工作也在后台。
在我的情况下,一旦启动应用/登录成功,我就在运行以下代码:
[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;
}