AVAudioRecorder недостаточно быстро записывает в файл

Я использую следующий код для записи с помощью AVAudioRecorder. Я также получаю доступ к записанному звуку в прямом эфире (через 4 секунды). Однако данные равны NULL до 6 секунд.

Есть ли способ принудительно попросить рекордер записать в файл?

NSDictionary * recordSetting;
recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:11025] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];

self.fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recorded.aac", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]]];
self.recorder = [[AVAudioRecorder alloc] initWithURL:self.fileURL settings:recordSetting error:nil];
self.recorder.meteringEnabled = YES;
self.recorder.delegate = self;
[self.recorder record];

А потом через 4 секунды я попытался прочитать файл с помощью NSDate.

NSData *songData = [NSData dataWithContentsOfURL:self.recorder.url];

Но songData равен нулю до тех пор, пока не пройдет 6 секунд.

Я знаю, что это можно сделать с помощью AudioQueue, однако я не хочу входить в AudioQueue, потому что думаю, что это было бы излишним.

Спасибо.


person moeseth    schedule 21.12.2015    source источник


Ответы (1)


Отказ от ответственности: правильный способ сделать это - записать ваш входной звук (через AudioUnit/AVAudioEngine/AudioQueue) и закодировать его с помощью AudioConverter, хотя запись на iOS - это push, а AudioConverter - pull, что не очень хорошо для чтения SO . Как вы видели, полагаться на высокоуровневый API, такой как AVAudioRecorder, для своевременной записи вывода в свой файл, пока вы копаетесь в нем, не очень надежно. Следующий пример кода (AVAudioEngine + ExtendedAudioFile) должен получить аудиоданные примерно через 1 секунду.

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/ExtendedAudioFile.h>
// ...
@property (nonatomic) AVAudioEngine *engine;
// ...

NSURL *fileURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recorded.aac", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]]];


const Float64 sampleRate = 11025;

AudioStreamBasicDescription aacDesc = { 0 };
aacDesc.mSampleRate = sampleRate;
aacDesc.mFormatID = kAudioFormatMPEG4AAC;
aacDesc.mFramesPerPacket = 1024;
aacDesc.mChannelsPerFrame = 1;

ExtAudioFileRef eaf;
OSStatus err = ExtAudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAAC_ADTSType, &aacDesc, NULL, kAudioFileFlags_EraseFile, &eaf);
assert(noErr == err);


self.engine = [[AVAudioEngine alloc] init];

AVAudioInputNode *input = self.engine.inputNode;
const AVAudioNodeBus bus = 0;

AVAudioFormat *micFormat = [input inputFormatForBus:bus];

err = ExtAudioFileSetProperty(eaf, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), micFormat.streamDescription);
assert(noErr == err);

[input installTapOnBus:bus bufferSize:512 format:micFormat block:^(AVAudioPCMBuffer *buffer, AVAudioTime *when) {
    const AudioBufferList *abl = buffer.audioBufferList;
    OSStatus err = ExtAudioFileWrite(eaf, buffer.frameLength, abl);
    assert(noErr == err);
}];

NSError *error;
if (![self.engine startAndReturnError:&error]) {
    NSLog(@"Engine start: %@", error);
}
person Rhythmic Fistman    schedule 23.12.2015
comment
Привет, можно ли получить среднюю мощность звука отсюда, как AVAudioRecorder? - person moeseth; 23.12.2015
comment
Нет, вам придется делать это вручную с входящими буферами, но это несложно. - person Rhythmic Fistman; 23.12.2015
comment
Как я могу преобразовать этот буфер в формат wav, который может читать FFMPEG? - person moeseth; 24.12.2015
comment
Можете ли вы задать это как новый вопрос? - person Rhythmic Fistman; 24.12.2015