AVAudioRecorder 写入文件的速度不够快
AVAudioRecorder doesn't write to file fast enough
我正在使用以下代码通过 AVAudioRecorder 进行录音。我也正在实时访问录制的音频(4 秒后)。但是,数据在 6 秒之前为 NULL。
有没有办法强制要求刻录机写入文件?
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 秒后才为 nil。
我知道使用 AudioQueue 可以做到这一点,但是,我不想进入 AudioQueue,因为我想这太过分了。
谢谢。
免责声明:正确的方法是录制您的输入音频(通过 AudioUnit
/AVAudioEngine
/AudioQueue
)并使用 AudioConverter
对其进行编码,虽然在 iOS 上的记录是推式的,而 AudioConverter
上的记录是拉式的,但这并不能很好地阅读。如您所见,依靠高级别 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);
}
我正在使用以下代码通过 AVAudioRecorder 进行录音。我也正在实时访问录制的音频(4 秒后)。但是,数据在 6 秒之前为 NULL。
有没有办法强制要求刻录机写入文件?
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 秒后才为 nil。
我知道使用 AudioQueue 可以做到这一点,但是,我不想进入 AudioQueue,因为我想这太过分了。
谢谢。
免责声明:正确的方法是录制您的输入音频(通过 AudioUnit
/AVAudioEngine
/AudioQueue
)并使用 AudioConverter
对其进行编码,虽然在 iOS 上的记录是推式的,而 AudioConverter
上的记录是拉式的,但这并不能很好地阅读。如您所见,依靠高级别 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);
}