来电后AVplayer恢复

Posted

技术标签:

【中文标题】来电后AVplayer恢复【英文标题】:AVplayer resuming after incoming call 【发布时间】:2013-12-23 04:03:06 【问题描述】:

我正在使用AVPlayer 播放音乐。我的问题是来电后,播放器不会恢复。来电时如何处理?

【问题讨论】:

【参考方案1】:

ios 6 开始,您必须处理 AVAudioSessionInterruptionNotificationAVAudioSessionMediaServicesWereResetNotification,在此之前您必须使用委托方法。

首先,您应该调用 AVAudioSession 单例并将其配置为您想要的用途。

例如:

AVAudioSession *aSession = [AVAudioSession sharedInstance];
[aSession setCategory:AVAudioSessionCategoryPlayback
          withOptions:AVAudioSessionCategoryOptionAllowBluetooth 
                error:&error];
[aSession setMode:AVAudioSessionModeDefault error:&error];
[aSession setActive: YES error: &error];

那么你应该实现两个方法,用于 AVAudioSession 将调用的通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleAudioSessionInterruption:)
                                             name:AVAudioSessionInterruptionNotification
                                           object:aSession];

第一个用于任何因来电、闹钟等而被调用的中断。

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleMediaServicesReset)
                                             name:AVAudioSessionMediaServicesWereResetNotification
                                           object:aSession];

第二个如果媒体服务器因任何原因重置,您应该处理此通知以重新配置音频或进行任何内务处理。顺便说一句,通知字典不会包含任何对象。

这里是一个处理播放中断的例子:

- (void)handleAudioSessionInterruption:(NSNotification*)notification 

    NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey];
    NSNumber *interruptionOption = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];

    switch (interruptionType.unsignedIntegerValue) 
        case AVAudioSessionInterruptionTypeBegan:
            // • Audio has stopped, already inactive
            // • Change state of UI, etc., to reflect non-playing state
         break;
        case AVAudioSessionInterruptionTypeEnded:
            // • Make session active
            // • Update user interface
            // • AVAudioSessionInterruptionOptionShouldResume option
            if (interruptionOption.unsignedIntegerValue == AVAudioSessionInterruptionOptionShouldResume) 
                // Here you should continue playback.
                [player play];
            
         break;
        default:
            break;
    

请注意,当可选值为AVAudioSessionInterruptionOptionShouldResume时,您应该恢复播放

对于其他通知,您应该注意以下事项:

- (void)handleMediaServicesReset 
// • No userInfo dictionary for this notification
// • Audio streaming objects are invalidated (zombies)
// • Handle this notification by fully reconfiguring audio

问候。

【讨论】:

在处理 MediaServicesWereReset 时,在文档中说“采取适当的步骤重新初始化您的应用程序使用的任何音频对象”。它只是重新配置 AudioSession 并将其设置回 Active。还有什么我应该做的吗? 太棒了!它真的对我有用!感谢这篇文章节省了我的时间【参考方案2】:

AVAudioSession 将在中断开始和结束时发送通知。见Handling Audio Interruptions

- (id)init

    if (self = [super init]) 
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(audioSessionInterrupted:) name:AVAudioSessionInterruptionNotification object:nil];
    


- (void)audioSessionInterrupted:(NSNotification *)notification

    int interruptionType = [notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue];
    if (interruptionType == AVAudioSessionInterruptionTypeBegan) 
        if (_state == GBPlayerStateBuffering || _state == GBPlayerStatePlaying) 
            NSLog(@"Pausing for audio session interruption");
            pausedForAudioSessionInterruption = YES;
            [self pause];
        
     else if (interruptionType == AVAudioSessionInterruptionTypeEnded) 
        if ([notification.userInfo[AVAudioSessionInterruptionOptionKey] intValue] == AVAudioSessionInterruptionOptionShouldResume) 
            if (pausedForAudioSessionInterruption) 
                NSLog(@"Resuming after audio session interruption");
                [self play];
            
        
        pausedForAudioSessionInterruption = NO;
    

【讨论】:

我们可以使用CTCallCenter吗 我不建议CTCallCenter,因为AVAudioSession提供了更详细的接口。我更新了我的答案以删除不推荐使用的方法。【参考方案3】:

在某些情况下,即使我致电 play(),我的 AVPlayer 也不会继续播放。只有重新加载播放器才能帮助我解决问题:

    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()
    
  

【讨论】:

【参考方案4】:

大家好,阅读本文的人。想和AVAudioSessionInterruptionNotification分享我的经验。它把我逼疯了。我花了一天时间寻找解决方案。我尝试了上面写的所有内容,但没有任何帮助。 iOS 13.2.3。因此,由于某种原因,此通知不适用于AVAudioSessionCategoryPlayback。对我来说,解决方法就是用AVAudioSessionCategoryPlayAndRecord 替换它,然后我开始收到AVAudioSessionInterruptionTypeEnded 见下面的例子:

-(void)setupAudioSession 

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    [[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:nil];
    [[AVAudioSession sharedInstance] setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];    

然后注册你的观察者,像这样:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionHandleIntrruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

并实际实现中断方法:

- (void)audioSessionHandleIntrruption:(NSNotification *)notification 

    NSDictionary *userInfo = notification.userInfo;
    int interruptionType = [userInfo[AVAudioSessionInterruptionTypeKey] intValue];

    if (interruptionType == AVAudioSessionInterruptionTypeBegan) 
        //Interruption begun

     else if (interruptionType == AVAudioSessionInterruptionTypeEnded) 
        int interruptionOption = [userInfo[AVAudioSessionInterruptionOptionKey] intValue];

        BOOL shouldResumePlayback = interruptionOption == AVAudioSessionInterruptionOptionShouldResume;

        if (shouldResumePlayback) 
            //Resume playback if needed
        
    

希望这可以为某人节省很多时间。

【讨论】:

【参考方案5】:

我必须等待 2 秒才能使其工作。

        DispatchQueue.main.asyncAfter(deadline: .now() + 2) 

            self.player.play()
        

整个功能:

func playerInterruption(notification: NSNotification) 

    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 (save state, update user interface)
        player.pause()
    
    else if type == .ended 

        guard let optionsValue =
            userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else 

                return
        
        let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
        if options.contains(.shouldResume) 
            // Interruption Ended - playback should resume

            DispatchQueue.main.asyncAfter(deadline: .now() + 2) 

                self.player.play()
            

        
    

【讨论】:

【参考方案6】:

我在“AVAudioPlayer”控制器中遇到了同样的问题。使用“AVAudioSession.interruptionNotification”,即使在后台播放音频,我们也可以在中断结束后恢复音频播放。

    @objc func interruptionNotification(notification: Notification) 
    guard let type = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt,
        let interruption = AVAudioSession.InterruptionType(rawValue: type) else 
            return
    

    if interruption == .began
        print("Pause audio....")
        self.player?.pause()
        do 
            try AVAudioSession.sharedInstance().setActive(false)
            print("AVAudioSession is inactive")
         catch let error as NSError 
            print(error.localizedDescription)
        
    

    if interruption == .ended
        print("Play audio....")
        do 
            try AVAudioSession.sharedInstance().setActive(true)
            print("AVAudioSession is Active again")
            self.player?.play()
         catch let error as NSError 
            print(error.localizedDescription)
        
    

这里首先你需要在中断时 InActive AVAudioSession 和在中断结束时激活 AVAudioSession。效果很好,请试一试!

【讨论】:

以上是关于来电后AVplayer恢复的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer 缓冲后未恢复

AVPlayer,长时间停顿后恢复 = 故障

我的 AVPlayer 不应该从 LIVE Streaming 的最后一点恢复

如何暂停/恢复 avplayer 预加载

为啥我在 AppDelegate 中的 AVPlayer 类引用返回 nil?

AVPlayer : 如何处理网络中断