前面学习了,如何枚举输出设备,其目的也正式为了创建正确的播放设备了,所以这次,学习如何创建一个播放设备。
创建设备对象,最简单的方法,就是通过DirectSoundCreate8函数来创建,该函数在Dspack的DirectX库中声明样式为:
DelphiCode:
function DirectSoundCreate8(pcGuidDevice: PGUID; out ppDS8: IDirectSound8;
pUnkOuter: IUnknown): HResult; stdcall; external DirectSoundDLL;
|
可见其第一个参数为PGUID形式,该参数就用来指定咱要创建的设备对象的GUID,前面,咱已经通过枚举获得了各种设备的GUID了并且保存在 Combobox的 Item中,可以随便选择一个GUID,来进行创建,该参数如果传递为nil或DSDEVID_DefaultPlayback,则使用系统默认的输出设备,SDEVID_DefaultVoicePlayback则指定为第二默认设备,通常指USB耳机麦克风等。
第二个参数,就指定需要得到的设备对象,第三个参数类型是一个未知类型,应该是留待以后使用,这里指定为nil就可以了
具体代码如下:
DelphiCode:
hr := DirectSound.DirectSoundCreate8(PGUID(ComboBox1.Items.Objects[0]),lp,nil);
if Failed(hr) then
ShowMessage('创建设备失败');
|
该函数一般在没有声音输出设备,或在VXD驱动程序下,声音输出设备正在被某个应用程序通过waveform格式的api函数控制的时候会失败。
自然,可能有人会想要完全通过Com调用来创建设备的,不过比较麻烦一点,具体代码如下:
DelphiCode:
Label 1;
begin
hr := ActiveX.CoInitializeEx(nil,0);//初始化COM库
if Failed(hr) then
goto 1;
//创建一个设备对象,CLSID_DirectSound8为DirectSound设备驱动类的类标识,IID_IDirectSound8为接口标识
hr := CoCreateInstance(CLSID_DirectSound8,nil,CLSCTX_INPROC_SERVER,IID_IDirectSound8,lp);
if Failed(hr) then
goto 1;
hr = lp.Initialize(nil);//初始化设备对象
if Fialed(hr) then
ShowMessage('失败');
1:
CoUninitialize;
end;
|
创建设备对象成功之后,首要的第一件事情,我们应该是设置设备对象的协作级别,因为Windows是一个多任务环境,同一时间由多个应用程序去反问设备,通过使用协作级别,DirectX可以确保应用程序不会在别的设备使用时去访问,每个DirectSound应用程序都一个协作级别,这个级别决定着访问硬件的权限。在创建一个设备对象之后,必须使用
IDirectSound8.SetCooperativeLevel来设置协作权限,否则将听不到声音的哦
设置的代码很简单:
DelphiCode:
lp.SetCooperativeLevel(self.Handle,DSSCL_NORMAL); //设置协作级别
|
这里我设置的是一个普通级别,第一个参数为应用程序的窗口句柄.
DirectSound定义了三个协作权限,分别是DSSCL_NORMAL,DSSCL_PRIORITY,DSSCL_WRITEPRIMARY
分别表示普通协作级,优先权协作级,写主缓冲区级
DSSCL_NORMAL(普通协作级)
在标准协作级别(DSSCL_NORMAL)下,应用程序不能设置主缓冲区的格式,填充主缓冲区,或者压缩设备的On-board内存。所有在这个协作级别的应用程序使用一个22KHz,立体音效,8位采样格式的主缓冲区,这样设备能够在应用程序间顺利地切换。
DSSCL_PRIORITY(优先协作级)
当使用一个出于优先协作级别(DSSCL_PRIORITY)地DirectSound设备时,应用程序享有对硬件资源的优先权,如硬件混频,设置主缓冲区的格式,以及压缩设备的On-board内存。
游戏程序在几乎所有环境下都应该使用优先协作级别。这个级别给予了应用程序最强大的行为能力,使它能够控制采样率和位深度。优先协作级别也允许来自其他应用程序(如IP电话)的声音与游戏中的声音一同被听到。
DSSCL_WRITEPRIMARY(写入主缓冲区级)
最高协作级别是写主缓冲区(DSSCL_WRITEPRIMARY)。当使用这一协作级别的DirectSound设备时,你的应用程序能够直接访问非WDM驱动的主缓冲区。在这种模式下,应用程序必须直接填充主缓冲区。此时,辅助缓冲区无法被播放。
一个应用程序为了获取对主缓冲区中音频采样的直接写访问,必须被设置为写主缓冲区级别。如果应用程序没有被设置成这一级别,那么所有对主缓冲区上IDirectSoundBuffer::Lock方法的调用都将失败。
另外需要注意的是:主缓冲区只支持IDirectSoundBuffer接口,而不是IDirectSoundBuffer8。
当你的应用程序被设置为写主缓冲区协作级别并出于前台位置时,所有用于其他应用程序的辅助缓冲区将被停止并标记为已丢失。当你的应用程序顺次移动到后台时,它的主缓冲区被标记为已丢失,并且在应用程序再次移动到前台时被恢复。
如果一个DirectSound驱动器不在用户系统中时,你无法设置写主缓冲区协作级别。为判断是否出于这种情形,调用IDirectSound8::GetCaps方法,并检查DSCAPS结构中DSCAPS_EMULDRIVER标识。
设备性能
DirectSound使你的应用程序可以检查声音设备的硬件性能。许多应用程序不需要这么做,因为DirectSound自动利用任何可用的硬件加速。然而,性能良好的应用程序能够使用这些信息,根据可用的硬件扩展它们的声音需求。比如,如果硬件混频可用,一个应用程序可能选择播放多道声音。在调用 DirectSoundCreate8 函数创建一个设备对象后,你的应用程序能够通过调用IDirectSound8.GetCaps方法获取声音设备的性能。
在Dspack中该函数的声明为:
function GetCaps(out pDSCaps: TDSCaps): HResult; stdcall;
要求传递一个TDsCaps,也就是DSCAPS的结构体
在调用的时候,我们必须先设置DSCAPS的dwsize的大小
具体代码如下:
DelphiCode:
var
hr: HRESULT;
caps: TDSCaps;
begin
caps.dwSize := SizeOf(TDscaps);
hr := lp.GetCaps(caps);
if failed(hr) then
begin
ShowMessage('获取性能失败'); exit; end; //这里,我们来查看是否有DSCAPS_EMULDRIVER,也就是测试是否能将协作级设置成DSSCL_WRITEPRIMARY
if caps.dwFlags and DSCAPS_EMULDRIVER = 0 then//如果等于0,就说明没有DSCAPS_EMULDRIVER标志
begin
ShowMessage('不能设置成写主缓冲区级别模式'); lp.SetCooperativeLevel(self.Handle,DSSCL_NORMAL); //设置协作级别
end
else
begin
ShowMessage('可以设置DSSCL_WRITEPRIMARY模式'); lp.SetCooperativeLevel(self.Handle,DSSCL_WRITEPRIMARY); //设置协作级别
end; end;
|