iOS在線音頻流播放

前言

這是一篇關(guān)于在線音頻播放的文章柜候,參考自蘋果OS X的demo搞动。
在移植到iOS后,可以通過iphone播放Mac上面的音頻渣刷,實現(xiàn)在線播放音頻的功能鹦肿。
本文可以學(xué)習(xí)到socket編程AudioFileStream轉(zhuǎn)換音頻流辅柴、AudioQueue播放音頻箩溃、信號量的使用瞭吃。

正文

demo有兩個工程,分別是serversclient涣旨。
servers是OS X的應(yīng)用歪架,作為服務(wù)端,負(fù)責(zé)發(fā)送音頻流數(shù)據(jù)霹陡;
client是iOS的應(yīng)用和蚪,作為客戶端,負(fù)責(zé)接收音頻流數(shù)據(jù)烹棉;
音頻數(shù)據(jù)通過AudioFileStream轉(zhuǎn)換后攒霹,調(diào)用AudioQueue進(jìn)行播放,中間會用到信號量進(jìn)行等待和同步浆洗。

1催束、socket編程

bind方法用于綁定接口,然后用listen監(jiān)聽tcp連接請求伏社,accept用于接受tcp連接泣崩;
fopen打開音頻文件,fread讀取音頻數(shù)據(jù)洛口,send對建立的連接發(fā)送音頻流矫付;

對已經(jīng)失效的socket,send兩次數(shù)據(jù)就會觸發(fā)SIGPIPE信號第焰,默認(rèn)的處理是關(guān)閉進(jìn)程买优。

// 打開文件
FILE* file = fopen([[[NSBundle mainBundle] pathForResource:@"chenli" ofType:@"mp3"] UTF8String], "r");
// 創(chuàng)建socket
int listener_socket = socket(AF_INET, SOCK_STREAM, 0);
// 綁定socket
bind(listener_socket, (struct sockaddr*)&server_sockaddr, sizeof(server_sockaddr));
// 監(jiān)聽tcp連接
listen(listener_socket, 4);
// 接收tcp連接,注意挺举!這里并不是三次握手杀赢。
int connection_socket = accept(listener_socket, (struct sockaddr*)&client_sockaddr, &client_sockaddr_size);
// 讀取文件
size_t bytesRead = fread(buf, 1, 32768, file);
// 發(fā)送音頻流
ssize_t bytesSent = send(connection_socket, buf, bytesRead, 0);
// 關(guān)閉socket
close(connection_socket);
2、AudioQueue播放音頻

AudioQueue的播放時湘纵,需要先給audioBuffer填充數(shù)據(jù)脂崔,并把a(bǔ)udioBuffer放入AudioQueue,然后通知AudioQueue開始播放梧喷;
AudioQueue從已經(jīng)填充的audioBuffer里面開始播放數(shù)據(jù)砌左,實時把播放完畢的audioBuffer回調(diào)給業(yè)務(wù)層,業(yè)務(wù)繼續(xù)填充播放完畢的audioBuffer铺敌,重復(fù)流程直到音頻播放完畢汇歹。

前文使用AudioToolbox播放AAC有對AudioQueue更詳細(xì)的介紹以及更簡化的demo。

配置AudioQueue

// 添加AudioQueue的回調(diào)函數(shù)和添加參數(shù)偿凭,MyAudioQueueOutputCallback是播完結(jié)束的回調(diào)
AudioQueueNewOutput(&asbd, MyAudioQueueOutputCallback, myData, NULL, NULL, 0, &audioQueue);
// AudioBuffer分配buffer
AudioQueueAllocateBuffer(audioQueue, kAQBufSize, &audioQueueBuffer[i]);
// 添加AudioQueue的屬性監(jiān)聽
AudioQueueAddPropertyListener(audioQueue, kAudioQueueProperty_IsRunning, MyAudioQueueIsRunningCallback, myData);

開始播放

// 開始AudioQueue播放
AudioQueueStart(myData->audioQueue, NULL);
// 向AudioQueue傳入buffer
AudioQueueEnqueueBuffer(audioQueue, fillBuf, (UInt32)myData->packetsFilled, packetDescs);

播放結(jié)束

// 傳入最后的音頻數(shù)據(jù)后需要調(diào)用产弹,否則buffer里面的數(shù)據(jù)可能會影響下次播放
AudioQueueFlush(audioQueue);
// 如果需要停止播放,可以調(diào)用這個函數(shù)弯囊,第二個參數(shù)表示同步/異步
AudioQueueStop(audioQueue, false);
// 播放完畢痰哨,銷毀隊列
AudioQueueDispose(audioQueue, false);
3胶果、互斥鎖

普通鎖
pthread_mutex_lock(mutex) 加鎖,可能會阻塞斤斧;
pthread_mutex_unlock(mutex) 解鎖稽物;

條件鎖(pthread_cond_wait)
調(diào)用pthread_cond_wait時,條件不成立則阻塞折欠,直到條件成立贝或;
調(diào)用pthread_cond_wait前,要先調(diào)用pthread_mutex_lock(mutex)加鎖锐秦,pthread_cond_wait會在調(diào)用結(jié)束解鎖mutex咪奖;
pthread_cond_wait條件滿足后(pthread_cond_signal被調(diào)用),會對mutex加鎖酱床,當(dāng)我們執(zhí)行完程序時需要對mutex解鎖羊赵;

調(diào)用pthread_cond_wait時,為了防止并發(fā)放入阻塞隊列扇谣,所以需要提前對mutex加鎖昧捷;

申請條件鎖

pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);

釋放條件鎖

pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
4、AudioFileStream轉(zhuǎn)換音頻流

AudioFileStream可以用來讀取音頻流信息和分離音頻幀罐寨,與之類似的API簇還有AudioFile和ExtAudioFile靡挥。
AudioFileStream可以用在線音頻流,也可以使用本地文件鸯绿。

// 打開一個音頻流轉(zhuǎn)換器跋破,需要設(shè)置AudioFileStream_PropertyListenerProc 和 AudioFileStream_PacketsProc 回調(diào)函數(shù);
AudioFileStreamOpen(myData, MyPropertyListenerProc, MyPacketsProc, kAudioFileAAC_ADTSType, &audioFileStream);

// AudioFileStreamParseBytes 解析數(shù)據(jù)瓶蝴,會調(diào)用之前設(shè)置好的AudioFileStream_PropertyListenerProc 和 AudioFileStream_PacketsProc 回調(diào)函數(shù)毒返;
AudioFileStreamParseBytes(myData->audioFileStream, (UInt32)bytesRecvd, buf, 0);

// 獲取特定的屬性
AudioFileStreamGetProperty(inAudioFileStream, kAudioFileStreamProperty_DataFormat, &asbdSize, &asbd);

// 關(guān)閉音頻流
AudioFileStreamClose(audioFileStream);

附錄

demo中用到用到的一些方法:
AudioFileStreamParseBytes 解析數(shù)據(jù),會調(diào)用之前設(shè)置好的AudioFileStream_PropertyListenerProcAudioFileStream_PacketsProc 回調(diào)函數(shù)舷手;
AudioFileStreamOpen 打開一個音頻流轉(zhuǎn)換器拧簸,需要設(shè)置AudioFileStream_PropertyListenerProcAudioFileStream_PacketsProc 回調(diào)函數(shù);
MyPropertyListenerProc 音頻屬性回調(diào)函數(shù)男窟;
MyPacketsProc 數(shù)據(jù)回調(diào)函數(shù)盆赤;
MyEnqueueBuffer 把buffer里面的數(shù)據(jù)傳入AudioQueue;
WaitForFreeBuffer 當(dāng)前所有buffer已經(jīng)占用滿蝎宇,等待AudioQueue播放完釋放buffer弟劲;
MyAudioQueueOutputCallback AudioQueue釋放buffer的回調(diào)函數(shù);
MyAudioQueueIsRunningCallback AudioQueue是否在播放的回調(diào)函數(shù)姥芥;
MyConnectSocket 建立socket鏈接
demo 的代碼地址在這里傳送門

demo的打開方式:
server是服務(wù)端汇鞭,運行在OS X
有binary和app兩種方式

  • binary需要編譯完之后凉唐,找到二進(jìn)制所在的目錄庸追,在其目錄下放對應(yīng)的音頻文件;
  • app打開台囱,保持運行淡溯;

client是客戶端,運行在iOS

  • 1簿训、在getHostName處需要修改為OS X的ip地址咱娶;
  • 2、iOS和OS X需要處于同一局域網(wǎng)强品;
  • 3膘侮、clietn未播放完結(jié)束,會導(dǎo)致server關(guān)閉的榛;

總結(jié)

這個demo很有意思:用到很多知識點琼了,而且很簡單,非常適合學(xué)習(xí)夫晌。
最近越來越忙雕薪,如果有問題可以評論或者簡信聯(lián)系,盡量清楚點描述問題還有問題的上下文晓淀。

前文系列所袁,或許會有興趣。
使用VideoToolbox硬編碼H.264
使用VideoToolbox硬解碼H.264
使用AudioToolbox編碼AAC
使用AudioToolbox播放AAC
HLS點播實現(xiàn)(H.264和AAC碼流)
HLS推流的實現(xiàn)(iOS和OS X系統(tǒng))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凶掰,一起剝皮案震驚了整個濱河市纲熏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锄俄,老刑警劉巖局劲,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異奶赠,居然都是意外死亡鱼填,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門毅戈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苹丸,“玉大人,你說我怎么就攤上這事苇经∽咐恚” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵扇单,是天一觀的道長商模。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么施流? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任响疚,我火速辦了婚禮,結(jié)果婚禮上瞪醋,老公的妹妹穿的比我還像新娘忿晕。我一直安慰自己,他們只是感情好银受,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布践盼。 她就那樣靜靜地躺著,像睡著了一般宾巍。 火紅的嫁衣襯著肌膚如雪咕幻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天蜀漆,我揣著相機(jī)與錄音谅河,去河邊找鬼。 笑死确丢,一個胖子當(dāng)著我的面吹牛绷耍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鲜侥,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼褂始,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了描函?” 一聲冷哼從身側(cè)響起崎苗,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舀寓,沒想到半個月后胆数,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡互墓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年必尼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篡撵。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡判莉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出育谬,到底是詐尸還是另有隱情券盅,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布膛檀,位于F島的核電站锰镀,受9級特大地震影響娘侍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜互站,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一私蕾、第九天 我趴在偏房一處隱蔽的房頂上張望僵缺。 院中可真熱鬧胡桃,春花似錦、人聲如沸磕潮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽自脯。三九已至之景,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間膏潮,已是汗流浹背锻狗。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留焕参,地道東北人轻纪。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像叠纷,于是被迫代替她去往敵國和親刻帚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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