//
// audioQueuePlayer.m
// live
//
// Created by lujunjie on 2016/11/4.
// Copyright © 2016年 lujunjie. All rights reserved.
//
#import "AudioQueuePlayer.h"
#import <AudioToolbox/AudioToolbox.h>
#define QUEUE_BUFFER_SIZE 10 //队列缓冲个数
#define MIN_SIZE_PER_FRAME 2000 //每帧最小数据长度
@interface AudioQueuePlayer()
{
NSLock *synlock ;//同步控制
AudioQueueRef audioQueue;//音频播放队列
BOOL audioQueueUsed[QUEUE_BUFFER_SIZE]; //音频缓存是否在使用中
AudioStreamBasicDescription audioDescription;//音频参数
AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_SIZE];//音频缓冲
}
@end
@implementation AudioQueuePlayer
- (instancetype)init
{
if (self=[super init]) {
[self reset];
}
return self;
}
- (void)reset
{
[self stop];
synlock = [[NSLock alloc] init];
///设置音频参数
audioDescription.mSampleRate = 8000; //采样率
audioDescription.mFormatID = kAudioFormatLinearPCM;
audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioDescription.mChannelsPerFrame = 1; ///单声道
audioDescription.mFramesPerPacket = 1; //每一个packet一侦数据
audioDescription.mBitsPerChannel = 16; //每个采样点16bit量化
audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel / 8) * audioDescription.mChannelsPerFrame;
audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame;
AudioQueueNewOutput(&audioDescription, audioPlayerAQInputCallback, (__bridge void*)self, nil, nil, 0, &audioQueue); //使用player的内部线程播放
//初始化音频缓冲区
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);
}
}
- (void)stop
{
if (audioQueue) {
AudioQueueStop(audioQueue, true);
AudioQueueReset(audioQueue);
audioQueue = nil;
}
}
- (void)play:(void*)pcmData length:(unsigned int)length
{
if (audioQueue == nil || ![self checkBufferHasUsed]) {
// 第一次使用
[self reset];
AudioQueueStart(audioQueue, NULL);
}
[synlock lock];
AudioQueueBufferRef audioQueueBuffer = NULL;
while (true) {
audioQueueBuffer = [self getNotUsedBuffer];
if (audioQueueBuffer != NULL) {
break;
}
}
audioQueueBuffer->mAudioDataByteSize = length;
Byte* audiodata = (Byte*)audioQueueBuffer->mAudioData;
for (int i = 0; i < length; i++) {
audiodata[i] = ((Byte*)pcmData)[i];
}
AudioQueueEnqueueBuffer(audioQueue, audioQueueBuffer, 0, NULL);
[synlock unlock];
}
static void audioPlayerAQInputCallback(void *input, AudioQueueRef audioQueue, AudioQueueBufferRef audioQueueBuffers)
{
AudioQueuePlayer *player = (__bridge AudioQueuePlayer*)input;
[player playerCallback:audioQueueBuffers];
}
// 是不是有缓冲在使用中
- (BOOL)checkBufferHasUsed
{
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
if (YES == audioQueueUsed[i]) {
return YES;
}
}
return NO;
}
// 获取没有在使用的缓冲
- (AudioQueueBufferRef)getNotUsedBuffer
{
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
if (NO == audioQueueUsed[i]) {
audioQueueUsed[i] = YES;
return audioQueueBuffers[i];
}
}
return NULL;
}
// 标志缓冲空闲中
- (void)playerCallback:(AudioQueueBufferRef)outQB
{
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
if (outQB == audioQueueBuffers[i]) {
audioQueueUsed[i] = NO;
}
}
}
@end