DirectSound---輸出設備基本操作(枚舉、查詢等)


DirectSound是DirectX組件之一,提供了對音頻設備的捕獲和播放能力,同時它也是唯一幾個支持Xp系統的音頻技術之一。 DirectSound主要有以下特點:

優點:

  • 播放音頻低延遲
  • 硬件資源控制
  • 同時播放多個聲音。
  • 控制硬件緩沖區的使用優先級(DirectSound使用緩沖區來播放音頻)。
  • 模擬3D音頻環境。
  • 動態更改音效(回聲、和聲等)。
  • 捕獲音頻輸入設備聲音位wav(多為PCM數據,未經壓縮)。

缺點:

  • 只能播放wav音頻文件。

這里我們說說設備操作這一塊兒。

1. 輸出設備操作

在DirectSound中,一個設備對象就代表一個音頻設備,播放設備對象對應播放設備,輸入設備對象對應輸入設備。因為DirectSound使用COM協議,因此每個設備對象都用接口來表示。這里IDirectSound8這個接口就代表了一個輸出設備對象,應用程序可以對同一個音頻設備創建多個設備對象來進行音頻輸出操作。舊版本的DirectSound使用的是IDirectSound接口,相比前者少了一些功能。

1.1 枚舉

HRESULT WINAPI DirectSoundEnumerateW(In LPDSENUMCALLBACKW pDSEnumCallback, In_opt LPVOID pContext);
typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID);

我們通過DirectSoundEnumerateW這個函數來枚舉,該函數需要傳入一個回調函數(原型見上),當枚舉到一個設備時該回調會被調用。如果我們想繼續枚舉,需要在這個回調用中返回TRUE來告訴系統,否則返回FALSE。另一個參數pContext允許用戶傳入額外的參數,傳入回調函數的最后一個實參就是這個pContext。枚舉時,DirectSound會將默認也認作一個單獨的設備來對待,因此默認設備會被重復枚舉一次。當設備被作為默認設備枚舉時,它的GUID和設備描述字符串都為空,需要小心處理,這里我直接跳過了該次枚舉:

if (DirectSoundEnumerateW(enumerateCallback, nullptr) != DS_OK) {
    ...
}

BOOL CALLBACK DirectSoundBasic::enumerateCallback(LPGUID guid,
                                              LPCWSTR deviceDescription,
                                              LPCWSTR deviceDriverModule,
                                              LPVOID context)
{
    Q_UNUSED(context);

    //	if primary device, skip it
    if (guid == nullptr)		return TRUE;

    ...
}

1.2 創建設備對象

HRESULT WINAPI DirectSoundCreate8(In_opt LPCGUID pcGuidDevice, Outptr LPDIRECTSOUND8 *ppDS8, Pre_null LPUNKNOWN pUnkOuter);

調用DirectSoundCreate8函數,我們可以創建一個設備對象,通過傳入一個枚舉設備時獲得的GUID,函數會返給我們一個IDirectSound8接口代表設備對象:

IDirectSound8* directSound8;
if (DirectSoundCreate8(guid, &directSound8, NULL) != DS_OK) {
	std::wcout << L"[error] DirectSoundCreate8 call error!";
	return TRUE;	//	if error, skip this device
}

1.3 設置設備對象優先級

HRESULT IDirectSound8::SetCooperativeLevel(HWND hwnd, DWORD dwLevel)

在使用設備對象創建緩沖區(用來捕獲、播放音頻)之前,我們需要設置設備對象的協作級別。這個協作級別相當於用戶對設備進行操作的優先級,分為:

  • DSSCL_EXCLUSIVE: 互斥級別。對於DirectX8.0以前版本,僅播放當前應用的音頻數據,其他應用的聲音不會被播放;對於DirectX8.0級以后版本,同DSSCL_PRIORITY版本。

  • DSSCL_NORMAL: 普通級別,這種級別下的應用程序具有最平滑的多任務和資源共享表現,但是這種應用不能更改主緩沖區音頻數據格式,輸出音頻格式被限制為8位數據。在DirectSound中,次緩沖區用來填充應用程序需要播放的聲音,主緩沖區會對多個次緩沖區(可能是本應用的,也可能是其他應用的)進行混音,然后用聲卡輸出播放。

  • DSSCL_PRIORITY: 優先級別,可以更改主緩沖區數據格式。

  • DSSCL_WRITEPRIMARY:寫主緩沖區級別,應用可以直接寫入主緩沖區,此時所有次緩沖區不會被播放(如果設備的驅動是DirectSound模擬出來的,則不能設置該級別)。

注意該函數需要傳入一個窗口句柄,因為我們今天只介紹DirectSound的基本操作,我直接傳入桌面窗口的句柄並設定位DSSCL_NORMAL優先級:

if (directSound8->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL) != DS_OK) {
	std::wcout << L"[error] SetCooperativeLevel call error!";
	return TRUE;
}

1.4 設備能力

HRESULT IDirectSound8::GetCaps(LPDSCAPS pDSCaps)

不同的音頻播放設備具有不同的能力,DirectSound允許我們查詢設備的能力:

  • 是否經過Microsoft認證。
  • 知否支持最小最大采樣率之間的所有采樣率。
  • 當沒有DirectSound驅動時模擬驅動。
  • 主次緩沖區格式(16位、8位)。
  • 主次緩沖區聲道支持(單聲道、立體聲即多聲道)。
  • 不精准的數據(某些聲卡不支持):
    • 緩沖區(靜態緩沖區、流緩沖區、3D緩沖區)最大數、空閑數。
    • 聲卡上的總內存數量、空閑內存數量、最大空閑塊大小,

我們傳給GetCaps一個DSCAPS結構體地址,然后系統就幫我們填充相應的數據,調用GetCaps前需要將DSCAPS結構體的dwSize設置為DSCAPS的大小:

DSCAPS deviceCapability = { sizeof(deviceCapability) };
if (directSound8->GetCaps(&deviceCapability) != DS_OK) {
	std::wcout << L"[error] GetCaps call error!";
	return TRUE;
}

1.5 播放器配置

HRESULT IDirectSound8::GetSpeakerConfig(LPDWORD pdwSpeakerConfig)
HRESULT IDirectSound8::SetSpeakerConfig(LPDWORD pdwSpeakerConfig)

播放器配置只能是以下之一:

  • DSSPEAKER_5POINT1_SURROUNDDSSPEAKER_5POINT1_BACK: 家庭影院配置,5個環繞揚聲器,1個低音炮。
  • DSSPEAKER_DIRECTOUT:直接播放。
  • DSSPEAKER_HEADPHONE:頭戴式耳機。
  • DSSPEAKER_MONO:單聲道揚聲器。
  • DSSPEAKER_QUAD:4聲道播放器。
  • DSSPEAKER_STEREO:立體聲播放器。
  • DSSPEAKER_SURROUND:環繞播放器。
  • DSSPEAKER_7POINT1_WIDEDSSPEAKER_7POINT1_SURROUND:家庭影院配置,7個環繞揚聲器,1個低音炮。

雖然MSDN文檔沒有寫清楚,但是通過查以上宏定義我們發現它們是按大小順序定義的,因此不可能通過OR|來包含多種可能,例子中如果調用出錯直接返回TRUE表示我們繼續枚舉設備並繼續查詢那些設備能力:

DWORD deviceSpeakerConfiguration;
if (directSound8->GetSpeakerConfig(&deviceSpeakerConfiguration) != DS_OK) {
	std::wcout << L"[error] GetSpeakerConfig call error!";
	return TRUE;
}

2. 運行結果

這次我們用GUI界面來顯示實例運行的結果(出於方便考慮,以后我會用控制台來顯示示例),為防止用戶誤操作更改顯示的數據我將大部分控件都disable了:

result-img

完整代碼見鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM