音楽の再生にAVPlayer
を使用しています。私の問題は、電話がかかってきた後、プレーヤーが再開しないことです。着信があったときにこれをどのように処理しますか?
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が呼び出す通知のために、2つのメソッドを実装する必要があります。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:aSession];
1つ目は、着信や目覚まし時計などが原因で呼び出される割り込みです。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleMediaServicesReset)
name:AVAudioSessionMediaServicesWereResetNotification
object:aSession];
2つ目は、何らかの理由でメディアサーバーがリセットされた場合、この通知を処理してオーディオを再構成するか、ハウスキーピングを実行する必要があります。ちなみに、通知ディクショナリにはオブジェクトが含まれていません。
再生の中断を処理する例を次に示します。
- (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;
}
}
それが機能するように私は2秒待つ必要があります。
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.player.play()
}
Func全体:
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()
}
}
}
}
「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を実行する必要があります。ちゃんと動いているので試してみてください!
場合によっては、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()
}
}