如何在iPhone中使用AudioBuffer在本地录制从麦克风录制的audio文件?

我是新的audio框架,任何人都可以帮我写从麦克风捕捉正在播放的audio文件?

下面是通过iphone扬声器播放麦克风input的代码,现在我想将audio保存在iPhone中供将来使用。

我从这里find代码来使用麦克风录制audiohttp://www.stefanpopp.de/2011/capture-iphone-microphone/

/** Code start from here for playing the recorded voice */ static OSStatus playbackCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { /** This is the reference to the object who owns the callback. */ AudioProcessor *audioProcessor = (AudioProcessor*) inRefCon; // iterate over incoming stream an copy to output stream for (int i=0; i < ioData->mNumberBuffers; i++) { AudioBuffer buffer = ioData->mBuffers[i]; // find minimum size UInt32 size = min(buffer.mDataByteSize, [audioProcessor audioBuffer].mDataByteSize); // copy buffer to audio buffer which gets played after function return memcpy(buffer.mData, [audioProcessor audioBuffer].mData, size); // set data size buffer.mDataByteSize = size; // get a pointer to the recorder struct variable Recorder recInfo = audioProcessor.audioRecorder; // write the bytes OSStatus audioErr = noErr; if (recInfo.running) { audioErr = AudioFileWriteBytes (recInfo.recordFile, false, recInfo.inStartingByte, &size, &buffer.mData); assert (audioErr == noErr); // increment our byte count recInfo.inStartingByte += (SInt64)size;// size should be number of bytes audioProcessor.audioRecorder = recInfo; } } return noErr; } 

– (无效)prepareAudioFileToRecord {

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; NSTimeInterval time = ([[NSDate date] timeIntervalSince1970]); // returned as a double long digits = (long)time; // this is the first 10 digits int decimalDigits = (int)(fmod(time, 1) * 1000); // this will get the 3 missing digits // long timestamp = (digits * 1000) + decimalDigits; NSString *timeStampValue = [NSString stringWithFormat:@"%ld",digits]; // NSString *timeStampValue = [NSString stringWithFormat:@"%ld.%d",digits ,decimalDigits]; NSString *fileName = [NSString stringWithFormat:@"test%@.caf",timeStampValue]; NSString *filePath = [basePath stringByAppendingPathComponent:fileName]; NSURL *fileURL = [NSURL fileURLWithPath:filePath]; // modify the ASBD (see EDIT: towards the end of this post!) audioFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; // set up the file (bridge cast will differ if using ARC) OSStatus audioErr = noErr; audioErr = AudioFileCreateWithURL((CFURLRef)fileURL, kAudioFileCAFType, &audioFormat, kAudioFileFlags_EraseFile, &audioRecorder.recordFile); assert (audioErr == noErr);// simple error checking audioRecorder.inStartingByte = 0; audioRecorder.running = true; self.audioRecorder = audioRecorder; 

}

在此先感谢巴拉

要将AudioBuffer中的字节写入本地文件,我们需要AudioToolbox框架中包含的AudioFileServices 链接类的帮助。

从概念上讲,我们将做以下工作 – build立一个audio文件,并保持一个引用( 我们需要这个引用可以从你的post中包含的渲染callback中访问 )。 我们还需要跟踪每次调用callback时写入的字节数。 最后一个检查标志会让我们知道停止写入文件并closures文件。

由于您提供的链接中的代码声明了一个AudioStreamBasicDescription ,它是LPCM,因此具有恒定的比特率,所以我们可以使用AudioFileWriteBytes函数( 写入压缩audio更为复杂,而使用AudioFileWritePackets函数 )。

我们首先声明一个自定义结构( 包含所有需要的额外数据 ),然后添加一个自定义结构的实例variables,并创build一个指向结构variables的属性。 我们将这个添加到AudioProcessor自定义类中,因为您已经可以在该行中input的callback中访问此对象。

 AudioProcessor *audioProcessor = (AudioProcessor*) inRefCon; 

将此添加到AudioProcessor.h (在@interface上方)

 typedef struct Recorder { AudioFileID recordFile; SInt64 inStartingByte; Boolean running; } Recorder; 

现在让我们添加一个实例variables,并使其成为一个指针属性,并将其分配给实例variables( 以便我们可以从callback函数中访问它 )。 在@interface中添加一个名为audioRecorder的实例variables,并使该类可用的ASBD。

 Recorder audioRecorder; AudioStreamBasicDescription recordFormat;// assign this ivar to where the asbd is created in the class 

在方法– (void)initializeAudio注释掉或删除这一行,因为我们已经使recordFormat伊娃。

 //AudioStreamBasicDescription recordFormat; 

现在将kAudioFormatFlagIsBigEndian格式标志添加到ASBD的设置位置。

 // also modify the ASBD in the AudioProcessor classes -(void)initializeAudio method (see EDIT: towards the end of this post!) recordFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 

最后把它作为一个指向audioRecorder实例variables的属性添加,不要忘记在AudioProcessor.m中进行合成。 我们将命名属性audioRecorderPointer

 @property Recorder *audioRecorderPointer; // in .m synthesise the property @synthesize audioRecorderPointer; 

现在让我们把指针分配给伊娃(这可以放在AudioProcessor类的– (void)initializeAudio方法中)

 // ASSIGN POINTER PROPERTY TO IVAR self.audioRecorderPointer = &audioRecorder; 

现在在AudioProcessor.m中添加一个方法来设置文件并打开它,以便我们可以写入它。 这应该在你启动AUGraph运行之前调用。

 -(void)prepareAudioFileToRecord { // lets set up a test file in the documents directory NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; NSString *fileName = @"test_recording.aif"; NSString *filePath = [basePath stringByAppendingPathComponent:fileName]; NSURL *fileURL = [NSURL fileURLWithPath:filePath]; // set up the file (bridge cast will differ if using ARC) OSStatus audioErr = noErr; audioErr = AudioFileCreateWithURL((CFURLRef)fileURL, kAudioFileAIFFType, recordFormat, kAudioFileFlags_EraseFile, &audioRecorder.recordFile); assert (audioErr == noErr);// simple error checking audioRecorder.inStartingByte = 0; audioRecorder.running = true; } 

好的,我们快到了。 现在我们有一个要写入的文件,并且可以从rendercallback中访问AudioFileID 。 因此,在您发布的callback函数中,在方法结尾处返回noErr之前,请添加以下内容。

 // get a pointer to the recorder struct instance variable Recorder *recInfo = audioProcessor.audioRecorderPointer; // write the bytes OSStatus audioErr = noErr; if (recInfo->running) { audioErr = AudioFileWriteBytes (recInfo->recordFile, false, recInfo->inStartingByte, &size, buffer.mData); assert (audioErr == noErr); // increment our byte count recInfo->inStartingByte += (SInt64)size;// size should be number of bytes } 

当我们想要停止录音( 可能是由某个用户操作调用的 ),只需使运行布尔值为false,并在AudioProcessor类的某个地方closures文件。

 audioRecorder.running = false; OSStatus audioErr = AudioFileClose(audioRecorder.recordFile); assert (audioErr == noErr); 

编辑:样品的字节序列需要是文件的大端,所以将kAudioFormatFlagIsBigEndian位掩码标志添加到问题中提供的链接中find的源代码中的ASBD。

有关此主题的额外信息,Apple文档是一个很好的资源,我也推荐阅读Chris Adamson和Kevin Avila(我拥有一份副本)的“Learning Core Audio”。

使用audio队列服务。

在苹果文档中有一个例子完全符合你的要求:

audio队列服务编程指南 – 录制audio