AudioSessionSetActive не работает после прерывания - PullRequest
8 голосов
/ 28 октября 2011

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

В оригинальном коде все вызовы AudioSession и AudioQueue заключены в макросы, которые выводят OSStatus, если это означает ошибку, но я удалил его для лучшей читаемости.Кроме того, [self pause] просто переключает паузу, поэтому в основном она вызывает AudioQueueStart (audioQueue, NULL) для upause, но не работает, если 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, если это поможет каким-либо образом решить проблему ..

Ответы [ 6 ]

3 голосов
/ 04 ноября 2011

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

2 голосов
/ 13 декабря 2012

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

retry(~1000 times :) 

ftw)

AudioSessionSetActive(true), 

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

0 голосов
/ 04 ноября 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");
    }
}
0 голосов
/ 04 ноября 2011

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

AudioSessionSetActive(FALSE);

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

AudioSessionSetActive(TRUE);

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

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

0 голосов
/ 01 ноября 2011

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

0 голосов
/ 30 октября 2011

Попробуйте активировать 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");

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

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

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

...