通话后,后台音频不会恢复

时间:2012-02-28 05:06:16

标签: ios audio background

我的背景音频几乎一直都很好用。屏幕锁定或静音开启。但是当用户在后台运行应用程序并且它接收到呼叫时,即使用户没有应答呼叫,在中断结束后也不会恢复背景音频。

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

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

6 个答案:

答案 0 :(得分:22)

当应用程序在后台时,我们正在外拨电话和入站呼叫后恢复音频。

我们使用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
        }
    }
}

答案 1 :(得分:5)

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

知道音频会话停止后返回前台时会发生类似这样的事情:

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

答案 2 :(得分:2)

我正在使用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. 系统调用您的中断侦听器回调函数,指示您的会话已停用。 ...
  5. 我的PlayerViewController的“播放”按钮具有“暂停”属性,可在“播放”和“暂停”之间切换,并绘制相应的按钮图像。因此,我不是检查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
                    }
                }
    

答案 3 :(得分:0)

如果您只检测到呼叫状态,则可以使用CTCallCenter,但如果您想检测中断(包括呼叫中断),则可以使用AVAudioSessionInterruptionNotification,如果您想支持后台你应该添加这样的代码:

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

在你继续在background.hope中播放音乐之前,这可以提供帮助。

答案 4 :(得分:0)

只有两个选项对我有用:

  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. 使用

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

答案 5 :(得分:0)

看看:

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