检测 AVAudioSession 何时被“躲避”
Posted
技术标签:
【中文标题】检测 AVAudioSession 何时被“躲避”【英文标题】:Detect when AVAudioSession is being "Ducked" 【发布时间】:2013-08-06 14:45:23 【问题描述】:我正在开发一个 Podcast 应用程序。这使用AVAudiosessionCategoryPlayback
会话类型播放音频。这几乎可以完成我想要它做的所有事情。它会暂停其他播放音乐,当有来电时它会被打断,并且通常完全按照我的意愿工作。
有一个例外。当播放更高优先级的音频时(例如,运行逐向导航应用程序时),我的应用程序中的音频音量会降低,但会继续运行。这造成了两种不想要的声音的可怕混合。相反,我希望我的应用程序中的音频在过度播放的声音期间暂停,然后在完成后再次继续。
我已尝试更改不同的 AVAudioSession 属性,例如 AVAudioSessionCategoryOptionMixWithOthers
,但这些只会更改较低优先级的声音与我的应用程序混合的方式。它们不会改变我的声音与更高优先级声音的混合方式。我还尝试观察 sharedSession
的 otherAudioPlaying
属性,但是当我覆盖这些短片时,这并没有触发更改。
有什么方法可以检测到我的应用程序中的音频何时被闪避,以便我可以暂停它?或者是为了防止我的应用程序的音频被闪避,以便它将这些其他声音视为中断?
谢谢。
【问题讨论】:
你试过使用kAudioSessionBeginInterruption
和kAudioSessionEndInterruption
吗?
是的,但就 AVAudioSession 而言,覆盖闪避不算作“中断”。所以这些回调/通知不会被触发。
如果您认为应该这样做,您可能需要向 Apple 提交一份雷达报告。在我看来,应该将其视为音频会话中断似乎是合乎逻辑的。
你找到解决这个问题的方法了吗?我也有同样的问题……如果有,请告诉我。
问题可能是一旦您收到闪避通知并停止声音,您的应用程序就会停止并且您无法观察到未闪避通知。该系统需要对此的明确支持,并且由于它们似乎没有,我认为目前没有办法做到这一点。我发起了一个支持事件来获得 Apple 的答复。
【参考方案1】:
此功能是在 iOS 9 中添加的,可以通过将音频会话模式设置为 AVAudioSessionModeSpokenAudio 来启用。其他会说话的应用(例如导航应用)会打断您的音频而不是闪避。
见:https://developer.apple.com/documentation/avfoundation/avaudiosessionmodespokenaudio
【讨论】:
是的,这是正确答案,应该明确表示赞成!【参考方案2】:我就这个问题写信给 Apple DTS。这是我得到的结果:
感谢您联系 Apple 开发者技术支持 (DTS)。我们的 工程师审查了您的请求并得出结论认为存在 鉴于没有支持的方式来实现所需的功能 目前正在发布系统配置。
如果您希望 Apple 考虑在未来增加支持 允许/通知后台应用程序在 前台应用程序选择避开其他音频,然后启用后台 应用程序在闪避完成后重新开始音频,请提交 通过 Bug Reporter 工具的增强请求 http://bugreport.apple.com.
不幸的是,现在看来不可能。
【讨论】:
【参考方案3】:我从来没有这样做过,但我想你可以使用 AudioSession 服务 C 函数 audioSessionAddPropertyListener 来为 kAudioSessionProperty_OtherAudioIsPlaying 注册你的回调。
请注意,“FLATDACTED”文档和 Apple DevForums 中存在一些混淆,即“将来”可能会弃用所有或部分 AudioSession C 函数。
【讨论】:
感谢您的建议,感谢您的帮助。但是,我已经尝试过使用 Obj-C 和 C API。在闪避期间被触发时,两者都没有产生所需的回调结果。【参考方案4】:您可能想要查看中断,并在中断时简单地丢弃您的音频会话,然后在中断结束时恢复它,如下所示:
在您的 ViewDidLoad 中:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
if ([self canBecomeFirstResponder])
[self becomeFirstResponder];
处理通知:
static NSInteger audioSessionActiveCounter = 0;
- (void)audioSessionDidChangeInterruptionType:(NSNotification *)notification
AVAudioSessionInterruptionType interruptionType = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (AVAudioSessionInterruptionTypeBegan == interruptionType)
DDLogVerbose(@"Session interrupted: --- Begin Interruption ---");
// stop your session here with a setActive:NO
else if (AVAudioSessionInterruptionTypeEnded == interruptionType)
DDLogVerbose(@"Session interrupted: --- End Interruption ---");
// resume your session here with a setActive:YES
希望对你有帮助。
【讨论】:
【参考方案5】:我不认为 kAudioSessionProperty_OtherAudioIsPlaying 应该以任何方式回调 - 可能是您必须定期轮询此值。
当设备上播放其他音频时,它应该返回一个非零值。这可能并不表明您本身被“躲避”,但它表明其他音频正在与您的音频混合。假设只有当其他应用设置了其音频会话的 kAudioSessionProperty_OtherMixableAudioShouldDuck 属性时,您才会被躲避。
关于轮询 - 是的,它可能不如回调那么优雅,但有时它是必要的,我怀疑轮询这个值是一个小问题。
希望这会有所帮助。
【讨论】:
【参考方案6】:在你AppDelegate.m
类和didFinishLaunchingWithOptions
函数中,听下面的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
在应用启动方法之外,将选择器实现为
- (void)audioSessionInterruption:(NSNotification *)notif
NSLog(@"\n\nInterruption Notification :%@\n\n",notif.userInfo);
希望这对你有用....
【讨论】:
以上是关于检测 AVAudioSession 何时被“躲避”的主要内容,如果未能解决你的问题,请参考以下文章