PC端音視訊相關應用往往會涉及到系統音頻采集相關需求。例如音視訊通信應用在螢幕共享場景下,使用者除了共享螢幕内容之外,往往需要共享音頻資料。目前macOS沒有系統API可以直接擷取輸出到播放裝置的音頻資料,這就需要通過别的辦法來采集系統音頻。由于macOS開發相關資料較少,完成這個需求也花了點時間,在這裡将思路做個分享,希望能幫助到有這方面需求的朋友。
技術背景
macOS音頻裝置管理
macOS支援管理多個音頻輸入輸出裝置,可以使用“音頻 MIDI 設定”來設定如麥克風和多聲道音頻接口。

音頻 MIDI 設定”界面如上圖所示,左側清單展示了所有音頻輸入輸出裝置,例如内建麥克風、揚聲器、AirPods、通過資料線連接配接端iPhone裝置,右側界面支援調節裝置端具體參數,例如音量等。
我們可以通過右鍵選擇裝置,将其設為系統預設的輸入輸出裝置。設為預設裝置後,裝置清單上會有一個小圖示顯示,同時,系統會預設在對應的裝置上采集、播放音頻資料。當然,應用也依然可以選擇特定裝置采集、播放音頻,例如Abode公司的Audition中可以通過設定選擇輸入輸出裝置。
switchaudio-osx
switchaudio-osx是一款開源項目,支援指令行設定macOS預設輸入輸出音頻裝置。這個開源項目為我們通過代碼切換系統音頻裝置提供了極大幫助。
項目位址:
https://github.com/deweller/switchaudio-osxKEXT核心擴充
KEXT是macOS的核心擴充程式,通常用于系統驅動程式。核心擴充運作于核心态,支援動态加載。
我們可以在Xcode中選擇“general kernel extension”建立核心擴充,基于IOKit接口實作驅動程式,生成的産物以kext作為字尾名。
加載驅動需要首先将kext檔案拷貝到系統目錄(需要管理者權限):
/Library/Extensions
加載驅動:
sudo kextload /path/to/kext.kext
解除安裝驅動:
sudo kextunload /path/to/kext.kext
Soundflower
Soundflower是mac端開源的kext核心擴充程式,它虛拟了一套音頻采集、播放裝置驅動,直接将播放資料傳給采集裝置,實作音頻資料環路。通過将系統預設輸入輸出裝置設定為Soundflower,就可以采集到系統播放的音頻資料。
https://github.com/RogueAmoeba/Soundflower-Original方案實作
介紹完以上的技術背景,其實就可以設計出macOS系統音頻資料采集方案:
如上圖所示,使用者App通過mac系統播放音頻。
我們可以在啟動系統音頻采集功能時将系統音頻播放裝置設定為Soundflower虛拟揚聲器,同時在App中将輸入設為Soundflower虛拟麥克風和硬體麥克風,将混音後的音頻資料輸出到硬體揚聲器。關閉系統音頻采集功能将系統設定還原。理論上,這就已經可以滿足我們的需求了。
關鍵調用流程
為了實作以上方案,有以下關鍵調用流程:
- 第一次調用内錄接口時,請求管理者權限,将Soundflower.kext核心擴充拷貝到系統目錄
- 調用kextload指令加載Soundflower.kext
- 将系統預設音頻播放裝置設定為Soundflower虛拟揚聲器
- App中将音頻采集裝置設定為Soundflower虛拟麥克風
- App中如果有硬體麥克風采集需求,則另起一路硬體麥克風采集
- App中将音頻播放裝置設定為硬體揚聲器
需要關閉該功能時,需要執行如下調用流程:
- 将系統預設輸入輸出裝置還原
- 解除安裝Soundflower.kext
以上調用流程并不複雜,關鍵代碼都可以從以上介紹的開源項目中找到參考,需要注意一下幾點:
加載/解除安裝kext需要系統提權,macOS提權可以選擇
AuthorizationRef或者蘋果官方推薦的
SMJobBless切換系統預設音頻裝置代碼實作可以參考switchaudio-osx項目中
audio_switch.c相關代碼
至于mac端音頻采集播放的代碼實作就相對比較複雜了,不過幸運的是,谷歌WebRTC項目中
audio_device_mac.cc已經有了一套實作
總結
文本提供了macOS采集/錄制系統音頻資料的一種實作思路。具體代碼實作過程中,還是有很多工作需要做的,例如系統提權如果要做的比較友好就需要用到
啟動守護程序來實作。當然,這屬于另外一個話題了,在此不再贅述。