【问题标题】:Background audio doesn't resume after a call通话后背景音频不恢复
【发布时间】:2012-03-17 14:46:08
【问题描述】:

我的背景音频几乎一直都能正常工作。屏幕锁定,或静音开关打开。但是当用户在后台有应用程序,并且接到电话时,即使用户没有接听电话,中断结束后背景音频也不会恢复。

如果音乐应用被中断,它会正确恢复背景音频。

我是否缺少某些属性,还是需要回调或设置后台任务以在中断后继续执行后台音频?或者这是我们做不到的?

【问题讨论】:

  • 我也面临同样的问题,请您帮帮我!
  • 但是这个应用程序运行良好 na link ,他们是怎么做的?
  • 应用有问题。
  • 不,该应用只能正常运行。我也得到了解决方案!
  • 你愿意分享解决方案吗,Rajesh?

标签: ios audio background


【解决方案1】:

当应用程序在后台时,我们在呼出电话和呼入电话后恢​​复我们的音频。

我们使用AVAudioPlayer 播放音频并收听AVAudioSessionInterruptionNotification。 Apple 会在中断时自动为您暂停 AVAudioPlayer,当您在收到中断结束后告诉它恢复时,Apple 会再次将您的会话设置为活动状态。如果您使用其他类型的音频技术,请参阅Handling Audio Interruptions 的表 3-2 中的建议。

订阅通知:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];

处理通知:

- (void) onAudioSessionEvent: (NSNotification *) notification
{
    //Check the type of notification, especially if you are sending multiple AVAudioSession events here
    if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
        NSLog(@"Interruption notification received!");

        //Check to see if it was a Begin interruption
        if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
            NSLog(@"Interruption began!");

        } else {
            NSLog(@"Interruption ended!");
            //Resume your audio
        }
    }
}

【讨论】:

  • 应用在前台播放音频时有效。如果应用程序是后台它不是恢复。但是如果我来到前台然后工作。 @Michale Myers 你能给点建议吗?
  • 我的应用程序在后台运行良好。但是如何在屏幕锁定后检查我的应用程序是否仍在运行?因为当我的应用程序在后台运行时我的设备没有被锁定...
  • 这是我面临的问题stackoverflow.com/questions/22400345/…请给建议
  • 使用 SoloAmbient,即使在我正确注册后,我也不会再收到此通知。使用 PlayAndRecord,我只收到进入通知,但没有收到退出通知。这个机制对我来说完全被打破了。顺便说一句,我使用的是 AVAudioSession,但底层技术是 AU。但我认为半年前这行得通。它一定是在 iOS 8.1.x 的某个地方被破坏了。
【解决方案2】:

根据我的经验,我发现我必须“等待一两秒”才能尝试重新打开音频设备。我认为操作系统从通话切换回您的应用后,手机应用仍在关闭。

当您在知道您的音频会话已停止后返回前台时会出现这样的情况:

            dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW, 
                                                      1.5LL * NSEC_PER_SEC);

            dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{ 
                [audioSystem restart]; 
            });

【讨论】:

  • 这仅在应用程序处于后台且后台音频服务启动时发生。如果在应用程序运行和播放音频时收到呼叫,它会在呼叫后恢复播放。
  • 啊,我明白了。坏消息,应用程序在后台无法重新打开音频设备,用户必须手动将应用程序置于前台才能重新打开音频设备!
  • 我就是这么想的。我小跛脚,音乐应用通话后成功恢复播放。
【解决方案3】:

我正在使用 Xamarin,所以这是 C#,但以下代码对我有用。我首先设置我的 AppDelegate 通过包含 IAVAudioSessionDelegate 来实现 AVAudioSession 委托方法

public partial class AppDelegate: UIApplicationDelegate, IAVAudioSessionDelegate

我为音频会话的 AppDelegate 类添加了一个变量

public static AVAudioSession AudioSession;

在 FinishedLaunching 方法的覆盖中:

AudioSession = AVAudioSession.SharedInstance();
AudioSession.Delegate = this;
error = AudioSession.SetCategory( AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers );
AudioSession.SetMode( new NSString( "AVAudioSessionModeMoviePlayback" ), out error );

AppDelegate.cs 中两个相关的委托方法是:

[Export( "beginInterruption" )]
public void BeginInterruption()
{
        PlayerViewController.BeginSessionInterruption();
}
[Export( "endInterruptionWithFlags:" )]
public void EndInterruption( AVAudioSessionInterruptionFlags flags )
{  // ignore the flags so we're not dependent on the interrupting event saying that we can resume

 PlayerViewController.ResumeAfterSessionInterruption();
 }

我的 AppDelegate 还具有对 OnActivated 的覆盖以启用视频轨道(如果它是视频资产),以及对 DidEnterBackground 的覆盖以禁用媒体的视频轨道但仍播放音频。

在 PlayerViewController.BeginSessionInterruption() 方法中,我无法查看 Player.Rate 来查看播放器当时是否正在运行,因为中断的警报或电话已经暂停播放器。来自 Apple 音频会话编程指南的“响应中断”部分,我的重点是:

  1. 您的应用处于活动状态,正在播放音频。
  2. 来了一个电话。系统会激活手机应用的音频会话。
  3. 系统会停用您的音频会话。此时,* 在您的应用中播放已停止 *
  4. 系统调用您的中断监听回调函数,表明您的会话已被停用。 ...

我的 PlayerViewController 的播放按钮有一个 Paused 属性,用于在播放和暂停之间切换并绘制适当的按钮图像。因此,我没有检查 Player.Rate,而是查看按钮的 Paused 属性是否为 false:

 public void BeginSessionInterruption()
        {
 PlayerWasRunningOnInterruption = !btnPlay.Paused;
 TogglePlayPause( true );  // put the Play button into the Paused state to agree with the player being stopped
public void ResumeAfterSessionInterruption()
        {
        NSError error;
AppDelegate.AudioSession.SetActive( true, AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation, out error );  // always reactivate the audio session
    if ( PlayerWasRunningOnInterruption )
                {
// rewind a little bit
// call btnPlayClick to resume the playback as if the user pressed the Play button
            }
    }

【讨论】:

    【解决方案4】:

    看看:

    https://developer.apple.com/documentation/avfoundation/avaudiosession#//apple_ref/doc/uid/TP40008240-CH1-DontLinkElementID_3

    https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_interruptions

    代码:

    private func setupAudioSession() {
        do {
    
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
            try AVAudioSession.sharedInstance().setActive(true)
    
            setupAudioNotifications()
    
        } catch {
            print(error)
        }
    }
    
    private func setupAudioNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: .AVAudioSessionInterruption, object: nil)
    }
    
    @objc func handleInterruption(notification: Notification) {
    
        guard let userInfo = notification.userInfo,
            let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
            let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
                return
        }
    
        if type == .began {
            // Interruption began, take appropriate actions
            Player.shared.stop()
    
        } else if type == .ended {
            if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
                let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
                if options.contains(.shouldResume) {
                    // Interruption Ended - playback should resume
                    Player.shared.start()
                } else {
                    // Interruption Ended - playback should NOT resume
                }
            }
        }
    }
    

    【讨论】:

    • 你能帮我解决一下“中断结束 - 播放不应该恢复”吗?
    • 很好的例子。请注意:当应用程序当前未播放任何音频时,不会调用此处理程序。一个负责重新启动所需的所有音频。
    【解决方案5】:

    如果只检测通话状态可以使用CTCallCenter,但是如果要检测中断(包括通话中断)可以使用AVAudioSessionInterruptionNotification,如果要支持后台需要添加代码像这样:

      [[AVAudioSession sharedInstance] setActive:YES error:nil];
      [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    

    在您继续在后台播放音乐之前。希望这会有所帮助。

    【讨论】:

      【解决方案6】:

      只有两个选项适合我:

      1. 中断结束后重新加载AVPlayerAVAudioPlayer

        func interruptionNotification(_ notification: Notification) {
        guard let type = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt,
          let interruption = AVAudioSessionInterruptionType(rawValue: type) else {
            return
        }
        if interruption == .ended && playerWasPlayingBeforeInterruption {
          player.replaceCurrentItem(with: AVPlayerItem(url: radioStation.url))
          play()
        }
        

        }

      2. 使用

      AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)

      【讨论】:

      • 什么时候调用interruptNotification()?
      • 您需要使用interruptionNotification 函数将AVAudioSessionInterruptionNotification 的监听器添加到NotificationCenter
      猜你喜欢
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多