【问题标题】:Audio playing while app in background iOS应用程序在后台 iOS 中播放音频
【发布时间】:2014-06-11 07:15:53
【问题描述】:

我有一个主要基于核心蓝牙的应用程序。 当发生特定事情时,应用程序会使用 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);

的振动效果很好

知道为什么这个声音不会播放吗?

谢谢

【问题讨论】:

  • 你用设备测试过吗?
  • 当然可以。我需要蓝牙设备才能正常工作。
  • 在这个答案中有你需要的所有信息..stackoverflow.com/questions/22591421/…
  • 这是我几周前的原始问题,但没有得到有效的答案:(
  • 在重要代码中传递错误参数并检查返回值。我很确定 AudioSession 返回错误。

标签: ios objective-c audio background avaudioplayer


【解决方案1】:

Apple 在其文档中对此有很好的Technical Q&A article(另请参阅Playing and Recording Background Audio)。

我认为缺少的一件大事是您没有在 Xcode 设置中激活 Audio Background Mode

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 恐怕这行不通。 if([player play]) 返回 FALSE
    • 好的,编辑了我的答案,也许问题是你在进入后台之前没有开始玩
    • 在需要之前我不想开始玩。
    • 你可以!在applicationDidEnterBackground: 时开始播放声音,但将音量设置为 0。然后您将能够稍后播放声音...
    • 这是一个想法。如果静音播放 3-4 小时,对电池有何影响?
    【解决方案3】:

    Apple docs

    功能标签

    的背景模式部分启用音频支持

    或者通过在您应用的 Info.plist 文件中包含 UIBackgroundModes 键和 audio 值来启用此支持

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 是的,我在 plist 中有背景音频。我最初使用通知,但是我需要它在手机静音时也发出声音。就没有其他办法了吗?
      • 嗯,在手机静音时发出声音似乎不受标准通话的支持。
      • 上述方法在静音时播放。有很多应用程序可以做这种事情。
      • 是的,即使在静音模式下,音频会话也会在后台播放。我所有的音乐应用程序都是这样做的。请参阅我上面关于后台唤醒方法调用问题的回答。
      【解决方案5】:

      试试这个:

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

      link

      试试这个http://www.sagorin.org/ios-playing-audio-in-background-audio/

      【讨论】:

        【解决方案6】:

        您需要让您的应用在后台处理音频会话中断(和结束中断)。应用通过通知中心处理音频中断:

        1. 首先,向通知中心注册您的应用:

          - (void) registerForMediaPlayerNotifications {
          
              [notificationCenter addObserver : self
                                      selector: @selector (handle_iPodLibraryChanged:)
                                          name: MPMediaLibraryDidChangeNotification
                                        object: musicPlayer];
          
              [[MPMediaLibrary defaultMediaLibrary] beginGeneratingLibraryChangeNotifications];
          
          }
          
        2. 现在在中断开始时保存播放器状态:

          - (void) audioPlayerBeginInterruption: player {
          
              NSLog (@"Interrupted. The system has paused audio playback.");
          
              if (playing) {
                  playing = NO;
                  interruptedOnPlayback = YES;
              }
          }
          
        3. 并在中断结束时重新激活音频会话并恢复播放:

          -(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 的示例代码,其中完整实现了您想要实现的目标:

        https://developer.apple.com/library/ios/samplecode/AddMusic/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008845

        【讨论】:

        • 您好,startAlert 被调用,因为应用已被蓝牙后台模式唤醒。那么如何调用 audioPlayerEndInterruption 呢?还是当我第一次尝试play 时,代表调用了它?
        • 1.如果调用 startAlert 并且播放器未播放,则意味着您的 audioPlayer 状态和上下文在应用程序暂停时丢失,然后您有机会保存它。 2.audioPlayerEndInterruption 是在你的应用从挂起状态唤醒时被通知中心调用的,这就是为什么你的音频播放应用需要注册通知中心来处理音频中断的原因。 3. 现在,当中断结束时,您可以使用以下命令重新激活您的音频会话:[[AVAudioSession sharedInstance] setActive: YES error: nil];我将在几分钟内用详细的代码编辑我的主要答案。
        • 谢谢。我似乎没有在任何地方使用 AVAudioSession,只是 AVAudioPlayer。上面定义的 mediaPlayer 是什么?
        • 好的,这些通知似乎是针对 MPMusicPlayerController 的,我没有使用它,因为我没有播放用户库中的媒体。
        • 不知道您正在使用该库。相应地编辑了我的答案(步骤 1)。它也存在于 Apple 的示例代码中。希望你最终让它工作:)
        【解决方案7】:

        我也遇到了同样的问题,但我只是在最初尝试在应用程序处于后台时播放声音时遇到它,一旦应用程序进入前台并且我播放一次声音就可以了也在后台。

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

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

        【讨论】:

          猜你喜欢
          • 2021-01-05
          • 2013-04-20
          • 2013-03-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-30
          • 1970-01-01
          • 2011-05-24
          相关资源
          最近更新 更多