AudioSessionSetActive не работает после прерывания

Я пытался понять, что на самом деле происходит в течение нескольких недель, и я понятия не имею, почему я не могу продолжить воспроизведение после прерывания, так что, вероятно, вы, ребята, знаете ответ. AudioSessionSetActive (TRUE) всегда возвращает '! Cat', который является kAudioSessionIncompatibleCategory при повторной активации, если мое приложение воспроизводится в фоновом режиме, а я нахожусь в другом приложении. Хотя он работает нормально и продолжает воспроизведение, если я обнаружил прерывание во время нахождения в моем приложении.

Исходный код фактически содержит все вызовы AudioSession и AudioQueue, заключенные в макросы, которые выводят OSStatus, если это означает ошибку, но я удалил его для лучшей читаемости. Кроме того, [self pause] просто переключает паузу, поэтому в основном он вызывает AudioQueueStart (audioQueue, NULL) при upause, но, конечно, не работает, если AudioSession не удается.

Код инициализации аудиосессии:

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, если это поможет каким-то образом решить проблему ..


person Ben Affleck    schedule 27.10.2011    source источник


Ответы (6)


Если вы используете AudioQueue API, вам необходимо выполнить некоторые дополнительные действия, которые зависят от некоторых факторов. Я никогда этого не делал, поэтому оставлю объяснение эксперту:
на веб-сайте Apple Developer есть видео по этой теме, в котором освещается именно эта проблема. WWDC 2010 session 412 Audio Development for iPhone OS part 1 Примерно на 45-й минуте у вас есть довольно хорошее объяснение по этому поводу.

person Vincent Bernier    schedule 04.11.2011
comment
Я до сих пор не могу понять, почему AudioSessionSetActive (true); возвращает! cat, вероятно, даже не имеет значения, что он возвращает, все, что мне нужно сделать, просто продолжить воспроизведение. Так что в основном мне нужно избавиться и воссоздать AudioQueue при использовании аппаратного кодека. Это очень важно, спасибо за ответ. - person Ben Affleck; 04.11.2011
comment
В том видео много чего, если я правильно помню, есть раздел по категории AudioSession, может быть, там вы что-нибудь найдете. - person Vincent Bernier; 04.11.2011

У меня была проблема: когда во время запуска приложения приходит сигнал тревоги, пользователь просто нажимает кнопку питания устройства, чтобы оно перешло в спящий режим. Затем, после выхода из спящего режима, мой AudioSessionSetActive не работает с чем-то вроде «this audiosession type can't be used». Я попытался добавить свойство set audiosession перед AudioSessionSetActive(true) в Interruptionlistener, но безуспешно. Наконец я добавил

retry(~1000 times :) 

ftw)

AudioSessionSetActive(true), 

и это решило мою проблему.

person NoAngel    schedule 13.12.2012
comment
Думаю, в те дни мне не удалось полностью заставить его работать, это было довольно случайное поведение. Позже я переключился на AVFoundation и AVSession, которые, похоже, работают. Честно говоря, я думаю, что у Apple были ошибки в их SDK, и я предполагаю, что этот код будет правильно работать на iOS 6, но это только предположение. - person Ben Affleck; 13.12.2012

Попробуйте активировать AudioSession в условии else if следующим образом:

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");

Но я считаю, что это может не сработать, потому что в моем случае то, что произошло, произошло, когда я был в фоновом режиме, у него не было сеанса. Но попробуйте проанализировать пример aurioTouch Apple. и просматривайте только AppDelegate файл и попробуйте проанализировать (void)rioInterruptionListener метод, который объясняет ту же проблему.

Вы используете потоковое аудио в реальном времени? тогда я бы порекомендовал вам пройти мой вопрос-ответ, где решена проблема запуска очереди обработав ошибку, как указано в моем ответе.

Надеюсь, что это может быть вам полезно.

person DShah    schedule 30.10.2011
comment
Как вы и ожидали, это не работает и дает мне ту же ошибку более модным способом: не удалось установить категорию в AVAudioSession. Операция не может быть завершена. (Ошибка OSStatus 560161140.). Попробую проанализировать rioInterruptionListener .. Думаю, просто пропустил какую-то мелочь. - person Ben Affleck; 04.11.2011
comment
Тогда я считаю, что сначала вы должны попробовать то, что указано в ответе на мой вопрос. Но здесь будет слишком сложно разобраться в точном вопросе. Вам необходимо определить, где exactly вы хотите изменить код. это было проблемой для меня, когда я сделал ... Удачи тебе ... Надеюсь, ты сможешь решить проблему ... - person DShah; 04.11.2011

kAudioSessionEndInterruption может или не может поразить ваш код, это ненадежный способ контролировать ваши состояния воспроизведения, просто не выключайте аудиосеанс в вашем коде, он возобновит сеанс, как только он снова сможет получить контроль, в вашем случае, просто закомментируйте, что AudioSessionSetActive (FALSE) вам поможет.

person Allen    schedule 01.11.2011
comment
Я понимаю вашу точку зрения, но это не помогает мне вернуть аудиосеанс и продолжить воспроизведение :( - person Ben Affleck; 04.11.2011

Если вы посмотрите на Listing 7-16 An interruption listener callback function в раздел кулинарной книги Руководства по программированию аудиосеансов, образец кода (который, кажется, совместим с вашей ситуацией, используя kAudioSessionCategory_MediaPlayback) фактически не выполняет

AudioSessionSetActive(FALSE);

вызов в случае kAudioSessionBeginInterruption, и

AudioSessionSetActive(TRUE);

вызов в случае kAudioSessionEndInterruption. Я действительно не думаю, что тебе следует это делать. Этот пост похоже, также иллюстрирует эту проблему (получение kAudioSessionIncompatibleCategory). Что будет, если закомментировать оба этих звонка?

Причина, по которой проблема возникает, когда ваше приложение работает в фоновом режиме, а не на переднем плане, остается загадкой. Возможно, вам следует отслеживать состояние (как вы, кажется, делаете с NX_STATE_PLAY), а затем использовать два разных метода ([самопауза] и [самовоспроизведение]), поскольку, возможно, [самопауза] (переключение состояния воспроизведения) называется неожиданное количество раз.

person jbat100    schedule 03.11.2011
comment
[self pause] вызывается только дважды, так что в основном AudioQueuePause при начале прерывания и AudioQueueStart при завершении прерывания, я проверил это, никаких проблем. Я удалил AudioSessionSetActive (FALSE) из своего кода, и я все еще получаю это в моем журнале: VERIFY_OSS AudioSessionSetActive (true) - '! Cat' VERIFY_OSS AudioQueueStart (audioQueue, NULL) - -12985 - person Ben Affleck; 04.11.2011

У меня кое-как работает, можете попробовать на свой страх и риск.

В функции

void _audioSessionInterruptionListener(void *inClientData, UInt32 inInterruptionState)

Удалить

[(NxAudioStreamer*)inClientData handleInterruptionChangeToState:inInterruptionState];

нет необходимости вызывать handleInterruptionChangeToState, если вы можете напрямую обрабатывать его в audioSessionInterruptionListener, потому что audioSessionInterruptionListener имеет inInterruptionState в качестве параметра. Так что измените свой на 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");
    }
}
person saadnib    schedule 04.11.2011
comment
Думаю, я отказался от этого и использую AVFoundation, поскольку iOS 3 для меня больше не важна. В любом случае спасибо за ответ. - person Ben Affleck; 24.08.2012