Audio Queue Services 解讀之 Playing Audio(上)

前言:

  • 一直想研究一下Audio Queue Services逊彭,趁著過年這段時(shí)間有空就去研究一下先誉,首選肯定是官方文檔,下面是我讀文檔的時(shí)候翻譯過來怔匣,自己一句一句翻譯可以加深自己的理解記憶雄人,同時(shí)又能方便大家砂沛,何樂而不為谴餐!
  • 由于文檔內(nèi)容較多累舷,本文會(huì)分兩篇介紹蝇摸,避免篇幅過長(zhǎng)橘洞,影響閱讀,Demo會(huì)遲點(diǎn)分享捌袜,敬請(qǐng)期待。

Audio Queue Services 解讀之 Playing Audio(下)

Playing Audio

當(dāng)你使用 Audio Queue Services 播放音頻的時(shí)候炸枣,音頻源可以是任何東西-磁盤文件虏等、基于軟件的音頻合成弄唧、內(nèi)存中的音頻對(duì)象等等,這節(jié)介紹的是播放磁盤文件

注意:本章介紹了基于ANSI-C的播放實(shí)現(xiàn)霍衫,以及一些來自Mac OS X Core Audio SDK的C ++類套才。 對(duì)于基于Objective-C的示例,請(qǐng)參閱 iOS Dev Center 中的SpeakHere示例代碼慕淡。

為你的應(yīng)用添加播放功能背伴,你通常需要實(shí)現(xiàn)下面步驟:

  • 1、定義一個(gè)自定義的結(jié)構(gòu)體峰髓,管理音頻狀態(tài)傻寂、格式和路徑等信息。

  • 2携兵、編寫一個(gè)音頻隊(duì)列回調(diào)函數(shù)來執(zhí)行實(shí)際播放疾掰。

  • 3、編寫代碼以確定音頻隊(duì)列緩沖區(qū)的大小徐紧。

  • 4静檬、打開音頻文件進(jìn)行播放并確定其音頻數(shù)據(jù)格式。

  • 5并级、創(chuàng)建播放音頻隊(duì)列并將其配置為播放拂檩。

  • 6、分配和入隊(duì)音頻隊(duì)列緩沖區(qū)嘲碧, 告訴音頻隊(duì)列開始播放稻励; 完成后,回調(diào)會(huì)指示音頻隊(duì)列停止愈涩。

  • 7望抽、處理音頻隊(duì)列, 釋放資源履婉。


一煤篙、Define a Custom Structure to Manage State

開始之前,先定義一個(gè)自定義的結(jié)構(gòu)體毁腿,用來管理你的音頻樣式和音頻隊(duì)列狀態(tài)信息辑奈,例如:

static const int kNumberBuffers = 3;                              // 1
struct AQPlayerState {
    AudioStreamBasicDescription   mDataFormat;                    // 2
    AudioQueueRef                 mQueue;                         // 3
    AudioQueueBufferRef           mBuffers[kNumberBuffers];       // 4
    AudioFileID                   mAudioFile;                     // 5
    UInt32                        bufferByteSize;                 // 6
    SInt64                        mCurrentPacket;                 // 7
    UInt32                        mNumPacketsToRead;              // 8
    AudioStreamPacketDescription  *mPacketDescs;                  // 9
    bool                          mIsRunning;                     // 10
};

此結(jié)構(gòu)中的大多數(shù)字段與用于記錄的自定義結(jié)構(gòu)中的字段相同(或接近),如定義管理狀態(tài)的Define a Custom Structure to Manage State中的錄音音頻章節(jié)所述狸棍。 例如身害,mDataFormat字段在此用于保存正在播放的文件的格式。 當(dāng)記錄時(shí)草戈,類似字段保存正在寫入磁盤的文件的格式塌鸯。

下面介紹一下結(jié)構(gòu)體中的字段:

  • 1、設(shè)置audio queue buffers 音頻緩存數(shù)唐片,三個(gè)是最好的丙猬,可參考Audio Queue Buffers.

  • 2涨颜、AudioStreamBasicDescription(在CoreAudioTypes.h) 代表正在播放的音頻數(shù)據(jù)格式;mDataFormat字段通過查詢音頻文件的kAudioFilePropertyDataFormat屬性來填充茧球,如Obtaining a File’s Audio Data Format中所述庭瑰。
    有關(guān)AudioStreamBasicDescription結(jié)構(gòu)的詳細(xì)信息,請(qǐng)參閱Core Audio Data Types Reference

  • 3抢埋、你應(yīng)用創(chuàng)建的播放音頻隊(duì)列對(duì)象

  • 4弹灭、存放緩沖對(duì)象 audio queue buffer 的數(shù)組

  • 5、一個(gè)音頻文件對(duì)象揪垄,表示你的程序播放的音頻文件穷吮。

  • 6、每個(gè)緩沖對(duì)象 audio queue buffer 的大屑⑴(以字節(jié)為單位)捡鱼,此值在這些示例中在 DeriveBufferSize 函數(shù)中計(jì)算,在音頻隊(duì)列創(chuàng)建后和啟動(dòng)之前酷愧。詳情看 Write a Function to Derive Playback Audio Queue Buffer Size

  • 7驾诈、表示要從音頻文件播放的下一個(gè)數(shù)據(jù)包的數(shù)據(jù)包索引。

  • 8溶浴、在每次調(diào)用音頻隊(duì)列的播放回調(diào)時(shí)要讀取的數(shù)據(jù)包數(shù)乍迄。 與 bufferByteSize 字段一樣,在創(chuàng)建音頻隊(duì)列之后和啟動(dòng)音頻隊(duì)列之前戳葵,在 DeriveBufferSize 函數(shù)中的這些示例中計(jì)算此值就乓。

  • 9、對(duì)于VBR(可變比特率)音頻數(shù)據(jù)拱烁,正在播放的文件的數(shù)據(jù)包描述數(shù)組。 對(duì)于CBR(恒定比特率)數(shù)據(jù)噩翠,此字段的值為NULL戏自。(VBR 和 CBR 的介紹和區(qū)別

  • 10、表示音頻隊(duì)列是否正在運(yùn)行


二伤锚、 Write a Playback Audio Queue Callback

下一步就是寫一個(gè)音頻隊(duì)列 Audio queue 的回調(diào)函數(shù)擅笔,這個(gè)函數(shù)做了三件事:

  • 1、從音頻文件讀取指定數(shù)量的數(shù)據(jù)屯援,并將其放入音頻隊(duì)列緩沖區(qū)猛们。
  • 2、將音頻隊(duì)列緩沖區(qū) buffers 加入緩沖區(qū)隊(duì)列 audio queue 中狞洋。
  • 3弯淘、當(dāng)沒有更多的數(shù)據(jù)要從音頻文件讀取時(shí),告訴音頻隊(duì)列停止吉懊。

此部分顯示回調(diào)聲明示例庐橙,分別描述每個(gè)任務(wù)假勿,最后呈現(xiàn)整個(gè)回放回調(diào)。 有關(guān)回放回調(diào)的作用的說明态鳖,可以參考下圖转培。


圖

(1)、The Playback Audio Queue Callback Declaration

下面展示的 音頻隊(duì)列 播放回調(diào)實(shí)例聲明浆竭,在AudioQueue.h頭文件中聲明為AudioQueueOutputCallback

static void HandleOutputBuffer (
    void                 *aqData,                 // 1
    AudioQueueRef        inAQ,                    // 2
    AudioQueueBufferRef  inBuffer                 // 3
)

介紹一下方法參數(shù):

  • 1浸须、通常,aqData 是是包含音頻隊(duì)列的狀態(tài)信息的自定義結(jié)構(gòu)(就上面定義的結(jié)構(gòu)體)邦泄,看 Define a Custom Structure to Manage State 所述羽戒。
  • 2、管理這個(gè)回調(diào)的音頻隊(duì)列
  • 3虎韵、一個(gè)音頻隊(duì)列緩沖區(qū)易稠,回調(diào)將通過從音頻文件讀取來填充數(shù)據(jù)。

(2)包蓝、Reading From a File into an Audio Queue Buffer(從文件中讀取到音頻隊(duì)列緩沖區(qū))

回放音頻隊(duì)列回調(diào)的第一個(gè)動(dòng)作是從音頻文件讀取數(shù)據(jù)并將其放置在音頻隊(duì)列緩沖器中驶社。看下面代碼:

AudioFileReadPackets (                        // 1
    pAqData->mAudioFile,                      // 2
    false,                                    // 3
    &numBytesReadFromFile,                    // 4
    pAqData->mPacketDescs,                    // 5
    pAqData->mCurrentPacket,                  // 6
    &numPackets,                              // 7
    inBuffer->mAudioData                      // 8
);

參數(shù)說明:

  • 1测萎、AudioFileReadPackets 函數(shù)聲明在 AudioFile.h 頭文件中亡电,從音頻文件中讀取數(shù)據(jù)并放置到音頻隊(duì)列緩沖區(qū)中
  • 2、要讀取的音頻文件
  • 3硅瞧、當(dāng)讀取的時(shí)候份乒,用 false 來表示函數(shù)不緩存數(shù)據(jù)
  • 4、輸出時(shí)腕唧,從音頻文件讀取的音頻數(shù)據(jù)的字節(jié)數(shù)
  • 5或辖、輸出時(shí),從音頻文件讀取的數(shù)據(jù)的數(shù)據(jù)包描述數(shù)組枣接。 對(duì)于CBR數(shù)據(jù)颂暇,此參數(shù)的輸入值為NULL
  • 6、要從音頻文件讀取的第一個(gè)數(shù)據(jù)包的數(shù)據(jù)包索引
  • 7但惶、輸入時(shí)耳鸯,從音頻文件讀取的數(shù)據(jù)包數(shù)。 輸出時(shí)膀曾,實(shí)際讀取的數(shù)據(jù)包數(shù)
  • 8县爬、輸出時(shí),填充的音頻隊(duì)列緩沖器包含從音頻文件讀取的數(shù)據(jù)

(3)添谊、Enqueuing an Audio Queue Buffer (將音頻隊(duì)列緩沖區(qū) buffers 加入緩沖區(qū)隊(duì)列 audio queue 中)

現(xiàn)在财喳,已經(jīng)從音頻文件讀取數(shù)據(jù)并將其放入音頻隊(duì)列緩沖區(qū)中,回調(diào)將緩沖區(qū)排入隊(duì)列碉钠,如下面代碼所示纲缓。 一旦進(jìn)入緩沖器隊(duì)列卷拘,緩沖器中的音頻數(shù)據(jù)就可供音頻隊(duì)列發(fā)送到輸出設(shè)備

AudioQueueEnqueueBuffer (                      // 1
    pAqData->mQueue,                           // 2
    inBuffer,                                  // 3
    (pAqData->mPacketDescs ? numPackets : 0),  // 4
    pAqData->mPacketDescs                      // 5
);

下面介紹一下參數(shù):

  • 1、AudioQueueEnqueueBuffer 函數(shù)將音頻隊(duì)列緩沖區(qū)添加到緩沖區(qū)隊(duì)列祝高。
  • 2栗弟、管理緩沖區(qū)隊(duì)列的音頻隊(duì)列
  • 3、要入隊(duì)的音頻隊(duì)列緩沖區(qū)buffers
  • 4工闺、音頻隊(duì)列緩沖區(qū)數(shù)據(jù)中表示的數(shù)據(jù)包數(shù)乍赫, 對(duì)于不使用數(shù)據(jù)包描述的CBR數(shù)據(jù),使用0
  • 5陆蟆、對(duì)于使用數(shù)據(jù)包描述的壓縮音頻數(shù)據(jù)格式雷厂,緩沖區(qū)中數(shù)據(jù)包的數(shù)據(jù)包描述

(4)、Stopping an Audio Queue(停止音頻隊(duì)列)

回調(diào)函數(shù)的最后一件事是檢查是否沒有更多的數(shù)據(jù)要從你正在播放的音頻文件中讀取叠殷。 一旦發(fā)現(xiàn)文件的結(jié)尾改鲫,回調(diào)就要告訴播放音頻隊(duì)列停止,看如下代碼處理:

if (numPackets == 0) {                          // 1
    AudioQueueStop (                            // 2
        pAqData->mQueue,                        // 3
        false                                   // 4
    );
    pAqData->mIsRunning = false;                // 5
}

介紹一下代碼:

  • 1林束、通過使用函數(shù) AudioFileReadPackets 檢查是否有數(shù)據(jù)包讀认窦(由回調(diào)早先調(diào)用)
  • 2、使用 AudioQueueStop 函數(shù)停止音頻隊(duì)列
  • 3壶冒、要停止的音頻隊(duì)列
  • 4缕题、是否馬上停止,false的話就當(dāng)所有排隊(duì)緩沖區(qū)都已播放時(shí)胖腾,異步停止音頻隊(duì)列烟零。
  • 5、重置音頻隊(duì)列狀態(tài)不是正在運(yùn)行

(5)咸作、A Full Playback Audio Queue Callback(完整的回調(diào)函數(shù))

static void HandleOutputBuffer (
    void                *aqData,
    AudioQueueRef       inAQ,
    AudioQueueBufferRef inBuffer
) {
    // 官方文檔這里寫的有問題
    //AQPlayerState *pAqData = (AQPlayerState *) aqData;        // 1
    struct AQPlayerState *pAqData = aqData;
    if (pAqData->mIsRunning == 0) return;                     // 2
    UInt32 numBytesReadFromFile;                              // 3
    UInt32 numPackets = pAqData->mNumPacketsToRead;           // 4
    AudioFileReadPackets (
        pAqData->mAudioFile,
        false,
        &numBytesReadFromFile,
        pAqData->mPacketDescs, 
        pAqData->mCurrentPacket,
        &numPackets,
        inBuffer->mAudioData 
    );
    if (numPackets > 0) {                                     // 5
        inBuffer->mAudioDataByteSize = numBytesReadFromFile;  // 6
       AudioQueueEnqueueBuffer ( 
            pAqData->mQueue,
            inBuffer,
            (pAqData->mPacketDescs ? numPackets : 0),
            pAqData->mPacketDescs
        );
        pAqData->mCurrentPacket += numPackets;                // 7 
    } else {
        AudioQueueStop (
            pAqData->mQueue,
            false
        );
        pAqData->mIsRunning = false; 
    }
}

部分代碼介紹:

  • 1锨阿、在實(shí)例化時(shí)提供給音頻隊(duì)列的定制數(shù)據(jù),包括表示要播放的文件的音頻文件對(duì)象(AudioFileID類型)以及各種狀態(tài)數(shù)據(jù)性宏。 請(qǐng)參閱Define a Custom Structure to Manage State群井。
  • 2、如果音頻隊(duì)列停止毫胜,則立即返回。
  • 3诬辈、保存從正在播放的文件中讀取的音頻數(shù)據(jù)的字節(jié)數(shù)的變量酵使。
  • 4、使用從正在播放的文件中讀取的數(shù)據(jù)包數(shù)量初始化 numPackets 變量焙糟。
  • 5口渔、測(cè)試是否從文件中檢索了某些音頻數(shù)據(jù)。 如果是穿撮,則將新填充的緩沖區(qū)排入隊(duì)列缺脉。 如果不是痪欲,停止音頻隊(duì)列。
  • 6攻礼、告訴音頻隊(duì)列緩沖區(qū)結(jié)構(gòu)讀取的數(shù)據(jù)的字節(jié)數(shù)业踢。
  • 7、根據(jù)讀取的數(shù)據(jù)包數(shù)量增加數(shù)據(jù)包索引礁扮。

三知举、Write a Function to Derive Playback Audio Queue Buffer Size(編寫一個(gè)函數(shù)去獲取播放音頻隊(duì)列緩沖區(qū)的大小)

Audio Queue Services 希望你在應(yīng)用里面給你的音頻隊(duì)列緩沖區(qū)指定大小太伊,下面提供的代碼可以導(dǎo)出足夠大的緩沖器大小以容納給定持續(xù)時(shí)間的音頻數(shù)據(jù)雇锡。

創(chuàng)建音頻隊(duì)列后,可以通過調(diào)用 DeriveBufferSize(下面的方法)來作為請(qǐng)求音頻隊(duì)列分配緩沖區(qū)的先決條件僚焦∶烫幔可查看 Set Sizes for a Playback Audio Queue

這里的代碼做了兩個(gè)額外的事情,對(duì)比 Write a Function to Derive Recording Audio Queue Buffer Size 類似的

  • 1芳悲、導(dǎo)出每次回調(diào)調(diào)用 AudioFileReadPackets 函數(shù)時(shí)要讀取的數(shù)據(jù)包數(shù)
  • 2立肘、設(shè)置緩沖區(qū)大小的下限,以避免磁盤訪問頻率過高

這里的計(jì)算考慮了從磁盤讀取的音頻數(shù)據(jù)格式芭概。 格式包括可能影響緩沖區(qū)大小的所有因素赛不,如音頻通道數(shù)

void DeriveBufferSize (
    // 不應(yīng)該有&
    //AudioStreamBasicDescription &ASBDesc,                            // 1
    AudioStreamBasicDescription ASBDesc,
    UInt32                      maxPacketSize,                       // 2
    Float64                     seconds,                             // 3
    UInt32                      *outBufferSize,                      // 4
    UInt32                      *outNumPacketsToRead                 // 5
) {
    static const int maxBufferSize = 0x50000;                        // 6
    static const int minBufferSize = 0x4000;                         // 7
 
    if (ASBDesc.mFramesPerPacket != 0) {                             // 8
        Float64 numPacketsForTime =
            ASBDesc.mSampleRate / ASBDesc.mFramesPerPacket * seconds;
        *outBufferSize = numPacketsForTime * maxPacketSize;
    } else {                                                         // 9
        *outBufferSize =
            maxBufferSize > maxPacketSize ?
                maxBufferSize : maxPacketSize;
    }
 
    if (                                                             // 10
        *outBufferSize > maxBufferSize &&
        *outBufferSize > maxPacketSize
    )
        *outBufferSize = maxBufferSize;
    else {                                                           // 11
        if (*outBufferSize < minBufferSize)
            *outBufferSize = minBufferSize;
    }
 
    *outNumPacketsToRead = *outBufferSize / maxPacketSize;           // 12
}

代碼介紹:

  • 1、音頻隊(duì)列的AudioStreamBasicDescription結(jié)構(gòu)罢洲。
  • 2踢故、播放的音頻文件中數(shù)據(jù)的估計(jì)最大包大小∪敲纾可以通過調(diào)用屬性ID為 kAudioFilePropertyPacketSizeUpperBoundAudioFileGetProperty 函數(shù)(在 AudioFile.h 頭文件中聲明)來確定此值殿较。請(qǐng)參閱Set Sizes for a Playback Audio Queue
  • 3桩蓉、為每個(gè)音頻隊(duì)列緩沖區(qū)指定的大辛芨佟(以秒為單位)。
  • 4院究、輸出時(shí)洽瞬,每個(gè)音頻隊(duì)列緩沖區(qū)的大小(以字節(jié)為單位)业汰。
  • 5伙窃、輸出時(shí),在每次調(diào)用回放音頻隊(duì)列回調(diào)時(shí)從文件讀取的音頻數(shù)據(jù)的數(shù)據(jù)包數(shù)样漆。
  • 6为障、音頻隊(duì)列緩沖區(qū)大小的上限(以字節(jié)為單位)。在此示例中,上限設(shè)置為320 KB鳍怨。這對(duì)應(yīng)于大約5秒的立體聲呻右,24位音頻,采樣率為96kHz鞋喇。
  • 7声滥、音頻隊(duì)列緩沖區(qū)大小的下限(以字節(jié)為單位)。在此示例中确徙,下限設(shè)置為16 KB醒串。
  • 8、對(duì)于定義每個(gè)分組固定數(shù)量的幀的音頻數(shù)據(jù)格式鄙皇,導(dǎo)出音頻隊(duì)列緩沖區(qū)大小芜赌。
  • 9、對(duì)于沒有為每個(gè)分組定義固定數(shù)量的幀的音頻數(shù)據(jù)格式伴逸,基于最大分組大小和你設(shè)置的上限缠沈,導(dǎo)出合理的音頻隊(duì)列緩沖區(qū)大小。
  • 10错蝴、如果導(dǎo)出的緩沖區(qū)大小高于你設(shè)置的上限洲愤,請(qǐng)根據(jù)估計(jì)的最大數(shù)據(jù)包大小調(diào)整綁定。
  • 11顷锰、如果派生的緩沖區(qū)大小低于你設(shè)置的下限柬赐,請(qǐng)將其調(diào)整到綁定。
  • 12官紫、計(jì)算在每次調(diào)用回調(diào)時(shí)從音頻文件讀取的數(shù)據(jù)包數(shù)肛宋。

四、Open an Audio File for Playback(打開音頻文件播放)

現(xiàn)在播放音頻文件只需要下面三個(gè)步驟:

  • 1束世、獲取表示要播放的音頻文件的 CFURL 對(duì)象
  • 2酝陈、打開文件
  • 3、獲取文件的音頻數(shù)據(jù)格式

(1)毁涉、Obtaining a CFURL Object for an Audio File(獲取播放文件的CFURL對(duì)象)

通過下面代碼獲瘸涟铩:

CFURLRef audioFileURL =
    CFURLCreateFromFileSystemRepresentation (           // 1
        NULL,                                           // 2
        (const UInt8 *) filePath,                       // 3
        strlen (filePath),                              // 4
        false                                           // 5
    );

代碼介紹:

  • 1、在 CFURL.h 頭文件中聲明的 CFURLCreateFromFileSystemRepresentation 函數(shù)創(chuàng)建一個(gè)表示要播放的文件的CFURL對(duì)象贫堰。
  • 2穆壕、使用 NULL(或 kCFAllocatorDefault)來使用當(dāng)前的默認(rèn)內(nèi)存分配器。
  • 3其屏、要轉(zhuǎn)換為CFURL對(duì)象的文件系統(tǒng)路徑粱檀。 在生產(chǎn)代碼中,通常從用戶獲取filePath的值漫玄。
  • 4、文件系統(tǒng)路徑中的字節(jié)數(shù)。
  • 5睦优、值為false表示filePath表示文件渗常,而不是目錄。

還有一種方法汗盘,我覺得是比較常用的皱碘,在我demo就使用這個(gè),這個(gè)是通過傳入一個(gè)NSString 路徑實(shí)現(xiàn)的

CFStringRef strRef = (__bridge CFStringRef)filePath;
// CFURLPathStyle 不建議使用kCFURLHFSPathStyle隐孽。 使用HFS樣式路徑的Carbon文件管理器已被棄用癌椿。 HFS樣式路徑不可靠,因?yàn)樗鼈兛梢噪S意引用多個(gè)卷(如果這些卷具有相同的卷名稱)菱阵。 您應(yīng)該盡可能使用kCFURLPOSIXPathStyle踢俄。
    CFURLRef audioFileURL =
    CFURLCreateWithFileSystemPath(NULL,
                                  strRef,
                                  kCFURLPOSIXPathStyle,
                                  YES
                                  );
  • 其中CFURLPathStyle 不建議使用kCFURLHFSPathStyle。 使用HFS樣式路徑的Carbon文件管理器已被棄用晴及。 HFS樣式路徑不可靠都办,因?yàn)樗鼈兛梢噪S意引用多個(gè)卷(如果這些卷具有相同的卷名稱)。 官方建議應(yīng)該盡可能使用這個(gè)

(2)虑稼、Opening an Audio File(打開音頻文件)

下面示例演示怎么去打開一個(gè)音頻文件去播放

AQPlayerState aqData;                                   // 1
 
OSStatus result =
    AudioFileOpenURL (                                  // 2
        audioFileURL,                                   // 3
        fsRdPerm,                                       // 4
        0,                                              // 5
        &aqData.mAudioFile                              // 6
    );
 
CFRelease (audioFileURL); 

代碼解釋:

  • 1琳钉、創(chuàng)建一個(gè) AQPlayerState 自定義結(jié)構(gòu)體實(shí)例(可查看 Define a Custom Structure to Manage State),當(dāng)你打開一個(gè)音頻文件播放的時(shí)候蛛倦,這個(gè)實(shí)例可以控制正在播放的音頻文件(類型是 AudioFileID
  • 2歌懒、AudioFileOpenURL 函數(shù)聲明在 AudioFile.h 頭文件,打開一個(gè)你想播放的音頻文件
  • 3溯壶、CFURLRef 播放引用url
  • 4及皂、你播放的音頻文件所需的文件權(quán)限,可用的文件權(quán)限定義在文件管理 File Access Permission Constants 枚舉中
  • 5茸塞、可選的文件類型提示躲庄。 值為0表示該示例不使用此功能
  • 6、在輸出上钾虐,對(duì)音頻文件的引用被放置在自定義結(jié)構(gòu)的mAudioFile字段中
  • 7噪窘、釋放在步驟1中創(chuàng)建的CFURLRef 對(duì)象

(3)、Obtaining a File’s Audio Data Format(獲取文件的音頻數(shù)據(jù)格式)

上代碼:

UInt32 dataFormatSize = sizeof (aqData.mDataFormat);    // 1
 
AudioFileGetProperty (                                  // 2
    aqData.mAudioFile,                                  // 3
    kAudioFilePropertyDataFormat,                       // 4
    &dataFormatSize,                                    // 5
    &aqData.mDataFormat                                 // 6
);
  • 1效扫、查詢音頻文件的音頻數(shù)據(jù)格式的時(shí)候獲取預(yù)期值
  • 2倔监、AudioFileGetProperty 函數(shù),聲明在 AudioFile.h 頭文件中菌仁,獲取指定音頻文件中屬性的值
  • 3浩习、你想要獲取的音頻數(shù)據(jù)格式的音頻文件對(duì)象,類型是 AudioFileID
  • 4济丘、獲取音頻文件數(shù)據(jù)格式值的屬性ID
  • 5谱秽、在輸入時(shí)洽蛀,描述音頻文件的數(shù)據(jù)格式的AudioStreamBasicDescription結(jié)構(gòu)體的預(yù)期大小疟赊;在輸出時(shí)郊供,實(shí)際大小, 播放應(yīng)用程序不需要使用此值
  • 6近哟、在輸出時(shí)驮审,完整的音頻數(shù)據(jù)格式,以AudioStreamBasicDescription結(jié)構(gòu)體的形式吉执,從音頻文件獲得疯淫。 此行通過將文件的音頻數(shù)據(jù)格式存儲(chǔ)在音頻隊(duì)列的自定義結(jié)構(gòu)中來將其應(yīng)用于音頻隊(duì)列。

下篇將介紹 創(chuàng)建音頻播放隊(duì)列并實(shí)現(xiàn)播放戳玫,會(huì)附上Demo熙掺,前往:Audio Queue Services 解讀之 Playing Audio(下)


歡迎大家關(guān)注我,喜歡就點(diǎn)個(gè)like和star量九,你的支持將是我的動(dòng)力~

翻譯過來的可能有出入适掰,如果大家發(fā)現(xiàn)有什么問題或者寫錯(cuò)的,歡迎留言荠列,謝謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末类浪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肌似,更是在濱河造成了極大的恐慌费就,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件川队,死亡現(xiàn)場(chǎng)離奇詭異力细,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)固额,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門眠蚂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斗躏,你說我怎么就攤上這事逝慧。” “怎么了啄糙?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵笛臣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我隧饼,道長(zhǎng)沈堡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任燕雁,我火速辦了婚禮诞丽,結(jié)果婚禮上鲸拥,老公的妹妹穿的比我還像新娘。我一直安慰自己率拒,他們只是感情好崩泡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著猬膨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呛伴。 梳的紋絲不亂的頭發(fā)上勃痴,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音热康,去河邊找鬼沛申。 笑死,一個(gè)胖子當(dāng)著我的面吹牛姐军,可吹牛的內(nèi)容都是我干的铁材。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奕锌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼著觉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惊暴,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤饼丘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后辽话,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肄鸽,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年油啤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了典徘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡益咬,死狀恐怖逮诲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情础废,我是刑警寧澤汛骂,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站评腺,受9級(jí)特大地震影響帘瞭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒿讥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一蝶念、第九天 我趴在偏房一處隱蔽的房頂上張望抛腕。 院中可真熱鬧,春花似錦媒殉、人聲如沸担敌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽全封。三九已至,卻和暖如春桃犬,著一層夾襖步出監(jiān)牢的瞬間刹悴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工攒暇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留土匀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓形用,卻偏偏與公主長(zhǎng)得像就轧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子田度,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容