2010年9月21日 星期二

iPhone Live audio streaming using AudioQueue


原本用AVAudioPlayer來播放一些音效感覺很方便,
可是要播放即時的音訊串流就沒輒了.
請見 Technical Q&A QA1634

好吧~那就自立自強捲起袖子… 趕緊google阿!
不過google大神給的答案實在很朦朧,
勉勉強強找到的殘破程式碼也有看沒有懂.

幸好天無絕人之路 :)
Apress出的iPhone cool projects這本書第六章有寫捏,
又有source code可以run,實在"揪甘心"阿.



官方網



















範例程式:下載

如果剛點開範例程式,跟我一樣有頭暈眼花的症狀.
那不用擔心,沒有這麼難,看完下面解釋說不定就懂了.

從架構上來講,一共分成三個部分:

1. AudioPlayer跟AudioRequest可以視作一個大項
    主要負責下達URLrequest,並將收到的data回傳給AudioStream
    另外就是擔任AudioStream的委託(delegate)去使用AudioQueue

2. AudioStream有三件主要的事情
    * 將一收到的data進行parse並得到StreamID
    * 有了StreamID之後會分成 propertyCallback與packetCallback
       先講propertyCallback, 其目的顧名思義就是要辨識Audio的屬性
       就想像成一段資料收進來,需要貼上標籤,註明格式,頻率等等
    * packetCallback會將收進來的stream分成數個packet
       然後請委託(delegate)幫忙執行AudioQueue的程式部分

3. AudioQueue會接受來自委託(delegate)的幾件事情
    * AudioQueueNewOutput會產生一個新的playback audio queue物件
    * AudioQueuePlay會開始播放AudioQueue裡頭的音訊
    * 上述兩項是延續自propertyCallback的部份,在packetCallback這邊
       因為有一整段stream的大小,所以透過AudioQueueAllocateBuffer給定
       適當的buffer size後,使用AudioQueueEnqueueBuffer一直塞buffer
       到audio queue就會播出我們要的串流音訊啦!


NOTE: 2011/01/10
這個範例被我拿來改用之後發現有memory allocation的問題
我原以為是我改壞了 才造成memory allocation不斷飆升的情況
最近花了一點時間修改一下 發現問題就出在AudioQueueAllocateBuffer
這個function不應該在data每次進來都做一次
如果好好看過Apple提供的playback示意圖
AudioQueueAllocateBuffer只會在AudioQueue宣告出來後指定好

講是這樣講啦~
實際測試了一下書中範例給的mp3
neilmix[dot]com[slash]book[slash]etude[dot]mp3
嗯…一切自我感覺良好,沒有問題
換成linear PCM格式的wav source…結果是"大崩壞"!
追了很久發現有一個叫packetDescription的structure資料全都是null,
難怪在memory copy時都會造成crash.

所以精華來啦~
1. 這邊mp3的audio stream是VBR格式,也就是說每個packet大小可能不一,
    因此packetDescription會特別記錄這些資訊.
    linear PCM的wav是CBR格式自然沒有這些資料,
    所以簡單的方法就是把packetDescriptions copy這段註解掉.

1
2
3
4
5
memcpy(outBufferRef->mAudioData, data.bytes, data.length);
outBufferRef->mAudioDataByteSize = data.length;
//memcpy(outBufferRef->mPacketDescriptions, packetDescriptions, 
  sizeof(AudioStreamPacketDescription) * packetCount); 
outBufferRef->mPacketDescriptionCount = packetCount;


2. 由於CBR格式中的bit rate是固定關係, AudioQueueEnqueueBuffer後兩個
    參數為0,跟NULL.

3. 總結來講,AudioQueue service是精隨.只要搞清楚流程,一邊餵進Audio基本資料
    另一邊allocate好audio queue把data依序塞進去,輕鬆播放串流音訊非難事!

參考資料: iOS Reference Library
                zonble
                cocoaChina
                stackoverflow (synthesize with CoreAudio)
                stackoverflow (iPhone combine audio files)    

歐~差點忘了,
在iOS4的simulator環境下跑,開始的時候都會頓一下
log會出現"AddRunningClient starting device on non-zero client count"訊息
雖然不會造成什麼大問題,不過這樣卡卡真的有點討厭就是了
網路上一片無解阿~討論串

1 則留言:

  1. 感謝 Jing Jong 大大....這篇對我現在的專案幫助很大...^^

    回覆刪除

內容回應