
文章目錄
- 一. 前言
- 二. 開發環境
- 三. 具體操作
- 四. 實際效果
一. 前言
起因是這樣的,我需要在Ubuntu中,實時讀取正在播放音樂的音頻流,然后對音頻進行相關的處理。本來打算使用的Pipewire+Helvum
的方式實現,好處是可以直接利用Helvum圖形化工具對軟件輸出的音頻進行重定向,但是由于使用的是Ubuntu20.04
,默認的音頻服務器使用的是PulseAudio,替換為Pipewire后,播放的音頻會出現卡頓不流暢,最終還是使用原生的PulseAudio+pavucontrol
來實現實時播放的音頻的處理。
二. 開發環境
Ubuntu: Ubuntu 20.04.6 LTS
虛擬機: VMware Workstation 17 Pro
音頻服務器: PluseAudio
音頻IO庫: Portaudio
音頻驅動: Alsa
開發語言: C/C++
三. 具體操作
舉個例子,我們需要在Ubuntu中實時獲取QQ音樂目前正在播放的音頻流,我們需要按如下步驟進行操作:
1. 創建虛擬設備:
pactl load-module module-null-sink sink_name=music sink_properties=device.description="Virtual_Music_Sink"
終端輸入指令,通過加載module-null-sink
模塊,PulseAudio 創建了一個虛擬的音頻輸出設備,其名稱為 “music”。該虛擬設備不會直接輸出聲音,但它會自動生成一個監控源,記錄所有發送到該虛擬設備的音頻數據。
指令部分 | 作用 |
---|---|
pactl | PulseAudio 控制工具(PulseAudio Control) |
load-module | 加載一個 PulseAudio 模塊 |
module-null-sink | 加載 Null Sink 模塊,創建一個虛擬音頻輸出設備 |
sink_name=music | 指定新創建的虛擬設備名稱為 music |
sink_properties=device.description=“Virtual_Music_Sink” | 設置設備的描述信息,在pavucontrol中顯示為 “Virtual_Music_Sink” |
2. 設置 QQ 音樂的音頻輸出:

pavucontrol
終端輸入指令,pavucontrol
打開(PulseAudio 音量控制工具),在 “Playback” 選項卡中將 QQ 音樂的輸出設備改為你剛創建的 “music” 虛擬設備。
3. 將虛擬設備輸出到揚聲器中:
為了保證你能聽到音頻,還需要把虛擬設備"music" 的音頻輸出送到物理揚聲器。這可以通過加載module-loopback
環回模塊實現:
pactl load-module module-loopback source=music.monitor sink=alsa_output.pci-0000_02_02.0.analog-stereo
部分 | 作用 |
---|---|
pactl | PulseAudio 控制工具(PulseAudio Control) |
load-module | 加載一個 PulseAudio 模塊 |
module-loopback | 加載 Loopback 模塊,用于將音頻流從一個設備轉發到另一個設備 |
source=music.monitor | 指定 音頻來源 為 music.monitor(虛擬設備 music 的監控源) |
sink=alsa_output.pci-0000_02_02.0.analog-stereo | 指定音頻目標為 alsa_output.pci-0000_02_02.0.analog-stereo(物理揚聲器) |
需要注意的是:sink后面的物理揚聲器信息需要根據自己的電腦來定。
4. 在 PortAudio 中捕捉音頻:
// PortAudio回調函數
static int paCallback(const void* inputBuffer, void* outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo* timeInfo,PaStreamCallbackFlags statusFlags,void* userData)
{return paContinue;
}int main()
{PaStreamParameters inputParameters;inputParameters.device = Pa_GetDefaultInputDevice();inputParameters.channelCount = 1; inputParameters.sampleFormat = paFloat32; const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(inputParameters.device);inputParameters.suggestedLatency = deviceInfo->defaultLowInputLatency;inputParameters.hostApiSpecificStreamInfo = nullptr;PaStream* stream = nullptr;Pa_OpenStream(&stream,&inputParameters,nullptr, // 不使用輸出流SAMPLE_RATE,FRAMES_PER_BUFFER,paNoFlag,paCallback,nullptr);Pa_StartStream(stream);while(1){}
}
5. pavucontrol修改程序音頻入口:

打開pavucontrol后,在Recording中,把啟動的應用程序的輸入入口修改為Virtual_Music_Sink,這樣就把程序的錄音入口修改為我們的虛擬設備,由于前面我們使用load-module環回模塊,已將QQ音樂中的輸出重定向至Virtual_Music_Sink虛擬設備中,那么此時,Portaudio收到的input設備獲得的音頻流便是QQ音樂輸出的音頻流。
四. 實際效果
通過上述操作,我們可以采集到的QQ音樂中播放的音頻,我們實時去捕捉音頻中的節奏點,再通過Implot畫出實時的歌曲的音頻曲線和節奏信息,效果如下:

如果希望捕獲的音頻流的延時更低,可以將Ubuntu的內核版本替換為lowlatency低延時版本(默認是Generic Kernel),具體的操作可以參考這篇文章:Ubuntu切換lowlatency內核教程。