应用程序在后台iOS中播放音频

应用程序在后台iOS中播放音频,ios,objective-c,audio,background,avaudioplayer,Ios,Objective C,Audio,Background,Avaudioplayer,我有一个主要基于核心蓝牙的应用程序。 当某些特定的事情发生时,应用程序会被核心蓝牙背景模式唤醒,并发出警报,但是当应用程序不在前台时,我无法让警报工作 我有一个Alarm Singleton类,它初始化AVAudioPlayer,如下所示: NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:soundName

我有一个主要基于核心蓝牙的应用程序。 当某些特定的事情发生时,应用程序会被核心蓝牙背景模式唤醒,并发出警报,但是当应用程序不在前台时,我无法让警报工作

我有一个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_振动)的振动功能工作正常

你知道为什么这个声音不能播放吗


谢谢

我想您已经为应用程序指定了音频背景模式。即便如此,我也不确定您是否可以在后台将音频会话设置为活动状态。你需要在进入后台之前激活它。您可能还需要播放一些静音音频以保持激活状态,但这似乎是一种不好的做法(可能会耗尽电池电量)。查看文档中的通知,似乎有一种方法可以让本地通知播放捆绑包中包含的音频样本,这似乎是您想要做的,所以也许这就是方法。

苹果在其文档中对此有一个很好的解释(另请参阅)

我认为缺少的一点是,您没有在Xcode设置中激活音频背景模式:


也许在您的提醒方法中添加
[self.player prepareToPlay]
也会有所帮助。

您需要启用应用程序,以便在后台处理音频会话中断(和已结束的中断)。应用程序通过通知中心处理音频中断:

- (void) registerForMediaPlayerNotifications {

    [notificationCenter addObserver : self
                            selector: @selector (handle_iPodLibraryChanged:)
                                name: MPMediaLibraryDidChangeNotification
                              object: musicPlayer];

    [[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];

}
  • 首先,向通知中心注册您的应用程序:

    - (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;
        }
    }
    
  • 以下是苹果的示例代码,其中包含您试图实现的目标的完整实现:


    我有一个应用程序也需要背景音频,但我的应用程序使用应用程序背景模式“IP语音”,因为它有时需要录制。我播放背景音频,告诉应用程序singleton我需要在背景中播放音频:

    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];   
    }
    
    试试这个:

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
    

    试试这个

    从功能选项卡的背景模式部分启用音频支持


    或者通过在应用程序的Info.plist文件中包含UIBackgroundModes键和audio值来启用此支持。我也遇到了同样的问题,但我只是在应用程序处于后台时尝试播放声音的初始时间才遇到这个问题,一旦应用程序出现在前台,我播放一次声音,它也会在后台工作

    因此,在我的情况下,一旦应用程序启动/登录成功,我就会运行以下代码:

    [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;
    }
    


    是的,我在plist中有背景音频。我最初使用的通知,但我需要它也发出声音时,手机是无声的。没有其他方法可以解决这个问题吗?嗯,当手机处于静默状态时发出声音似乎不受标准通话的支持。上面使用的方法在静默状态下播放。有很多应用程序都能做到这一点。是的,音频会话将在后台播放,即使在静音模式下也是如此。我所有的音乐应用程序都能做到这一点。请看我上面关于背景唤醒方法呼叫问题的回答。你用设备测试过吗?当然可以。我需要蓝牙设备才能正常工作。在这个答案中有你需要的所有信息。。这是几周前我最初的问题,没有得到有效的答案:(在重要代码中传递错误参数并检查返回值。我非常确定AudioSession返回错误。您好,调用startAlert是因为应用程序已被蓝牙背景模式唤醒。那么我如何调用audioPlayerEndInterruption?还是在我第一次尝试
    播放
    时由代理调用?1.如果是startAlert被调用,而播放机未播放,这意味着您的audioPlayer状态和上下文在您有机会保存应用程序之前已在应用程序暂停时丢失。2.当您的应用程序从暂停中唤醒时,通知中心会调用audioPlayerEndInterruption,这就是为什么您的音频播放应用程序需要注册到通知中心以便可以处理音频中断。3.现在,当中断结束时,您可以使用:[[AVAudioSession sharedInstance]setActive:YES错误:nil]重新激活音频会话;我将在几分钟内编辑我的主要答案,并提供详细的代码。谢谢。我似乎没有在任何地方使用AVAudioSession,只使用AVAudioPlayer。mediaPlayer的上述定义是什么?好的,这些通知似乎是针对
    MPMusicLayerController
    的,我没有使用它,因为我没有从用户库中播放媒体。不知道你是u在库中唱歌。相应地编辑了我的答案(步骤1)。它也在苹果的示例代码中。希望你最终能让它工作:)恐怕这不起作用。如果([player play])返回FALSEOk,编辑了我的答案,可能问题是你在去后台之前没有开始播放,但在需要之前我不想开始播放。你可以!在
    applicationIdentinterbackground:
    when中启动声音,但将音量设置为0。然后你以后就可以播放声音了……这是个主意。呵呵