4

我正在使用 OpenAL 播放游戏声音,并使用标准 AV 播放背景音乐。最近我发现,在来电后,所有的 openal 声音都不起作用,而 bg 音乐仍在播放。如果我强制停止应用程序并重新启动,声音会再次出现。smbd 是否碰巧知道在来电期间/之后 openal 发生了什么?

4

2 回答 2

2

好的,看来我找到了解决方案。我正在使用 obj-c 声音管理器,所以我只是将 AVAudioSession(和 AVAudioPlayer)的 beginInterruption 和 endInterruption 委托方法添加到我的类中。

开始中断看起来像:

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 的声音,就会发生一些奇怪的事情。取消来电和 AVAudioSessionDelegate::endInterruption 与 AVAudioPlayerDelegate::audioPlayerEndInterruption 永远不会调用。只有开始中断,没有结束。甚至 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....
}
于 2012-12-03T17:41:07.523 回答
0

我很难弄清楚这一点,所以想在这里添加我的答案。这在 Xamarin 中都是专门的,但我怀疑它普遍适用并且类似于@Tertium 的答案

  • 您可以防止 iOS 在某些情况下中断您的音频(例如,接听电话但拒绝接听),使用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);

于 2021-05-19T20:44:33.203 回答