来电后AVplayer恢复
Posted
技术标签:
【中文标题】来电后AVplayer恢复【英文标题】:AVplayer resuming after incoming call 【发布时间】:2013-12-23 04:03:06 【问题描述】:我正在使用AVPlayer
播放音乐。我的问题是来电后,播放器不会恢复。来电时如何处理?
【问题讨论】:
【参考方案1】:从 ios 6 开始,您必须处理 AVAudioSessionInterruptionNotification
和 AVAudioSessionMediaServicesWereResetNotification
,在此之前您必须使用委托方法。
首先,您应该调用 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 不应该从 LIVE Streaming 的最后一点恢复