AVAudioEngine случайно останавливается после того, как приложение переходит в фоновый режим и возвращается на передний план - PullRequest
1 голос
/ 07 мая 2020

У меня проблема с остановкой AVAudioEngine по неизвестной причине в следующей ситуации:

  • Вся работа выполняется в собственном потоке pthread с максимальным приоритетом.
  • В основную функцию потока я вызываю update в al oop, которая планирует AVAudioPCMBuffer -s следующим образом:
    [player_ scheduleBuffer:buffer completionHandler:^()
    {
        for (auto &bufferStruct : buffers_)
        {
            if (bufferStruct.buffer == buffer)
            {
                bufferStruct.available = true;
                return;
            }
        }
    }];

, где player_ имеет тип AVAudioPlayerNode.

Запланированные мной буферы заполняются вручную данными float32 pcm. Длина кадра буфера достаточна для воспроизведения 1 / 25,0 секунды. Общее количество буферов равно 5, поэтому, когда все буферы были запланированы, код ожидает, пока они станут доступны следующим образом:

    for (auto &bufferStruct : buffers_)
    {
        if (bufferStruct.position + bufferStruct.buffer.frameLength < playerTime && bufferStruct.available)
        {
            if (UpdateBuffer(bufferStruct.buffer))
            {
                ScheduleBuffer(bufferStruct);
            }
        }
    }

, где playerTime получается через AVAudioPlayerNode::playerTimeForNodeTime и AVAudioPlayerNode::lastRenderTime .

Эта схема отлично работает до тех пор, пока go приложение не перестанет работать в фоновом режиме, а затем вернется на передний план. Когда приложение переходит в фоновый режим, я прекращаю планирование AVAudioPCMBuffer -s для AVAudioPlayerNode и начинаю делать это снова, когда приложение переходит на передний план. Но в какой-то момент после того, как приложение перешло на передний план, AVAudioEngine может перестать воспроизводиться, то есть его isRunning возвращает NO (оно может перестать играть после первого переключения фона или после десятого, я не вижу в нем никакого шаблона). isRunning начинает возвращать NO через некоторое время после того, как приложение возвращается на передний план, поэтому я могу слышать несколько звуков от устройства, и несколько буферов запланированы для воспроизведения.

И в этой ситуации я Я не могу ничего сделать, чтобы заставить его снова воспроизвести:

  • Я попытался перезапустить его, позвонив startAndReturnError:
    NSError *error = nil;
    [engine_ startAndReturnError:&error];

    if (![player_ isPlaying])
    {
        [player_ play];
    }

Нет ошибок, возвращаемых startAndReturnError но при планировании новых буферов для игрока обработчик завершения, переданный в [player_ scheduleBuffer: completionHandler:...], никогда не вызывается.

  • Я попытался полностью воссоздать буферы и проигрыватель, но это не сработало.
  • Я пытался воссоздать AVAudioEngine:
    [engine_ stop];
    [engine_ release];

, и это вызывает ошибку sh в Thread 70 Queue : engine (serial):

#0  0x000000019e08b528 in objc_msgSend ()
#1  0x000000019f7f1894 in +[NSConcreteNotification newTempNotificationWithName:object:userInfo:] ()
#2  0x000000019f7f17d8 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#3  0x00000001a4d2f6ec in ___ZN17AVAudioEngineImpl26IOUnitConfigurationChangedEv_block_invoke_2 ()

Я подписан на AVAudioSessionInterruptionNotification, AVAudioSessionMediaServicesWereResetNotification, AVAudioSessionRouteChangeNotification, AVAudioEngineConfigurationChangeNotification и ни один из них не вызывается.

Я использую устройство iPhone SE, 12.3.1.

Есть какие-нибудь предложения?

...