Аудиосистема iOS. Начать и остановить или просто начать?

У меня есть приложение, в котором аудиозапись является основной и самой важной частью. Однако пользователь может переключиться на контроллер табличного представления, где отображаются все записи, а запись не выполняется.

Вопрос в том, какой подход лучше: «запустить и остановить аудиосистему или просто запустить ее». Может показаться очевидным, что первый более правильный, например, «выделять, когда вам это нужно, освобождать, когда это используется». Я изложу свои мысли по этому вопросу и надеюсь найти одобрение или неодобрение аргументами среди знающих людей.

Когда я создал AudioController.m в первый раз, я реализовал методы для открытия/закрытия аудиосессии и запуска/остановки аудиоустройства. Я хотел остановить аудиосистему, когда запись не активна. Я использовал следующий код:

- (BOOL)startAudioSystem {

    // open audio session
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *err = nil;
    if (![audioSession setActive:YES error:&err] ) {
        NSLog(@"Couldn't activate audio session: %@", err);
    }
    // start audio unit
    OSStatus status;
    status = AudioOutputUnitStart([self audioUnit]);
    BOOL noErrors = err == nil && status == noErr;    
    return noErrors;
}

а также

- (BOOL)stopAudioSystem {
    // stop audio unit
    BOOL result;
    result = AudioOutputUnitStop([self audioUnit]) == noErr;
    HANDLE_RESULT(result);
    // close audio session
    NSError *err;
    HANDLE_RESULT([[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&err]);
    HANDLE_ERROR(err);
    BOOL noErrors = err == nil && result;
    return noErrors;
}

Я нашел этот подход проблематичным по следующим причинам:

  1. Аудиосистема запускается с задержкой. Это означает, что функция record_callback() не вызывалась какое-то время. Я подозреваю, что за это отвечает AudioOutputUnitStart. Я попытался закомментировать строку с вызовом этой функции и перенести ее в инициализацию. задержка ушла.
  2. Если пользователь выполняет переключение между представлением записи и представлением таблицы очень-очень быстро (запуски и остановки аудиосистемы тоже очень быстрые), это приводит к гибели медиа-сервиса (я знаю, что здесь может помочь наблюдение за AVAudioSessionMediaServicesWereResetNotification, но это не главное).

Чтобы решить эти проблемы, я модифицировал AudioController.m другим подходом, который мне удалось обнаружить: запускать аудиосистему, когда приложение становится активным, и не останавливать ее до завершения работы приложения. В этом случае также есть несколько проблем. :

  1. использование процессора
  2. Если для категории аудио установлена ​​только запись, то никакие другие аудио не могут воспроизводиться, когда пользователь исследует контроллер табличного представления.

Первый, на удивление, не имеет большого значения, если отменить любую обработку в record_callback() следующим образом:

    static OSStatus recordingCallback(void *inRefCon,
                                  AudioUnitRenderActionFlags *ioActionFlags,
                                  const AudioTimeStamp *inTimeStamp,
                                  UInt32 inBusNumber,
                                  UInt32 inNumberFrames,
                                  AudioBufferList *ioData) {

    AudioController *input = (__bridge AudioController*)inRefCon;

    if(!input->shouldPerformProcessing)
        return noErr;

    // processing
    // ...
    //

    return noErr;
}

При этом загрузка ЦП равна 0% на реальном устройстве, когда не требуется запись и не выполняются никакие другие действия.

А вторую проблему можно решить переключив категорию аудио на RecordAndPlay и включив микширование или просто проигнорировав проблему. Например, в моем случае приложение требует, чтобы мини-разъем использовался внешним устройством, поэтому наушники нельзя использовать параллельно.

Несмотря на все это, первый подход мне ближе, так как мне нравится закрывать/очищать каждый поток/ресурс, когда он больше не нужен. И я хочу быть уверен, что действительно нет другого выхода, кроме как просто запустить аудиосистему. Пожалуйста, убедитесь, что я не единственный, кто пришел к этому решению, и оно является правильным.


person galarius    schedule 30.04.2015    source источник


Ответы (1)


Ключом к решению этой проблемы является то, что аудиосистема фактически работает в другом потоке (в реальном времени). И вы не можете на самом деле остановить и освободить что-то, работающее в другом потоке, именно тогда, когда вам (или основному потоку пользовательского интерфейса приложения) это «не нужно», но вам нужно отложить, чтобы позволить другому потоку понять, что это нужно сделать что-то, а затем закончить и очистить себя. Это потенциально может занять до многих сотен миллисекунд для звука.

Учитывая это, стратегия 2 (просто начать) более безопасна и реалистична.

Или, возможно, установите задержку в несколько секунд неиспользования перед попыткой остановить звук и, возможно, еще одну короткую задержку после этого перед попыткой любого перезапуска.

person hotpaw2    schedule 29.11.2015
comment
Спасибо за ваш ответ! Я понимаю это сейчас. Я выбрал вторую стратегию. - person galarius; 06.12.2015