我正在使用OpenAL播放游戏声音,并使用标准AV播放音乐。最近我发现之后 当bg音乐仍在播放时,来电所有开放的声音都不起作用。如果我强制停止应用程序并重新开始 声音再次出现。 smbd碰巧知道在来电期间/之后发生了什么事情?
答案 0 :(得分:1)
好的,我似乎找到了解决方案。 我正在使用obj-c声音管理器,所以我只是将AVAudioSession(和AVAudioPlayer)的beginInterruption和endInterruption委托方法添加到我的班级。
beginInterruption看起来像:
alcMakeContextCurrent(NULL);
和endInterruption看起来像:
NSError * audioSessionError = NULL;
[audioSession setCategory:soundCategory error:&audioSessionError];
if (audioSessionError)
{
Log(@"ERROR - SoundManager: Unable to set the audio session category");
return;
}
// Set the audio session state to true and report any errors
audioSessionError = NULL;
[audioSession setActive:YES error:&audioSessionError];
if (audioSessionError)
{
Log(@"ERROR - SoundManager: Unable to set the audio session state to YES with error %d.", (int) result);
return;
}
//music players handling
bool plays = false;
if (musicPlayer[currentPlayer] != nil)
plays = [musicPlayer[currentPlayer] isPlaying];
if (musicPlayer[currentPlayer] != nil && !plays)
[musicPlayer[currentPlayer] play];
alcMakeContextCurrent(context);
是的,如果您只使用openAL声音,则此功能正常。但要播放长曲目,你应该使用AVAudioPlayer。 但这里再次是苹果魔术!如果您与OpenAL一起播放音乐,则会发生奇怪的事情。 取消传入呼叫,AVAudioPlayerDelegate :: audioPlayerEndInterruption将永远不会调用AVAudioSessionDelegate :: endInterruption。只有beginInterruption,而不是结束。 即使AppDelegate :: applicationWillEnterForeground也不会被调用,app也不知道我们已经返回。
但好消息是你可以在 AppDelegate :: applicationDidBecomeActive 方法中调用endInterruption,并恢复openAL上下文。这很有效!
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if (MySoundMngr != nil)
{
[MySoundMngr endInterruption];
}
// Restart any tasks that were paused and so on....
}
答案 1 :(得分:0)
我很难弄清楚这一点,所以想在这里添加我的答案。这都是专门在 Xamarin 中的,但我怀疑它普遍适用并且类似于@Tertium 的回答
您可以使用 AVAudioSession.SharedInstance().SetPrefersNoInterruptionsFromSystemAlerts(true, out NSError err);
您在某些情况下仍会被打扰(例如,您接听电话)。要捕获这些内容,您必须在启动应用程序时AVAudioSession.Notifications.ObserveInteruption(myAudioInterruptionHandler);
。
在此处理程序中,您可以确定是关闭还是像这样返回:
void myAudioInterruptionHandler(object sender, AVAudioSessionInterruptionEventArgs args) {
args.Notification.UserInfo.TryGetValue(
new NSString("AVAudioSessionInterruptionTypeKey"),
out NSObject typeKey
);
bool isBeginningInterruption = (typeKey.ToString() == "1");
// ...
}
当中断开始时,停止正在播放的任何音频(您需要根据您的应用自行处理此问题,但可能通过对所有内容调用 AL.SourceStop
)。
然后,批判性地,
ContextHandle audioContextHandle = Alc.GetCurrentContext();
Alc.MakeContextCurrent(ContextHandle.Zero);
如果您不立即执行此操作,iOS 会破坏您的 ALC 上下文,而您注定要失败。请注意,如果您有 AudioRouteChanged
的处理程序,这也是迟到,您必须在 AudioInterruption
处理程序中执行此操作。
当您从中断中恢复过来时,首先重新启动您的 iOS 音频会话:
AVAudioSession.SharedInstance().SetActive(true);
您可能还需要重置您的首选输入(如果您始终使用默认输入,我认为此步骤是可选的)AVAudioSession.SharedInstance().SetPreferredInput(Input, out NSError err)
然后恢复你的上下文
Alc.MakeContextCurrent(audioContextHandle);