AVplayer возобновляется после входящего звонка
Я использую AVPlayer
для воспроизведения музыки. Моя проблема в том, что после входящего звонка плеер не возобновит работу. Как мне справиться с этим, когда приходит входящий звонок?
4 ответа
Начиная с 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
}
С уважением.
AVAudioSession отправит уведомление, когда прерывание начинается и заканчивается. См. Обработка аудио прерываний
- (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;
}
}
Привет всем, кто это читал. Хочу поделиться своим опытом с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
}
}
}
Надеюсь, это поможет кому-то сэкономить много времени.
В некоторых случаях мой AVPlayer
не возобновлять игру, даже если я позвоню play()
, Только перезагрузка плеера помогает мне решить проблему:
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()
}
}
У меня была такая же проблема в контроллере "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, когда он прерван, и Active AVAudioSession, когда прерывание закончилось. Он работает отлично, попробуйте!
Мне нужно подождать 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()
}
}
}
}