如何录制/保存 iPhone 应用程序中正在播放的音频?
Posted
技术标签:
【中文标题】如何录制/保存 iPhone 应用程序中正在播放的音频?【英文标题】:How to record/save audio being played in iPhone Application? 【发布时间】:2012-07-10 19:34:56 【问题描述】:我想录制(保存为文档目录中的文件)正在应用程序中播放的音频。基本上我可以连接到音频输出缓冲区并可以在文件中读取/保存这些缓冲区吗?
我阅读了一些博客并在谷歌上进行了搜索。他们中的大多数都指向 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 读取缓冲区时犯了一些错误。
非常感谢任何形式的帮助。
【问题讨论】:
您尝试过使用 novocaine 吗? github.com/alexbw/novocaine 【参考方案1】:好的。很多事情都可能在这里出错。
我不知道您是如何初始化 ExtAudioFileRef 的。 您设置的客户端格式是什么。 你设置的是什么音频格式(是的,正确的 mp3)。 您使用的是什么文件格式。 他们都必须无缝协作。不过,看看这个条目。这是一个完美运行的示例代码:
Recording to AAC from RemoteIO: data is getting written but file unplayable
它可以满足您的需求。即时录制压缩音频。
你有没有像这样初始化你的ExtAudioFileWriteAsync
(在回调之前)?
ExtAudioFileWriteAsync(extAudioFileRefVar, 0, NULL);
如果没有更多的代码,真的很难说在所有可能的事情中哪些地方会出错。
【讨论】:
以上是关于如何录制/保存 iPhone 应用程序中正在播放的音频?的主要内容,如果未能解决你的问题,请参考以下文章