打开 al 声音在来电后不播放,直到应用重新启动

Posted

技术标签:

【中文标题】打开 al 声音在来电后不播放,直到应用重新启动【英文标题】:open al sounds don't play after the incoming call, until app restart 【发布时间】:2012-12-02 12:51:30 【问题描述】:

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

【问题讨论】:

刚刚找到:developer.apple.com/library/ios/documentation/Audio/Conceptual/…。应该阅读以了解问题所在 【参考方案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 的声音,就会发生一些奇怪的事情。 取消来电和 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....

【讨论】:

我在 iOS 10 上仍然遇到这种问题。我认为 interruption 是为 AVAudios 设计的。你的意思是OpenAL的东西也需要中断吗? 为了避免所有令人头疼的问题,我已经停止写目标 c 并开始使用 xamarin 和 c#(VS2015+Xamarin 现在是免费的)。由于有缺陷的 xcode 和丑陋的语言,在开发过程中遭受了痛苦,然后应用程序甚至无法工作 - 不,这对我来说太过分了,现在人们有了另一种选择。至少我很高兴地发展:) Alc.MakeContextCurrent(ContextHandle.Zero); on interrupt 是这里的关键。【参考方案2】:

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

您可以使用 AVAudioSession.SharedInstance().SetPrefersNoInterruptionsFromSystemAlerts(true, out NSError err); 防止 iOS 在某些情况下中断您的音频(例如,接听电话但拒绝接听)

在某些情况下您仍会被打断(例如,您接听电话)。要捕获这些,您必须在启动应用时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);

【讨论】:

以上是关于打开 al 声音在来电后不播放,直到应用重新启动的主要内容,如果未能解决你的问题,请参考以下文章

电脑放不了音频怎么办?

电话录音服务仅记录来电者的声音。 (安卓)

托管在 Azure 上的点网 mvc 应用程序突然一次又一次地重定向到登录页面,直到重新启动

MPMoviePlayerController 停止 iPod 播放并且不重新启动

如何在点击时播放声音?

iPhone播放声音时如何操作?