【问题标题】:AudioSessionSetActive fails after interruptionAudioSessionSetActive 中断后失败
【发布时间】:2011-10-27 21:06:03
【问题描述】:

我试图弄清楚几周以来实际发生了什么,但我不知道为什么在中断后我无法继续播放,所以你们可能知道答案。如果我的应用在后台播放并且我在不同的应用中,则在重新激活时,AudioSessionSetActive(TRUE) 始终返回“!cat”,即 kAudioSessionIncompatibleCategory。虽然如果我在我的应用程序中遇到中断,它可以正常工作并继续播放。

原始代码实际上将所有 AudioSession 和 AudioQueue 调用包装在宏中,如果这意味着错误,则打印 OSStatus,但我将其删除以提高可读性。另外,[self pause] 只是切换暂停,所以基本上它在 upause 时调用 AudioQueueStart(audioQueue, NULL) 但如果 AudioSession 失败,它当然不起作用。

Audio Session 初始化代码:

AudioSessionInitialize(NULL, NULL, _audioSessionInterruptionListener, self);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, _audioSessionPropertyListener, self);
AudioSessionSetActive(TRUE);

中断处理程序代码:

- (void)handleInterruptionChangeToState:(AudioQueuePropertyID)inInterruptionState 
{
    if(inInterruptionState == kAudioSessionBeginInterruption)
    {

        NSLog(@"+Interruption"); 

        if(self.state == NX_STATE_PLAY) 
        {
            [self pause];
            AudioSessionSetActive(FALSE);

            isPausedByInterruption = YES;
        }
    }
    else if(inInterruptionState == kAudioSessionEndInterruption) 
    {
        if(isPausedByInterruption) 
        {
            AudioSessionSetActive(TRUE);
            [self pause];

            isPausedByInterruption = FALSE;
        }

        NSLog(@"-Interruption");
    }
}

这个流媒体源代码可以在这里找到https://bitbucket.org/and/amaudiostreamer/src/122de41fe6c0/AMAudioStreamer/AMAudioStreamer/Classes/NxAudioStreamer.m,如果它有助于以某种方式解决问题..

【问题讨论】:

    标签: iphone objective-c audioqueue interruption


    【解决方案1】:

    如果您使用的是 AudioQueue API,您需要根据某些因素执行一些额外的步骤。我从来没有这样做过,所以我将把解释留给专家:
    Apple Developer 网站上有一个关于该主题的视频,涵盖了该确切问题。 WWDC 2010 会议 412 iPhone OS 的音频开发第 1 部分在第 45 分钟左右你已经对这个问题有了很好的解释。

    【讨论】:

    • 我还是不明白为什么 AudioSessionSetActive(true);返回!cat,可能它返回什么都没有关系,我所要做的就是继续播放。所以基本上我必须在使用硬件编解码器时处理和重新创建 AudioQueue。这很重要,谢谢您的回复。
    • 那个视频里有很多,如果我没记错的话有一个关于 AudioSession 类别的部分,也许你会在那里找到一些东西。
    【解决方案2】:

    我遇到了一个问题,当应用程序运行期间警报响起时,用户只需按下设备电源按钮使其进入睡眠状态。然后,在从睡眠中恢复后,我的AudioSessionSetActive 失败,出现类似“this audiosession type can't be used”的内容。我试图在 Interruptionlistener 中的 AudioSessionSetActive(true) 之前添加 set audiosession 属性,但没有运气。 最后我添加了

    retry(~1000 times :) 
    

    ftw)

    AudioSessionSetActive(true), 
    

    它解决了我的问题。

    【讨论】:

    • 我想我当时并没有完全让它工作,这是非常随机的行为。后来我切换到似乎工作的 AVFoundation 和 AVSession 。老实说,我认为 Apple 在他们的 SDK 中存在错误,我猜这段代码可以在 iOS 6 上正常运行,但这只是假设。
    【解决方案3】:

    尝试在 else if 条件下激活 AudioSession,如下所示:

    AVAudioSession *session = [AVAudioSession sharedInstance];
    NSError *error = nil;
    
    [session setCategory: AVAudioSessionCategoryPlayback error: &error];
    if (error != nil)
        NSLog(@"Failed to set category on AVAudioSession");
    
    // AudioSession and AVAudioSession calls can be used interchangeably
    OSStatus result = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, RouteChangeListener, self);
    if (result) NSLog(@"Could not add property listener! %d\n", result);
    
    BOOL active = [session setActive: YES error: nil];
    if (!active)
        NSLog(@"Failed to set category on AVAudioSession");
    

    但我相信这可能行不通,因为在我的情况下,发生的事情是当我在后台时,它没有得到任何会话。但是尝试分析Apple的aurioTouch example,只通过AppDelegate文件并尝试分析(void)rioInterruptionListener方法,它解释了同样的问题。

    您是否使用实时流式传输音频??那么我建议您通过我的question's answer,通过处理我的答案中给出的错误来解决队列启动问题。

    希望这对您有帮助。

    【讨论】:

    • 如您所料,它不起作用,并以更时尚的方式给我同样的错误:“无法在 AVAudioSession 上设置类别。操作无法完成。(OSStatus 错误 560161140。) ”。我会尝试分析 rioInterruptionListener.. 我想我只是漏掉了一些小东西。
    • 那么我相信首先您必须尝试我的问题答案中的内容。但是这里将很难得到确切的问题。您需要确定要修改代码的exactly 位置。当我完成时,这对我来说是一个挑战......祝你好运......希望你能够解决这个问题......
    【解决方案4】:

    kAudioSessionEndInterruption 可能会也可能不会影响您的代码,这不是控制播放状态的可靠方法,只是不要在您的代码中关闭音频会话,一旦它可以再次获得控制权,它将恢复会话,在您的情况,只需将 AudioSessionSetActive(FALSE) 注释掉即可。

    【讨论】:

    • 我明白你的意思,但这并不能帮助我恢复音频会话并继续播放:(
    【解决方案5】:

    如果您查看Audio Session Programming Guide cookbook section 中的Listing 7-16 An interruption listener callback function,代码示例(似乎与您的情况兼容,使用 kAudioSessionCategory_MediaPlayback)实际上并没有执行

    AudioSessionSetActive(FALSE);
    

    kAudioSessionBeginInterruption的情况下调用,

    AudioSessionSetActive(TRUE);
    

    kAudioSessionEndInterruption 的情况下调用。我真的不认为你应该这样做。 This post 似乎也说明了这个问题(得到一个 kAudioSessionIncompatibleCategory)。如果您注释掉这两个调用会发生什么?

    当您的应用程序在后台而不是前台时出现问题的原因是一个谜。您也许应该跟踪状态(就像您似乎正在使用 NX_STATE_PLAY 所做的那样),然后有两种不同的方法([self pause] 和 [self play]),因为 [self pause](切换播放状态)可能被称为意外的次数。

    【讨论】:

    • [self pause] 只调用了两次,所以基本上 AudioQueuePause 在中断开始时,AudioQueueStart 在中断结束时,我检查了一下,没有问题。我从我的代码中删除了 AudioSessionSetActive(FALSE),但我的日志中仍然有这些东西: VERIFY_OSS AudioSessionSetActive(true) - '!cat' VERIFY_OSS AudioQueueStart(audioQueue, NULL) - -12985
    【解决方案6】:

    我知道了一些对我有用的方法,你可以试试你的风险。

    在函数中

    void _audioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)
    

    删除

    [(NxAudioStreamer*)inClientData handleInterruptionChangeToState:inInterruptionState];
    

    audioSessionInterruptionListener中直接处理就不需要调用handleInterruptionChangeToState,因为audioSessionInterruptionListenerinInterruptionState作为参数。所以修改你的audioSessionInterruptionListener

    void _audioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)
    {
        if(inInterruptionState == kAudioSessionBeginInterruption)
        {
    
            NSLog(@"+Interruption"); 
    
            if(self.state == NX_STATE_PLAY) 
            {
                [self pause];
                AudioSessionSetActive(FALSE);
    
                isPausedByInterruption = YES;
            }
        }
        else if(inInterruptionState == kAudioSessionEndInterruption) 
        {
            if(isPausedByInterruption) 
            {
                AudioSessionSetActive(TRUE);
                [self pause];
    
                isPausedByInterruption = FALSE;
            }
    
            NSLog(@"-Interruption");
        }
    }
    

    【讨论】:

    • 我想我放弃了这个并使用了 AVFoundation,因为 iOS 3 对我来说不再重要了。无论如何感谢您的回答。
    猜你喜欢
    • 2013-07-09
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多