从音频输入中捕获原始音频以在 Mac 上进行实时处理的最简单方法
Posted
技术标签:
【中文标题】从音频输入中捕获原始音频以在 Mac 上进行实时处理的最简单方法【英文标题】:Simplest way to capture raw audio from audio input for real time processing on a mac 【发布时间】:2011-05-18 02:37:02 【问题描述】:什么是从内置音频输入捕获音频并能够在请求时实时读取原始采样值(如 .wav 格式)的最简单方法,例如从套接字读取。
希望代码使用 Apple 的一种框架(音频队列)。文档不是很清楚,我需要的很基础。
【问题讨论】:
【参考方案1】:为此尝试使用 AudioQueue 框架。您主要需要执行 3 个步骤:
-
设置音频格式如何对传入的模拟音频进行采样
使用 AudioQueueNewInput() 开始新的录音 AudioQueue
注册一个回调例程来处理传入的音频数据包
在第 3 步中,您有机会使用 AudioQueueGetProperty() 分析传入的音频数据
大致是这样的:
static void HandleAudioCallback (void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudiostreamPacketDescription *inPacketDesc)
// Here you examine your audio data
static void StartRecording()
// now let's start the recording
AudioQueueNewInput (&aqData.mDataFormat, // The sampling format how to record
HandleAudioCallback, // Your callback routine
&aqData, // e.g. AudioStreamBasicDescription
NULL,
kCFRunLoopCommonModes,
0,
&aqData.mQueue); // Your fresh created AudioQueue
AudioQueueStart(aqData.mQueue,
NULL);
我建议Apple AudioQueue Services Programming Guide 获取有关如何启动和停止 AudioQueue 以及如何正确设置所有其他必需对象的详细信息。
您还可以仔细查看 Apple 的演示程序 SpeakHere。但恕我直言,这开始有点令人困惑。
【讨论】:
【参考方案2】:这取决于您需要它的“实时性”程度
如果您需要它非常清脆,请直接从底层向下并使用音频单元。这意味着设置一个 INPUT 回调。请记住,当它触发时,您需要分配自己的缓冲区,然后从麦克风请求音频。
即不要被参数中存在缓冲区指针所迷惑......它只是因为Apple对输入和渲染回调使用相同的函数声明。
这是我的一个项目的粘贴:
OSStatus dataArrivedFromMic(
void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * dummy_notused )
OSStatus status;
RemoteIOAudioUnit* unitClass = (RemoteIOAudioUnit *)inRefCon;
AudioComponentInstance myUnit = unitClass.myAudioUnit;
AudioBufferList ioData;
int kNumChannels = 1; // one channel...
enum
kMono = 1,
kStereo = 2
;
ioData.mNumberBuffers = kNumChannels;
for (int i = 0; i < kNumChannels; i++)
int bytesNeeded = inNumberFrames * sizeof( Float32 );
ioData.mBuffers[i].mNumberChannels = kMono;
ioData.mBuffers[i].mDataByteSize = bytesNeeded;
ioData.mBuffers[i].mData = malloc( bytesNeeded );
// actually GET the data that arrived
status = AudioUnitRender( (void *)myUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
& ioData );
// take MONO from mic
const int channel = 0;
Float32 * outBuffer = (Float32 *) ioData.mBuffers[channel].mData;
// get a handle to our game object
static KPRing* kpRing = nil;
if ( ! kpRing )
//AppDelegate * appDelegate = [UIApplication sharedApplication].delegate;
kpRing = [Game singleton].kpRing;
assert( kpRing );
// ... and send it the data we just got from the mic
[ kpRing floatsArrivedFromMic: outBuffer
count: inNumberFrames ];
return status;
【讨论】:
在输入回调中调用 malloc() 不是一个好主意,因为它可能会影响实时性能。最好通过inRefCon
指针传递预先分配的缓冲区。以上是关于从音频输入中捕获原始音频以在 Mac 上进行实时处理的最简单方法的主要内容,如果未能解决你的问题,请参考以下文章
使用 Google Speech to Text API 从 Web 应用程序中的麦克风捕获实时音频 [关闭]
如何在 WASAPICaptureSharedEventDriven 中保存原始格式的音频文件