这是一篇干货,是直接应用的关于audio queue 播放
先看下面一张运行时的流程原理图:
上图中的步骤:
1、准备播放的音频队列,为每个音频队列缓冲区(Buffer)进行数据填充;
2、当启用AudioQueueStart时,即刻进行播放数据;
3、将队列里第一个缓冲的buffer发送到音频输出区
4、播放队列进入循环模式,音频队列可以进行下一个的音频缓冲区播放
5、回调告诉上层缓冲的buffer已被使用了,然后可以进行下一次的缓冲
6、待上一个已被播放了的音频buffer释放后再次填充buffer
1、设置宏定义
#define MIN_SIZE_PER_FRAME 2000
#define QUEUE_BUFFER_NUM 3
2、定义相关的属性
AudioQueueRef audioQueue;
AudioStreamBasicDescription _audioDescription;
AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_NUM];
BOOL audioqueueBufferUsed[QUEUE_BUFFER_NUM];
NSLock *sysLock;
NSMutableData *tempData;
OSStatus osState;
3、初始化音频播放的参数
_audioDescription.mSampleRate = 8000;//采样率
_audioDescription.mFormatID = kAudioFormatLinearPCM;//音频格式
_audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;//保存音频数据的方式的说明
_audioDescription.mChannelsPerFrame = 1; //1单声道 2双声道
_audioDescription.mFramesPerPacket = 1;//每一个packet指定只有一帧数据,每个数据包的帧数
_audioDescription.mBitsPerChannel = 16;//采样点,语音每个采样点的占用位数
_audioDescription.mBytesPerFrame = (_audioDescription.mBitsPerChannel/8) * _audioDescription.mChannelsPerFrame;
_audioDescription.mBytesPerPacket = _audioDescription.mBytesPerFrame * _audioDescription.mFramesPerPacket;
AudioQueueNewOutput(&_audioDescription, AudioPlayerAQInputCallback, (__bridge void*)self, NULL, kCFRunLoopCommonModes, 0, &audioQueue);
//设置AudioSessionInitialize
// 设置音量
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 1.0);
//初始化缓冲区
for (int i = 0; i < QUEUE_BUFFER_NUM; i++) {
audioqueueBufferUsed[i] = false;
osState = AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);
printf("第 %d 个AudioQueueAllocateBuffer 初始化结果 %d (0表示成功)\n", i + 1, osState);
}
osState = AudioQueueStart(audioQueue, NULL);
if (osState != noErr) {
NSLog(@"Audio Queue Start Failed");
}
4、设置相关的回调函数,用于设置数据的回调
// 回调回来把buffer状态设为未使用
static void AudioPlayerAQInputCallback(void* inUserData,AudioQueueRef audioQueueRef, AudioQueueBufferRef audioQueueBufferRef) {
ECAudioQueuePlayer* player = (__bridge ECAudioQueuePlayer*)inUserData;
[player resetBufferState:audioQueueRef and:audioQueueBufferRef];
}
- (void)resetBufferState:(AudioQueueRef)audioQueueRef and:(AudioQueueBufferRef)audioQueueBufferRef {
for (int i = 0; i < QUEUE_BUFFER_NUM; i++) {
// 将这个buffer设为未使用
if (audioQueueBufferRef == audioQueueBuffers[i]) {
audioqueueBufferUsed[i] = false;
}
}
}
6、输入播放数据
-(void)playWithData:(NSData *)data{
[sysLock lock];
tempData = nil;
tempData = [NSMutableData new];
[tempData appendData:data];
NSUInteger len = tempData.length;
Byte *bytes = (Byte *)malloc(len);
[tempData getBytes:bytes length:len];
int i = 0;
while (true) {
if (!audioqueueBufferUsed[i]) {
audioqueueBufferUsed[i] = true;
break;
}else{
i++;
if (i>=QUEUE_BUFFER_NUM) {
i = 0;
}
}
}
audioQueueBuffers[i]->mAudioDataByteSize = (unsigned int)len;
memcpy(audioQueueBuffers[i]->mAudioData, bytes, len);
free(bytes);
AudioQueueEnqueueBuffer(audioQueue, audioQueueBuffers[i], 0, NULL);
[sysLock unlock];
}