Skype 憑藉優異語音品質成為全球熱門通訊軟體。早期版本缺乏內建錄音功能,筆者於 2006 年針對業務需求,研究並實作了一套 Skype 錄音與自動答錄機系統。本文揭秘其核心編程思路與關鍵代碼,為音頻編程愛好者提供參考。
嘗試用標準錄音 API(選取「立體聲混音」錄對方、「麥克風」錄自己)會發現:
結論:常規錄音機制無法同時捕獲雙向語音流。
所有語音軟體最終都會呼叫 Windows 底層音頻 API(位於 winmm.dll)。利用系統 Hook 修改這些 API 入口地址,在 Skype 調用前攔截、複製音頻數據,再轉交原函數執行,即可「神不知鬼不覺」地獲取雙向語音數據。
| API | 用途 |
|---|---|
waveInOpen / waveInClose | 開啟/關閉音頻輸入裝置(錄音) |
waveOutOpen / waveOutClose | 開啟/關閉音頻輸出裝置(播放) |
waveInPrepareHeader | 準備錄音緩衝區(捕獲「我方說話」數據) |
waveOutWrite | 發送播放數據塊(捕獲「對方聲音」數據) |
程式必須編譯為 DLL 注入 Skype 進程。使用《Windows 核心編程》中的 CAPIHook 類修改 API 地址:
// 定義函數指標類型
typedef MMRESULT (WINAPI *PFN_waveOutWrite)(HWAVEOUT, LPWAVEHDR, UINT);
// ... 其他 5 個同理
// 修改 API 入口
CAPIHook g_waveOutWrite("winmm.dll", "waveOutWrite", (PROC)Hook_waveOutWrite, TRUE);
// ... 其他 5 個同理
MMRESULT WINAPI Hook_waveOutWrite(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh)
{
// pwh->lpData 緩衝區即為對方語音數據
SendDataToMainWnd(pwh->lpData,
pwh->dwBytesRecorded > 0 ? pwh->dwBytesRecorded : pwh->dwBufferLength,
ENUM_CATCHSOUNDTYPE_waveOutWrite);
// 呼叫原始 API
return ((PFN_waveOutWrite)(PROC)g_waveOutWrite)(hwo, pwh, cbwh);
}
MMRESULT WINAPI Hook_waveInPrepareHeader(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh)
{
// 錄音緩衝區滿時會調用此函數準備下一塊,當前緩衝已含錄製數據
SendDataToMainWnd(pwh->lpData,
pwh->dwBytesRecorded > 0 ? pwh->dwBytesRecorded : pwh->dwBufferLength,
ENUM_CATCHSOUNDTYPE_waveInPrepareHeader);
return ((PFN_waveInPrepareHeader)(PROC)g_waveInPrepareHeader)(hwi, pwh, cbwh);
}
hw_mp3_enc.dll 庫進行 MP3 編碼(效果足夠電話錄音級)。兩種實現路徑:
Hook 回調函數執行效率直接影響通話品質。耗時操作(MP3 編碼、寫檔)必須拋給工作線程處理,否則會導致通話卡頓、數據丟失。

waveInPrepareHeader 前清理了數據。建議嘗試捕獲 MM_WIM_DATA 訊息獲取錄音數據,留待有興趣者攻克。完整關鍵代碼已打包,商業邏輯代碼因版權未公開。歡迎技術交流。