您的位置:首页 > 产品设计 > UI/UE

AudioQueue来实现音频播放功能时最主要的步骤

2013-08-02 09:04 686 查看
AudioQueue是Mac
OS X与iPhone中提供录音、播放功能的高级框架,比AudioUnit等框架更方便,而且不要求掌握更多专门的知识。

从AudioQueue的名称就可以看出,AudioQueue框架以队列的形式处理音频数据。因此使用时需要给队列分配缓存空间,由回调(Callback)函数完成向队列缓存读写音频数据的功能。另外,AudioQueue是AudioToolbox框架的一部分,使用前需要将AudioToolbox框架导入进来。

使用AudioQueue来实现音频播放功能时最主要的步骤,可以更简练的归纳如下。

1. 打开播放音频文件

2. 取得播放音频文件的数据格式

3. 准备播放用的队列

4. 将缓冲中的数据移动到队列中

5. 开始播放

6. 在回调函数中进行队列处理

以下是贯彻上述六个主要步骤的代码实例,只需要向[play:]中传入音频文件的路径就可以开始音频播放。稍加修改可以直接应用到自己的程序中。

Source Audioplay.h

#import <Foundation/Foundation.h>

#import <AudioToolbox/AudioToolbox.h>

#import <AudioToolbox/AudioFile.h>

#define NUM_BUFFERS 3

@interface AudioPlayer : NSObject {

//播放音频文件ID

AudioFileID audioFile;

//音频流描述对象

AudioStreamBasicDescription dataFormat;

//音频队列

AudioQueueRef queue;

SInt64 packetIndex;

UInt32 numPacketsToRead;

UInt32 bufferByteSize;

AudioStreamPacketDescription *packetDescs;

AudioQueueBufferRef buffers[NUM_BUFFERS];

}

//定义队列为实例属性

@property AudioQueueRef queue;

//播放方法定义

- (void) play:(CFURLRef) path;

//定义缓存数据读取方法

- (void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue

queueBuffer:(AudioQueueBufferRef)audioQueueBuffer;

//定义回调(Callback)函数

static void BufferCallback(void *inUserData, AudioQueueRef inAQ,

AudioQueueBufferRef
buffer);

//定义包数据的读取方法

- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;

@end

Source Audioplay.m

static UInt32 gBufferSizeBytes = 0x10000;

@implementation AudioPlayer

@synthesize queue;

// 回调(Callback)函数的实现

static void BufferCallback(void *inUserData, AudioQueueRef inAQ,

AudioQueueBufferRef buffer) {

AudioPlayer* player = (AudioPlayer*)inUserData;

[player audioQueueOutputWithQueue:inAQ
queueBuffer:buffer];

}

//初始化方法(为NSObject中定义的初始化方法)

- (id) init {

for(int i=0; i<NUM_BUFFERS; i++) {

AudioQueueEnqueueBuffer(queue,buffers[i],0,nil);

}

return self;

}

//缓存数据读取方法的实现

- (void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue

queueBuffer:(AudioQueueBufferRef)audioQueueBuffer
{

OSStatus status;

// 读取包数据

UInt32 numBytes;

UInt32 numPackets
= numPacketsToRead;

status = AudioFileReadPackets(

audioFile,
NO, &numBytes, packetDescs,

packetIndex,
&numPackets, audioQueueBuffer->mAudioData);

// 成功读取时

if (numPackets > 0) {

//将缓冲的容量设置为与读取的音频数据一样大小(确保内存空间)

audioQueueBuffer->mAudioDataByteSize = numBytes;

// 完成给队列配置缓存的处理

status = AudioQueueEnqueueBuffer(

audioQueue,
audioQueueBuffer, numPackets, packetDescs);

// 移动包的位置

packetIndex += numPackets;

}

}

//音频播放方法的实现

-(void) play:(CFURLRef) path {

UInt32 size,
maxPacketSize;

char *cookie;

int i;

OSStatus status;

// 打开音频文件

status = AudioFileOpenURL(path, kAudioFileReadPermission, 0, &audioFile);

if (status != noErr) {

// 错误处理

return;

}

// 取得音频数据格式

size = sizeof(dataFormat);

AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat,

&size,
&dataFormat);

// 创建播放用的音频队列

AudioQueueNewOutput(&dataFormat, BufferCallback,

self,
nil, nil, 0, &queue);

//计算单位时间包含的包数

if (dataFormat.mBytesPerPacket==0 || dataFormat.mFramesPerPacket==0) {

size = sizeof(maxPacketSize);

AudioFileGetProperty(audioFile,

kAudioFilePropertyPacketSizeUpperBound,
&size, &maxPacketSize);

if (maxPacketSize > gBufferSizeBytes) {

maxPacketSize = gBufferSizeBytes;

}

// 算出单位时间内含有的包数

numPacketsToRead = gBufferSizeBytes / maxPacketSize;

packetDescs = malloc(

sizeof(AudioStreamPacketDescription)
* numPacketsToRead);

} else {

numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket;

packetDescs = nil;

}

//设置Magic
Cookie,参见第二十七章的相关介绍

AudioFileGetPropertyInfo(audioFile,

kAudioFilePropertyMagicCookieData,
&size, nil);

if (size > 0) {

cookie = malloc(sizeof(char) * size);

AudioFileGetProperty(audioFile,

kAudioFilePropertyMagicCookieData,
&size, cookie);

AudioQueueSetProperty(queue,

kAudioQueueProperty_MagicCookie,
cookie, size);

free(cookie);

}

// 创建并分配缓存空间

packetIndex = 0;

for (i = 0; i < NUM_BUFFERS; i++) {

AudioQueueAllocateBuffer(queue, gBufferSizeBytes,
&buffers[i]);

//读取包数据

if ([self readPacketsIntoBuffer:buffers[i]] == 0)
{

break;

}

}

Float32 gain = 1.0;

//设置音量

AudioQueueSetParameter (

queue,

kAudioQueueParam_Volume,

gain

);

//队列处理开始,此后系统会自动调用回调(Callback)函数

AudioQueueStart(queue, nil);

}

- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer {

UInt32 numBytes,
numPackets;

// 从文件中接受包数据并保存到缓存(buffer)中

numPackets = numPacketsToRead;

AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs,

packetIndex,
&numPackets, buffer->mAudioData);

if (numPackets > 0) {

buffer->mAudioDataByteSize = numBytes;

AudioQueueEnqueueBuffer(queue, buffer,

(packetDescs
? numPackets : 0), packetDescs);

packetIndex += numPackets;

}

return numPackets;

}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: