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

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

優勢:github

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

缺點:函數

  • 只能播放wav音頻文件。

這裏咱們說說設備操做這一起。oop

1. 輸出設備操做

在DirectSound中,一個設備對象就表明一個音頻設備,播放設備對象對應播放設備,輸入設備對象對應輸入設備。由於DirectSound使用COM協議,所以每一個設備對象都用接口來表示。這裏IDirectSound8這個接口就表明了一個輸出設備對象,應用程序能夠對同一個音頻設備建立多個設備對象來進行音頻輸出操做。舊版本的DirectSound使用的是IDirectSound接口,相比前者少了一些功能。ui

1.1 枚舉

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

咱們經過DirectSoundEnumerateW這個函數來枚舉,該函數須要傳入一個回調函數(原型見上),當枚舉到一個設備時該回調會被調用。若是咱們想繼續枚舉,須要在這個回調用中返回TRUE來告訴系統,不然返回FALSE。另外一個參數pContext容許用戶傳入額外的參數,傳入回調函數的最後一個實參就是這個pContext。枚舉時,DirectSound會將默認也認做一個單獨的設備來對待,所以默認設備會被重複枚舉一次。當設備被做爲默認設備枚舉時,它的GUID和設備描述字符串都爲空,須要當心處理,這裏我直接跳過了該次枚舉:code

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接口表明設備對象:blog

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

完整代碼見連接

相關文章
相關標籤/搜索