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_SURROUND、DSSPEAKER_5POINT1_BACK: 家庭影院配置,5个环绕扬声器,1个低音炮。
- DSSPEAKER_DIRECTOUT:直接播放。
- DSSPEAKER_HEADPHONE:头戴式耳机。
- DSSPEAKER_MONO:单声道扬声器。
- DSSPEAKER_QUAD:4声道播放器。
- DSSPEAKER_STEREO:立体声播放器。
- DSSPEAKER_SURROUND:环绕播放器。
- DSSPEAKER_7POINT1_WIDE、DSSPEAKER_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了:

完整代码见链接。
DirectSound---输出设备基本操作(枚举、查询等)的更多相关文章
- 关于linq to sql调用存储过程,出现"无法枚举查询结果多次"的问题
DBML: [Function(Name="dbo.p_GetStudyStageSubjectGroup")] public ISingleResult<STUDYSTAG ...
- hdu 5595 GTW likes math(暴力枚举查询)
思路:直接暴力枚举区间[l,r]的整数值,然后max和min就可以了. AC代码: #pragma comment(linker, "/STACK:1024000000,1024000000 ...
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
- .NET LINQ标准查询运算符
标准查询运算符概述 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法. 大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了 IEnumerable<T> ...
- 某表含有N个字段超精简模糊查询方法
我们在做多个字段模糊查询时,是不是觉得非常麻烦?比如我要模糊查询某表多个字段存在某数据时,如下 select * from table where a like '%key%' or b like ...
- 媒体查询的应用以及在css3中的变革
CSS一直都支持设置与媒体相关联的样式表.它们可以适应不同媒体类型的显示.例如,文档在屏幕显示时使用sans-serif字体,在打印时则使用serif字体.screen和print是两种预定义的媒体类 ...
- SQL存储过程动态查询数据区间
以前经常看到人查询数据库采用left join及case方式,一条一条的枚举查询整个数据的数据区间方法可行,但是数据一但很大,枚举就死悄悄,在网上查看,几乎全是照抄case ,left join枚举无 ...
- ThinkPhp框架对“数据库”的基本操作
框架有时会用到数据库的内容,在"ThinkPhp框架知识"的那篇随笔中提到过,现在这篇随笔详细的描述下. 数据库的操作,无疑就是连接数据库,然后对数据库中的表进行各种查询,然后就是 ...
- Mysql 数据库学习笔记01查询
1.数据查询基本操作 * 正则表达式查询: 字段名 regexp '匹配方式', select * from user where username regexp '^名' -- 查询 姓名 名 ...
随机推荐
- poj:4091:The Closest M Points
poj:4091:The Closest M Points 题目 描写叙述 每到饭点,就又到了一日几度的小L纠结去哪吃饭的时候了.由于有太多太多好吃的地方能够去吃,而小L又比較懒不想走太远,所以小L会 ...
- Springboot的默认定时任务——Scheduled注解
本博客参考博文地址. 1.pom依赖: 引入springboot starter包即可 <dependencies> <dependency> <groupId>o ...
- Python笔记·第三章—— 逻辑运算
一.逻辑运算符的种类及优先级 ▷逻辑运算符包括 not and or ▷他们的优先级是 () > not > and > or 二.普通逻辑运算 ▷A and B ---> ...
- 一、Spring Cloud介绍
springcloud 介绍 研究了一段时间spring boot了准备向spirng cloud进发,公司架构和项目也全面拥抱了Spring Cloud.在使用了一段时间后发现Spring Clou ...
- 前后端分离ueditor富文本编辑器的使用-Java版本
最近在写一个自己的后台管理系统(主要是写着玩的,用来熟悉后端java的知识,目前只是会简单的写点接口),想在项目中编写一个发布新闻文章的功能,想到了使用百度的ueditor富文本编辑器,网上找了很多j ...
- 在jQuery中使用canvas时遇到的问题
正常的情况下一般在JavaScript中使用canvas,会用到如下代码: var canvas=document.getElementById("canvas"); var co ...
- JavaScript定时器:setTimeout()和setInterval()
1 超时调用setTimeout() 顾名思义,超时调用的意思就是在一段实际之后调用(在执行代码之前要等待多少毫秒) setTimeout()他可以接收两个参数: 1 要执行的代码或函数 2 毫秒(在 ...
- vue+express之前后台分离博客
说来惭愧,这么久没有更新过博客了,写个项目练练手吧,打算写一个vue+express的博客 可能这个时间说长不长说短不短 写到哪就是哪吧 我采用的是前后台分离 express采用的是mvc,但 ...
- [WinForm]委托应用①——窗口之间方法/控件调用
不传参数 第二窗口:public partial class Form2 : Form { /// <summary> /// 定义委托 /// </summary> publ ...
- php项目报错 Warning: session_start(): open(D:/software/wamp/wamp/tmp\sess_msrjot7f32ciqb1p2hr4ahejg4, O_RDWR) f
今天一个php项目报错: Warning: session_start(): open(D:/software/wamp/wamp/tmp\sess_msrjot7f32ciqb1p2hr4ahejg ...