首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

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

2012-06-29 
AudioQueue来实现音频播放功能时最主要的步骤使用AudioQueue来实现音频播放功能时最主要的步骤,可以更简练

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

使用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,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);

????????//读取包数据
????????if ([self readPacketsIntoBuffer:buffers] == 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

热点排行