如何录制/保存在iPhone应用程序中播放的音频?

时间:2012-07-10 19:34:56

标签: iphone core-audio audio-recording audiounit

我想在应用程序中录制(保存为文档目录中的文件)音频。基本上我可以挂钩到音频输出缓冲区,并可以读取/保存文件中的缓冲区吗?

我阅读了一些博客并在谷歌上搜索过。他们中的大多数都指向AudioUnit。

我尝试过使用AudioUnit - RemoteIO,但我无法达到我想要的效果,可能是搞砸了。

以下是我为初始化AudioUnit编写的代码

OSStatus status;

// Describe audio component
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;

// Get component
AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

// Get audio units
status = AudioComponentInstanceNew(inputComponent, &mAudioUnit);

// Enable IO for recording
UInt32 flag = 1

// Enable IO for playback
status = AudioUnitSetProperty(mAudioUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Output, 
                              kOutputBus,
                              &flag, 
                              sizeof(flag));

// Describe format
AudioStreamBasicDescription audioFormat={0};
audioFormat.mSampleRate         = kSampleRate;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket    = 1;
audioFormat.mChannelsPerFrame   = 1;
audioFormat.mBitsPerChannel     = 16;
audioFormat.mBytesPerPacket     = 2;
audioFormat.mBytesPerFrame      = 2;

// Apply format
status = AudioUnitSetProperty(mAudioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Output, 
                              kInputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));


// Set input callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = playbackCallback;
callbackStruct.inputProcRefCon = self;

status = AudioUnitSetProperty(mAudioUnit, 
                              kAudioUnitProperty_SetRenderCallback, 
                              kAudioUnitScope_Input, 
                              kOutputBus,
                              &callbackStruct, 
                              sizeof(callbackStruct));
AudioUnitInitialize(mAudioUnit);
AudioOutputUnitStart(mAudioUnit);

在playbackCallback中:

static OSStatus playbackCallback(void *inRefCon, 
                             AudioUnitRenderActionFlags *ioActionFlags, 
                             const AudioTimeStamp *inTimeStamp, 
                             UInt32 inBusNumber, 
                             UInt32 inNumberFrames, 
                             AudioBufferList *ioData) {    
double timeInSeconds = inTimeStamp->mSampleTime / kSampleRate;
printf("\nPLAYBACK %fs inBusNumber: %lu inNumberFrames: %lu ", timeInSeconds, inBusNumber, inNumberFrames);

AudioBufferList bufferList;

SInt16 samples[inNumberFrames]; // A large enough size to not have to worry about buffer overrun
memset (&samples, 0, sizeof (samples));

bufferList.mNumberBuffers = 1;
bufferList.mBuffers[0].mData = samples;
bufferList.mBuffers[0].mNumberChannels = 1;
bufferList.mBuffers[0].mDataByteSize = inNumberFrames*sizeof(SInt16);

ViewController* THIS = THIS = (__bridge ViewController *)inRefCon;

OSStatus status;
status = AudioUnitRender(THIS->mAudioUnit,     
                         ioActionFlags, 
                         inTimeStamp, 
                         kOutputBus, 
                         inNumberFrames, 
                         &bufferList);

if (noErr != status) {

    printf("AudioUnitRender error: %ld", status); 
    return noErr;
}

// Now, we have the samples we just read sitting in buffers in bufferList
ExtAudioFileWriteAsync(THIS->mAudioFileRef, inNumberFrames, &bufferList);

return noErr;
}

以上mAudioFileRef是我在viewDidLoad中创建的mp3文件的参考。

当我运行上面的程序时,我收到AudioUnitRender错误:-50。和mp3文件没有填充数据。

可能我在设置音频单元或从ioData读取缓冲区时犯了一些错误。

非常感谢任何形式的帮助。

1 个答案:

答案 0 :(得分:0)

确定。很多事情都可能出错。

  • 我不知道你是如何初始化ExtAudioFileRef的。
  • 您设置了哪种客户端格式。
  • 你设置了什么音频格式(是的,右mp3)。
  • 您使用的是哪种文件格式。
  • 他们都必须无缝合作。

尽管如此,请看一下这个条目。这是一个完美的示例代码:

Recording to AAC from RemoteIO: data is getting written but file unplayable

它有点满足你的需要。即时录制压缩音频。

您是否已将此ExtAudioFileWriteAsync初始化(在回调之前)?

ExtAudioFileWriteAsync(extAudioFileRefVar, 0, NULL);

在没有更多代码的情况下,很难说出所有可能出现的问题。