我目前正在通过 Internet 传输 mp3 音频。我正在使用 AudioFileStream 解析来自 CFReadStreamRef 的 mp3 流,使用 AudioConverterFillComplexBuffer 解码 mp3 并将转换后的 PCM 数据复制到环形缓冲区中,最后使用 RemoteIO 播放 PCM。
我目前面临的问题是 AudioConverterFillComplexBuffer 总是返回 0(没有错误),但转换结果似乎不正确。在细节上,我可以注意到,
A. UInt32 *ioOutputDataPacketSize 保持与我发送的相同值。
B. convertData.mBuffers[0].mDataByteSize 总是设置为输出缓冲区的大小(不管缓冲区有多大)。
C. 我只能听到输出数据的咔嗒声。
以下是我渲染音频的程序。同样的过程适用于我的音频队列实现,所以我相信我在调用 AudioConverterFillComplexBuffer 或 AudioConverterFillComplexBuffer 回调的地方都没有错。
我在这个问题上被困了很长时间。任何帮助将不胜感激。
打开一个音频文件流。
// 创建音频文件流解析器 AudioFileTypeID fileTypeHint = kAudioFileMP3Type;
AudioFileStreamOpen(self, MyPropertyListenerProc, MyPacketsProc, fileTypeHint, &audioFileStream);在回调函数(“MyPacketsProc”)中处理解析的数据。
void MyPacketsProc(void * inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void * inInputData, AudioStreamPacketDescription *inPacketDescriptions) { @synchronized(self) { // 初始化音频转换器。if (!audioConverter) AudioConverterNew(&asbd, &asbd_out, &audioConverter);
struct mp3Data mSettings; memset(&mSettings, 0, sizeof(mSettings)); UInt32 packetsPerBuffer = 0; UInt32 outputBufferSize = 1024 * 32; // 32 KB is a good starting point. UInt32 sizePerPacket = asbd.mBytesPerPacket; // Calculate the size per buffer. // Variable Bit Rate Data. if (sizePerPacket == 0) { UInt32 size = sizeof(sizePerPacket); AudioConverterGetProperty(audioConverter, kAudioConverterPropertyMaximumOutputPacketSize, &size, &sizePerPacket); if (sizePerPacket > outputBufferSize) outputBufferSize = sizePerPacket; packetsPerBuffer = outputBufferSize / sizePerPacket; } //CBR else packetsPerBuffer = outputBufferSize / sizePerPacket; // Prepare the input data for the callback. mSettings.inputBuffer.mDataByteSize = inNumberBytes; mSettings.inputBuffer.mData = (void *)inInputData; mSettings.inputBuffer.mNumberChannels = 1; mSettings.numberPackets = inNumberPackets; mSettings.packetDescription = inPacketDescriptions; // Set up our output buffers UInt8 * outputBuffer = (UInt8*)malloc(sizeof(UInt8) * outputBufferSize); memset(outputBuffer, 0, outputBufferSize); // describe output data buffers into which we can receive data. AudioBufferList convertedData; convertedData.mNumberBuffers = 1; convertedData.mBuffers[0].mNumberChannels = 1; convertedData.mBuffers[0].mDataByteSize = outputBufferSize; convertedData.mBuffers[0].mData = outputBuffer; // Convert. UInt32 ioOutputDataPackets = packetsPerBuffer; OSStatus result = AudioConverterFillComplexBuffer(audioConverter, converterComplexInputDataProc, &mSettings, &ioOutputDataPackets, &convertedData, NULL ); // Enqueue the ouput pcm data. TPCircularBufferProduceBytes(&m_pcmBuffer, convertedData.mBuffers[0].mData, convertedData.mBuffers[0].mDataByteSize); free(outputBuffer); }
}
从其回调函数(“converterComplexInputDataProc”)向音频转换器提供数据。
OSStatus converterComplexInputDataProc(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData, AudioStreamPacketDescription** ioDataPacketDescription, void* inUserData) { struct mp3Data THIS = (struct mp3Data ) inUserData;
if (THIS->inputBuffer.mDataByteSize > 0)
{
*ioNumberDataPackets = THIS->numberPackets;
ioData->mNumberBuffers = 1;
ioData->mBuffers[0].mDataByteSize = THIS->inputBuffer.mDataByteSize;
ioData->mBuffers[0].mData = THIS->inputBuffer.mData;
ioData->mBuffers[0].mNumberChannels = 1;
if (ioDataPacketDescription)
*ioDataPacketDescription = THIS->packetDescription;
}
else
*ioDataPacketDescription = 0;
return 0;
}
使用 RemoteIO 组件播放。
输入和输出 AudioStreamBasicDescription。
输入:
采样率:16000 格式 ID:.mp3
格式标志:0
每个数据包的字节数:0
每包帧数:576
每帧字节数:0
每帧通道数:1
每通道位数:0
输出:
采样率:44100
格式 ID:lpcm
格式标志:3116
每个数据包的字节数:4
每包帧数:1
每帧字节数:4
每帧通道数:1
每通道位数:32