方案二:使用AudioQueues获取实时PCM音频流数据,调用lame转码,写入mp3文件
1.规定录制音频流相关参数
AudioStreamBasicDescription _format;
// 录制音频数据格式
_format.mFormatID = kAudioFormatLinearPCM;
// 标签格式
_format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
// 语音每采样点占用位数[8/16/24/32]
_format.mBitsPerChannel = 16;
// 单通道双通道
_format.mChannelsPerFrame = 1;
// 每个数据包中的Bytes数量 & 每帧的Byte数
_format.mBytesPerPacket = _format.mBytesPerFrame = (_format.mBitsPerChannel / 8) * _format.mChannelsPerFrame;
// 每个数据包中的帧数量
_format.mFramesPerPacket = 1;
// 录音采样率
_format.mSampleRate = 8000.0f;
2.初始化lame
lame = lame_init();
lame_set_in_samplerate(lame, format.mSampleRate);
lame_set_num_channels(lame, format.mChannelsPerFrame);
lame_set_VBR(lame, vbr_default);
lame_set_brate(lame, format.mBitsPerChannel);
lame_set_quality(lame,2);
lame_init_params(lame);
3.打开mp3文件流
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.mp3"];
FILE *mp3 = fopen([path cStringUsingEncoding:NSASCIIStringEncoding], "wb+");
4.音频队列回调音频缓冲数据并开始转码(仍然需要判断单通道&双通道)最后写入mp3文件
/*
@typedef AudioQueueInputCallback
当一个录音的音频队列已经填满其中一个缓冲区会调用回调函数
@param inUserData
为录音数据创建一个新的音频队列(AudioQueueNewInput)中的标明的参数
@param inAQ
音频队列调用回调函数
@param inBuffer
音频队列中最新被填充满的最新的音频数据缓冲区
@param inStartTime
@param inNumberPacketDescriptions
多少个数据包
@param inPacketDescs
音频流数据包描述
typedef void (*AudioQueueInputCallback)( void * __nullable inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription * __nullable inPacketDescs);
*/
int mp3DataSize = inNumberPacketDescriptions;
unsigned char mp3Buffer[mp3DataSize];
int encodedBytes = 0;
/* AudioQueueBuffer 结构体
typedef AudioQueueBuffer *AudioQueueBufferRef;
mAudioData: 这是一个指向音频数据缓冲区的指针
inNumberPacketDescriptions: 数据包
*/
if (_format.mChannelsPerFrame == 1) {
// 单通道
encodedBytes = lame_encode_buffer( lame, inBuffer->mAudioData,NULL, inNumberPacketDescriptions, mp3Buffer, mp3DataSize);
} else {
// 双通道
encodedBytes = lame_encode_buffer_interleaved(lame, inBuffer->mAudioData, inNumberPacketDescriptions, mp3Buffer, mp3DataSize);
}
fwrite(mp3Buffer, encodedBytes, 1, mp3);
5.找到mp3文件播放测试
参考资料:
http://www.cocoachina.com/bbs/read.php?tid=203683
https://blog.csdn.net/jiangyiaxiu/article/details/9190035