MacOS下如何从AudioQueueRef获取有效原始音频数据?
问题分析与解决方案
核心问题
你错误地使用了音频缓冲区的总容量(mAudioDataBytesCapacity)计算样本数,而回调中只有mAudioDataByteSize大小的数据是麦克风实际采集到的有效数据,剩余缓冲区空间未被填充,因此会出现大量0值。结合你的参数配置,实际有效样本数应该由实际采集的数据包数和每包帧数共同决定,而非缓冲区总容量。
修复后的回调代码
static void MyAQInputCallback(void *inUserData, AudioQueueRef inQueue, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc) { MyRecorder *recorder = (MyRecorder *)inUserData; if (inNumPackets > 0) { // 保留原有的音频文件写入逻辑(这部分是正确的) CheckError(AudioFileWritePackets(recorder->recordFile, FALSE, inBuffer->mAudioDataByteSize, inPacketDesc, recorder->recordPacket, &inNumPackets, inBuffer->mAudioData), "AudioFileWritePackets failed"); recorder->recordPacket += inNumPackets; // 关键修复:用实际有效字节数计算样本数,而非缓冲区总容量 int sampleCount = inBuffer->mAudioDataByteSize / sizeof(AUDIO_DATA_TYPE_FORMAT); // 更可靠的计算方式:直接用数据包数 × 每包帧数 // int sampleCount = inNumPackets * recorder->format->mFramesPerPacket; AUDIO_DATA_TYPE_FORMAT* samples = (AUDIO_DATA_TYPE_FORMAT*)inBuffer->mAudioData; // 增加文件打开失败的判断,避免崩溃 FILE *fp = fopen(filename, "a"); if (fp != NULL) { for (int i = 0; i < sampleCount; i++){ fprintf(fp, "%d\n", samples[i]); // 修正原代码的字符串格式错误 } fclose(fp); } } if (recorder->running) CheckError(AudioQueueEnqueueBuffer(inQueue, inBuffer, 0, NULL), "AudioQueueEnqueueBuffer failed"); }
额外优化建议
- 文件操作优化:不要在回调中频繁打开/关闭文件,回调属于实时线程,频繁IO会导致延迟甚至丢数据。建议在录音初始化时打开文件,停止录音时再关闭。
- 格式一致性验证:确保
AUDIO_DATA_TYPE_FORMAT与你设置的音频格式位深匹配。比如16位有符号PCM对应typedef SInt16 AUDIO_DATA_TYPE_FORMAT;,32位浮点PCM对应typedef float AUDIO_DATA_TYPE_FORMAT;,不匹配会导致数据解析错误。 - 缓冲区参数校准:你的
buffer duration=0.1、采样率44100,单声道下每缓冲区应有4410帧。如果mFramesPerPacket=1024,inNumPackets应为ceil(4410/1024)=5,当前的4包配置可能导致缓冲区未填满,建议手动计算缓冲区大小并按数据包对齐:UInt32 bufferByteSize = (44100 * 0.1) * sizeof(AUDIO_DATA_TYPE_FORMAT); bufferByteSize -= bufferByteSize % (recorder->format->mBytesPerPacket);
内容的提问来源于stack exchange,提问作者NotAProgrammer
相关产品推荐
相关产品推荐

