转载audio&video音、視頻編解碼

Audio Queue Services 解读之 Playing

2017-01-25  本文已影响744人  gitKong

解读Play Audio下集,如果你没看上集,建议先去看看上集.

Audio Queue Services 解读之 Playing Audio(上)

上集已经准备好音频队列的结构体以及回调函数,那么接下来就可以创建音频队列并实现播放了!

五、Create a Playback Audio Queue(创建播放的音频队列)

下面将演示怎么去创建回放音频队列,注意:AudioQueueNewOutput 函数中使用的自定义结构体和回调方法都是在之前写好了

AudioQueueNewOutput (                                // 1
    &aqData.mDataFormat,                             // 2
    HandleOutputBuffer,                              // 3
    &aqData,                                         // 4
    CFRunLoopGetCurrent (),                          // 5
    kCFRunLoopCommonModes,                           // 6
    0,                                               // 7
    &aqData.mQueue                                   // 8
);

六、Set Sizes for a Playback Audio Queue(设置播放音频队列的大小)

现在,你可以为播放音频队列设置一些大小,当你给缓冲队列分配缓冲区的时候和开始读取音频文件之前,你可以使用这些设置的大小

下面代码将会告诉你怎么设置

(1)、Setting Buffer Size and Number of Packets to Read(设置缓冲区大小和要读取的数据包数)

下面代码段会演示如何使用之前写的 DeriveBufferSize 函数(see Write a Function to Derive Playback Audio Queue Buffer Size)这里是为每一个音频缓冲区设置一个大小,单位是字节;以及确认每次调用回放音频回调要读取的数据包数

此代码使用最大包大小的保守估计,Core Audio通过 kAudioFilePropertyPacketSizeUpperBound 属性提供。 在大多数情况下,最好使用这种方式 - 这是近似但快速的 - 花费时间读取整个音频文件以获得实际的最大包大小

UInt32 maxPacketSize;
UInt32 propertySize = sizeof (maxPacketSize);
AudioFileGetProperty (                               // 1
    aqData.mAudioFile,                               // 2
    kAudioFilePropertyPacketSizeUpperBound,          // 3
    &propertySize,                                   // 4
    &maxPacketSize                                   // 5
);
 
DeriveBufferSize (                                   // 6
    aqData.mDataFormat,                              // 7
    maxPacketSize,                                   // 8
    0.5,                                             // 9
    &aqData.bufferByteSize,                          // 10
    &aqData.mNumPacketsToRead                        // 11
);

下面介绍一下代码的作用:

(2)、Allocating Memory for a Packet Descriptions Array(为包描述数组分配内存)

现在为数组分配内存,以保存一个缓冲区的音频数据的数据包描述。 恒定比特率数据不使用数据包描述,因此下面代码中CBR情形 - 步骤3非常简单。

bool isFormatVBR = (                                       // 1
    aqData.mDataFormat.mBytesPerPacket == 0 ||
    aqData.mDataFormat.mFramesPerPacket == 0
);
 
if (isFormatVBR) {                                         // 2
    aqData.mPacketDescs =
      (AudioStreamPacketDescription*) malloc (
        aqData.mNumPacketsToRead * sizeof (AudioStreamPacketDescription)
      );
} else {                                                   // 3
    aqData.mPacketDescs = NULL;
}

下面介绍代码作用

七、Set a Magic Cookie for a Playback Audio Queue(设置回放音频队列的 Magic Cookie )

一些音频压缩的音频格式,例如 MPEG 4 AAC,利用结构体包含音频的元数据。这些结构体就是Magic Cookie,当你用 Audio Queue Services 播放这种格式的音频文件时,你可以从音频文件中获取Magic Cookie ,然后在播放之前添加到音频队列中

下面代码教你怎么去从音频文件中获取Magic Cookie,并添加到音频队列中,下面的代码需要在开始回放之前执行

UInt32 cookieSize = sizeof (UInt32);                   // 1
bool couldNotGetProperty =                             // 2
    AudioFileGetPropertyInfo (                         // 3
        aqData.mAudioFile,                             // 4
        kAudioFilePropertyMagicCookieData,             // 5
        &cookieSize,                                   // 6
        NULL                                           // 7
    );
 
if (!couldNotGetProperty && cookieSize) {              // 8
    char* magicCookie =
        (char *) malloc (cookieSize);
 
    AudioFileGetProperty (                             // 9
        aqData.mAudioFile,                             // 10
        kAudioFilePropertyMagicCookieData,             // 11
        &cookieSize,                                   // 12
        magicCookie                                    // 13
    );
 
    AudioQueueSetProperty (                            // 14
        aqData.mQueue,                                 // 15
        kAudioQueueProperty_MagicCookie,               // 16
        magicCookie,                                   // 17
        cookieSize                                     // 18
    );
 
    free (magicCookie);                                // 19
}

下面介绍一下代码的作用:

八、Allocate and Prime Audio Queue Buffers(分配和填充音频队列缓冲区)

现在你可以让你之前创建的音频对象去准备一些音频队列缓冲区,下面代码教你怎么做

aqData.mCurrentPacket = 0;                                // 1
 
for (int i = 0; i < kNumberBuffers; ++i) {                // 2
    AudioQueueAllocateBuffer (                            // 3
        aqData.mQueue,                                    // 4
        aqData.bufferByteSize,                            // 5
        &aqData.mBuffers[i]                               // 6
    );
 
    HandleOutputBuffer (                                  // 7
        &aqData,                                          // 8
        aqData.mQueue,                                    // 9
        aqData.mBuffers[i]                                // 10
    );
}

下面介绍代码的作用:

九、Set an Audio Queue’s Playback Gain(设置音频队列回放增益)

在告诉音频队列播放之前,你可以通过音频队列参数机制设置其增益,下面代码教你怎么设置,更多设置可以查看 Audio Queue Parameters

Float32 gain = 1.0;                                       // 1
    // Optionally, allow user to override gain setting here
AudioQueueSetParameter (                                  // 2
    aqData.mQueue,                                        // 3
    kAudioQueueParam_Volume,                              // 4
    gain                                                  // 5
);

下面介绍一下代码的作用:

十、Start and Run an Audio Queue(开启并运行音频队列)

所有上述代码已经播放文件的过程。 这包括在播放文件时启动音频队列并维护运行循环,看下面代码

aqData.mIsRunning = true;                          // 1
 
AudioQueueStart (                                  // 2
    aqData.mQueue,                                 // 3
    NULL                                           // 4
);
 
do {                                               // 5
    CFRunLoopRunInMode (                           // 6
        kCFRunLoopDefaultMode,                     // 7
        0.25,                                      // 8
        false                                      // 9
    );
} while (aqData.mIsRunning);
 
CFRunLoopRunInMode (                               // 10
    kCFRunLoopDefaultMode,
    1,
    false
);

介绍代码作用:

十一、Clean Up After Playing(播放完毕后清除)

当你的音频文件播放完毕,应该要销毁这个音频队列,关闭音频文件,同时要释放所有资源,下面代码处理了这些步骤

AudioQueueDispose (                            // 1
    aqData.mQueue,                             // 2
    true                                       // 3
);
 
AudioFileClose (aqData.mAudioFile);            // 4
 
free (aqData.mPacketDescs);                    // 5

下面介绍一下代码的作用:

十二、总结:

上一篇 下一篇

猜你喜欢

热点阅读