У меня есть приложение, в котором аудиозапись является основной и самой важной частью. Однако пользователь может переключиться на контроллер табличного представления, где отображаются все записи, а запись не выполняется.
Вопрос в том, какой подход лучше: «запустить и остановить аудиосистему или просто запустить ее». Может показаться очевидным, что первый более правильный, например, «выделять, когда вам это нужно, освобождать, когда это используется». Я изложу свои мысли по этому вопросу и надеюсь найти одобрение или неодобрение аргументами среди знающих людей.
Когда я создал 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;
}
Я нашел этот подход проблематичным по следующим причинам:
- Аудиосистема запускается с задержкой. Это означает, что функция record_callback() не вызывалась какое-то время. Я подозреваю, что за это отвечает AudioOutputUnitStart. Я попытался закомментировать строку с вызовом этой функции и перенести ее в инициализацию. задержка ушла.
- Если пользователь выполняет переключение между представлением записи и представлением таблицы очень-очень быстро (запуски и остановки аудиосистемы тоже очень быстрые), это приводит к гибели медиа-сервиса (я знаю, что здесь может помочь наблюдение за AVAudioSessionMediaServicesWereResetNotification, но это не главное).
Чтобы решить эти проблемы, я модифицировал AudioController.m другим подходом, который мне удалось обнаружить: запускать аудиосистему, когда приложение становится активным, и не останавливать ее до завершения работы приложения. В этом случае также есть несколько проблем. :
- использование процессора
- Если для категории аудио установлена только запись, то никакие другие аудио не могут воспроизводиться, когда пользователь исследует контроллер табличного представления.
Первый, на удивление, не имеет большого значения, если отменить любую обработку в 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 и включив микширование или просто проигнорировав проблему. Например, в моем случае приложение требует, чтобы мини-разъем использовался внешним устройством, поэтому наушники нельзя использовать параллельно.
Несмотря на все это, первый подход мне ближе, так как мне нравится закрывать/очищать каждый поток/ресурс, когда он больше не нужен. И я хочу быть уверен, что действительно нет другого выхода, кроме как просто запустить аудиосистему. Пожалуйста, убедитесь, что я не единственный, кто пришел к этому решению, и оно является правильным.