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

完整代码见连接

相关文章
相关标签/搜索