iOS 混音的一種實(shí)現(xiàn)方法

本文已經(jīng)投稿其他地方外莲,本處拒絕轉(zhuǎn)載猪半!

1. 背景

提到混音很多想到的是玩音樂的人用一些專業(yè)的設(shè)備做一些很炫但是看不懂的事情...

圖1. Digital Mixer

在移動直播場景中, 混音可以是用于主播一邊播放音樂, 一邊直播, 也就是一般說的背景音樂功能. 或者是直播連麥中, 將輔播的聲音和主播的聲音混合. 還有在畫中畫等功能中將,視頻的聲音和主播的聲音混合等等. 總之將多路聲音疊加, 對豐富移動直播的內(nèi)容起到了很重要的作用, 是現(xiàn)在移動直播APP必備的基礎(chǔ)功能之一了。

最初的時候, 一般是用其他APP將音樂播放出來, 再通過麥克風(fēng)采集, 利用聲音在空氣中自然的疊加完成混合偷线。這種做法有如下缺點(diǎn):

  1. 主播需要在其他音樂播放器APP中操作磨确,比較繁瑣;
  2. 音樂的聲音也會因?yàn)椴杉a(chǎn)生損耗声邦;
  3. 而且主播帶上耳機(jī)的話,自然混音就無效了乏奥;

其實(shí)所謂混音就是將不同來源的聲音混合在一起, 變成一路音頻信號。移動直播顯然無法使用專門的高大上設(shè)備來做亥曹,那只能在APP內(nèi)來完成邓了。下面我們來看看如何實(shí)現(xiàn)移動平臺上的混音功能。

2. 方案選擇

在沒有混音的場景下, 我們之前的音頻通路是媳瞪,音頻采集模塊將采集到的PCM音頻數(shù)據(jù)送入到音頻編碼器編碼為AAC進(jìn)行直播驶悟。當(dāng)加入混音后,我們面對的是多路音頻輸入材失,經(jīng)過混合后得到一路音頻送入音頻編碼器進(jìn)行編碼。

要在iOS上實(shí)現(xiàn)以上功能, 有好幾種方法可以實(shí)現(xiàn):

  • 系統(tǒng)API來做混音, iOS系統(tǒng)提供了多個層次的音頻處理接口:AudioUnit硫豆、AudioToolBox龙巨、AVFoundation等,從最底層開始就提供了混音模塊, 理論上都能能夠?qū)崿F(xiàn)聲音混合功能熊响。
  • 使用第三方或自己實(shí)現(xiàn)的音頻混合算法旨别。

使用系統(tǒng)API的方案網(wǎng)上的例子比較多, 參考Apple的示例代碼和文檔就好, 這里不詳細(xì)寫。我們主要通過自己實(shí)現(xiàn)的混音模塊來看看混音具體需要做些啥汗茄,并且這種方案對輸入和輸出數(shù)據(jù)的要求最低秸弛,和其他模塊的集成方式最靈活,可以直接以PCM數(shù)據(jù)的形式輸入和輸出。按照相同的實(shí)現(xiàn)思路,也可以跨平臺使用递览。

3. 音頻數(shù)據(jù)

音頻數(shù)據(jù)有兩種存在形式, 一種是壓縮后的, 比如MP3叼屠、AAC等格式的錄音或音樂文件; 另一種是未壓縮的PCM數(shù)據(jù),也就是我們用數(shù)字的形式對自然界中聲音的表示绞铃。聲音的波形非常復(fù)雜,為了描述和記錄聲音,通常我們采用脈沖代碼調(diào)制編碼(PCM編碼). PCM編碼通過抽樣,量化等步驟將連續(xù)的模擬信號轉(zhuǎn)換為離散的數(shù)字信號镜雨。

圖2. pcm 編碼

簡單來講PCM數(shù)據(jù)的格式信息包括如下三個:

  1. 采樣率;
  2. 每個sample的數(shù)據(jù)類型儿捧;
  3. 通道數(shù)和通道排列方式荚坞;

采樣率說的是每秒鐘采樣多少個sample, 也就是一秒鐘的聲音有多少數(shù)據(jù)來描述。采樣率越高表明對聲音的還原度越高菲盾,聲音質(zhì)量就越好颓影,但是相應(yīng)的數(shù)據(jù)量也越大。常見的采樣率是16KHz懒鉴、44.1KHz诡挂、48KHz等。
每個sample的數(shù)據(jù)類型, 比如是否有符號,整數(shù)還是浮點(diǎn)數(shù), 幾個bit表示等. 通常我們在iOS上處理的都是16bit的無符號整數(shù)的音頻疗我。
通道數(shù)主要為了產(chǎn)生立體聲, 現(xiàn)實(shí)中人能夠聽聲辯位主要是靠聲音到達(dá)左右耳的時間差, 在聽音樂時候,如果能夠還原出這種差異,就能有身臨其境的感覺.所以就有了雙通道甚至多通道的音頻數(shù)據(jù). 通道的排列方式主要是說多通道的數(shù)據(jù)是說每個sample交織著放在一起, 還是不同通道的數(shù)據(jù)分塊存放咆畏。

混音算法的處理對象就是這些PCM音頻數(shù)據(jù)。

4. 混音算法

其實(shí)混音的核心部分本來是音頻的疊加, 這一塊的算法和論文都蠻多的, 要實(shí)現(xiàn)好確實(shí)比較難吴裤。但是在直播場景中, 需要混合的聲音路數(shù)比較少, 每一路的音量電平都不太高, 可以直接使用每路音頻的PCM數(shù)據(jù)求和就可以了旧找。
為了調(diào)整每一路聲音在最后聲音中的音量大小,給每個sample乘以一個系數(shù),再做求和.這樣最后采樣的混音算法其實(shí)就是加權(quán)求和。

5. 混音模塊

在選定了混音算法之后, 就需要將該算法封裝為模塊, 集成到直播SDK中. 當(dāng)考慮到實(shí)際的場景的時候, 就面臨了新的問題, 比如聲音格式輸入格式的多樣性. 當(dāng)兩路聲音的格式不同時, 我們就需要對數(shù)據(jù)進(jìn)行轉(zhuǎn)換,得到相同的格式才能最終進(jìn)行PCM的加權(quán)求和. 比如采樣率不同, 那每一秒的數(shù)據(jù)的長度都不一樣, 無法進(jìn)行處理. 當(dāng)兩路聲音產(chǎn)生的頻率不同時,也就是每次送入的sample數(shù)量不同,我們就需要增加buffer來對輸入的數(shù)據(jù)進(jìn)行緩存,比如有的33毫秒一次, 有的50毫秒一次, 那一次就只能處理33毫秒的數(shù)據(jù),50毫秒的數(shù)據(jù)就需要緩存一段, 等下次再處理麦牺。

當(dāng)將以上提到的差異進(jìn)行了處理就得到了如下的模塊結(jié)構(gòu)钮蛛。


圖3. mixer architecture

每一路音頻, 送入混音模塊時,先按照輸出的的格式要求進(jìn)行格式轉(zhuǎn)化(resample), 然后送入pcm buffer中, 輸出模塊, 對每個buffer的長度進(jìn)行監(jiān)控, 當(dāng)滿足輸出條件時, 從每個buffer中取出相同長度的數(shù)據(jù), 進(jìn)行混合,最后輸出剖膳。

其中resampler 可以直接使用ffmpeg中的swresample庫來完成, PCM buffer可以使用循環(huán)buffer或者fifo來實(shí)現(xiàn).

6. 遇到的坑

  1. 輸出的聲音有周期性咔咔聲
    在實(shí)現(xiàn)混音模塊中,當(dāng)輸入和輸出的每次處理的sample數(shù)不同時,需要考慮多種組合的情況,當(dāng)時漏掉了, 輸入比輸出慢的情況, 導(dǎo)致出現(xiàn)buffer常滿,數(shù)據(jù)溢出丟棄,最后觀眾端聲音總是會周期性的咔咔聲. 主要要考慮以下三種情況:
  • 輸入和輸出數(shù)據(jù)的采樣率相同魏颓,此時送入數(shù)據(jù)和回調(diào)數(shù)據(jù)的頻率基本一致;
  • 輸入數(shù)據(jù)采樣率低于輸出數(shù)據(jù)吱晒,此時輸入數(shù)據(jù)頻率比回調(diào)數(shù)據(jù)的頻率低甸饱;
  • 輸入數(shù)據(jù)采樣率高于輸出數(shù)據(jù),此時輸入數(shù)據(jù)頻率比回調(diào)數(shù)據(jù)的頻率高仑濒;

要能夠兼容前兩種情形叹话,我們只需在每次輸入數(shù)據(jù)時檢查buffer中是否有足夠輸出的數(shù)據(jù)量,而要兼容第三種情形墩瞳,則需要內(nèi)部按照buffer中剩余數(shù)據(jù)的長度驼壶,定時向外刷回調(diào)數(shù)據(jù)。當(dāng)前的邏輯是兩者同時存在喉酌,每次數(shù)據(jù)輸入時檢查热凹,并且當(dāng)buffer中剩余數(shù)據(jù)足夠一次輸出時也定時回調(diào)泵喘。

2.只要在xcode中打斷點(diǎn),命中后繼續(xù)執(zhí)行就會出現(xiàn)崩潰

我們模塊中的PCMbuffer是采用的 TPCircularBuffer, 原本我們對buffer進(jìn)行寫入操作時, 只是通過 TPCircularBufferHead接口判斷還有多少空間, 而沒有檢查返回的header指針的有效性。
當(dāng)命中斷點(diǎn)的時候般妙,偶現(xiàn)字節(jié)數(shù)正確纪铺,而header失效的情況,導(dǎo)致在調(diào)試階段出現(xiàn)崩潰股冗,而實(shí)際運(yùn)行過程中沒問題的情況霹陡。該問題只影響了debug,但是具體原因未知止状。

7. 展望

這里采用的混音算法是簡單粗暴的加權(quán)求和, 當(dāng)路數(shù)增加或者其中某一路的音量很高時, 直接求和就會出現(xiàn)超過每個sample所能表示的范圍而溢出,造成爆音烹棉,如果要應(yīng)付更豐富的場景,可能需要更強(qiáng)的算法來支持怯疤。


也歡迎大家使用我們的直播浆洗、短視頻SDK。金山云SDK倉庫地址:

https://github.com/ksvc

金山云SDK相關(guān)的QQ交流群:

  • 視頻云技術(shù)交流群:574179720
  • 視頻云iOS技術(shù)交流:621137661
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末集峦,一起剝皮案震驚了整個濱河市伏社,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塔淤,老刑警劉巖摘昌,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異高蜂,居然都是意外死亡聪黎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進(jìn)店門备恤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稿饰,“玉大人,你說我怎么就攤上這事露泊『砹” “怎么了?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵惭笑,是天一觀的道長侣姆。 經(jīng)常有香客問我,道長沉噩,這世上最難降的妖魔是什么铺敌? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮屁擅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘产弹。我一直安慰自己派歌,他們只是感情好弯囊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胶果,像睡著了一般匾嘱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上早抠,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天霎烙,我揣著相機(jī)與錄音,去河邊找鬼蕊连。 笑死悬垃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的危纫。 我是一名探鬼主播斯稳,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼血柳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了看彼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤囚聚,失蹤者是張志新(化名)和其女友劉穎靖榕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顽铸,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茁计,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了跋破。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片簸淀。...
    茶點(diǎn)故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖毒返,靈堂內(nèi)的尸體忽然破棺而出租幕,到底是詐尸還是另有隱情,我是刑警寧澤拧簸,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布劲绪,位于F島的核電站,受9級特大地震影響盆赤,放射性物質(zhì)發(fā)生泄漏贾富。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一牺六、第九天 我趴在偏房一處隱蔽的房頂上張望颤枪。 院中可真熱鬧,春花似錦淑际、人聲如沸畏纲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盗胀。三九已至艘蹋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間票灰,已是汗流浹背女阀。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屑迂,地道東北人浸策。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像屈糊,于是被迫代替她去往敵國和親的榛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,606評論 2 350

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