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

http://yangping-account.iteye.com/blog/1114731

使用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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值