Как установить кран на inputNode по умолчанию AudioEngine и записать в файл

Я пытаюсь сделать что-то действительно простое, но я добился прогресса только урывками. Пока я хочу получить аудиоданные с микрофона в файл. Я займусь дополнительной обработкой данных в блоке, как только преодолею это препятствие. Я устал от некоторых идеосинкразий, которые я обнаружил в AVAudioEngine, и мне интересно, стоит ли мне вернуться к AudioUnits, который, вероятно, немного лучше отлажен (хотя и более сложен).

Во-первых, кажется, что AudioEngine не может быть запущен до тех пор, пока не будет создан экземпляр inputNode, а затем вы не можете использовать его outputFormatForBus для получения его формата (частота дискретизации равна нулю); вы должны использовать inputFormatForBus.

Теперь, когда он у меня работает, и я получаю вызовы в блоке с теми, которые кажутся действительными данными, я не могу записать в файл без создания исключения с ошибкой:

'ошибка записи буферных данных в файл. Операция не может быть завершена. (ошибка com.apple.coreaudio.avfaudio 1768846202.) '

('insz') Похоже, это указывает на какую-то ошибку либо с форматом, который я предоставляю, либо с форматом, который получает блок.

есть идеи?

_engine = [[AVAudioEngine alloc] init];

_outputFileURL = [NSURL URLWithString:[NSTemporaryDirectory() stringByAppendingString:@"tempOutput.caf"]];

AVAudioInputNode *inputNode = [_engine inputNode];
AVAudioFormat *format = [inputNode inputFormatForBus:1];
NSMutableDictionary *recordSettings = format.settings.mutableCopy;
[recordSettings addEntriesFromDictionary:@{
                              AVFormatIDKey : @(kAudioFormatMPEG4AAC),
                              AVEncoderAudioQualityKey : @(AVAudioQualityMedium)
                              }];

AVAudioFile *outputFile = [[AVAudioFile alloc] initForWriting:_outputFileURL settings:recordSettings error:&error];

[inputNode installTapOnBus:1 bufferSize:4096 format:format block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
    NSError *error;

    // as AVAudioPCMBuffer's are delivered this will write sequentially. The buffer's frameLength signifies how much of the buffer is to be written
    // IMPORTANT: The buffer format MUST match the file's processing format which is why outputFormatForBus: was used when creating the AVAudioFile object above
    NSAssert([outputFile writeFromBuffer:buffer error:&error], @"error writing buffer data to file, %@", [error localizedDescription]);
}];
if (!_engine.isRunning) [self startEngine];

Спасибо.

Обновленный код на основе комментария @matt


person mahboudz    schedule 21.04.2015    source источник
comment
settings:[format settings]. Вероятно, в этом проблема. Вам нужны правильные настройки формата выходного файла.   -  person matt    schedule 21.04.2015
comment
Я просто пытался записать данные в формате PCM, чтобы все было просто (см. Пример использования AVAudioEngine для воспроизведения, микширования и записи Apple). Я добавил ключи словаря, чтобы сохранить файл в формате MP4 AAC, но все равно не повезло.   -  person mahboudz    schedule 21.04.2015
comment
Хорошо, но я бы все же посоветовал вам совсем не основывать настройки выходного файла на формате входного узла. Попробуйте найти группу полностью независимых настроек, которые работают. Это то, что мне пришлось сделать, когда я впервые написал кран.   -  person matt    schedule 21.04.2015


Ответы (1)


Вот как я обошел это, на случай, если кто-то еще столкнется с той же проблемой.

@matt правильно заметил, что я должен создавать независимые настройки, а не использовать формат, связанный с inputNode.

commonFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 sampleRate:44100 channels:2 interleaved:NO];

engine = [[AVAudioEngine alloc] init];
AVAudioInputNode *inputNode = engine.inputNode;

NSError *error;
AVAudioFile *outputFile = [[AVAudioFile alloc] initForWriting:_outputFileURL settings:commonFormat.settings error:&error];

[inputNode installTapOnBus:0 bufferSize:4096 format:commonFormat block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
    NSError *error;

    NSAssert([outputFile writeFromBuffer:buffer error:&error], @"error writing buffer data to file, %@", [error localizedDescription]);
}];
person mahboudz    schedule 18.05.2015