Windows混音器API使用

1.首先用mixerGetNumDevs()函数获取系统中的混音器设备的数量。一般,机器上都至少有一个混音器设备——声卡,如果机器上没有连接其它的音频设备,那么也就只有声卡这一个混音器设备。我的机器上接有一个名为USB EMP Audio Dedice的录音设备,所以该函数返回2,表示有两个混音器设备:Realtec AC97 Audio和USB EMP Audio Dedice。
UINT uNum = mixerGetNumDevs();

2.使用mixerOpen()函数打开需要控制的混音器设备,获取其句柄。此函数第一个参数是一个传出参数,被打开的混音器设备句柄将写入其中,可作为后面一些函数的传入参数,第二个参数uMxId (Identifier of the mixer device to open)是一个传入参数,用它来指定需要打开的混音器设备,最后一个参数指出怎样打开混音器设备。
MIXER_OBJECTF_MIXER说明The uMxId parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.
下面的代码将依次打开系统中所以的混音器设备:
HMIXER hMixer;
for ( int id = 0; id < uNum; id++ )
{
      mixerOpen(&hMixer,id,0,0,MIXER_OBJECTF_MIXER);
}

3.使用mixerGetDevCaps()函数获取一个打开的混音器设备的能力特征,它的第一个参数为uMxId(Identifier or handle of an open mixer device),是一个打开的混音器设备的ID号。第二个参数是一个传出参数,将返回一个MIXERCAPS的结构。此结构中包含有此混音器设备的信息,其中有用的是cDestinations成员(member)(The number of audio line destinations available through the mixer device)它表示此混音器设备的audio line目标的数量。Realtec AC97 Audio有两个audio line目标(audio line destination),一个audio line目标为“音量控制”,另一个audio line目标为“录音控制”。
MIXERCAPS mixercaps;
mixerGetDevCaps(id,&mixercaps,sizeof(MIXERCAPS));
如果打开的混音器设备是Realtec AC97 Audio,可以看到mixercaps.cDestinations将等于2.

4.使用mixerGetLineInfo()函数retrieves information about a specific line of a mixer device,用它来获取混音器设备某一line的信息。它的第一个参数类型为HMIXEROBJ(混音器设备对象句柄,注意区别于前面的混音器设备句柄)(Handle to the mixer device object that controls the specific audio line),是一个传入参数,表示需要获取此混音器设备对象的line information,此参数可以用前面获得的混音器设备句柄或ID号转换得到:(HMIXEROBJ)hMixer或(HMIXEROBJ)id。它的第二个参数类型为LPMIXERLINE,为“传入和传出”参数,将传入并返回一个类型为MIXERLINE的结构。第三个参数指定此函数获取line info的方式,例如可以是by component type(通过线路的component类型),也可以是by line id(通过线路的ID号),还可以是MIXER_GETLINEINFOF_DESTINATION和MIXER_GETLINEINFOF_SOURCE等。你可以根据实际需要选择合适的方式。
注意:第三个参数的选择对第二个参数(MIXERLINE)的传入值的设定有要求,如果选择by component type方式,那么MIXERLINE必须初始化其dwComponentType成员再传入,而如果选择by line id方式,则MIXERLINE必须先初始化其dwLineID成员再传入。
下面看一些例子,注意首先要对MIXERLINE结构的cbStruct成员进行初始化(The cbStruct member must always be initialized to be the size, in bytes, of the MIXERLINE structure)

MIXERLINE mixerline;
memset(&mixerline,0,sizeof(MIXERLINE));
mixerline.cbStruct = sizeof(MIXERLINE);

如果根据line的component类型来获取line的 information。注意,因为有可能不同的两个line的component 类型相同,因此有必要作进一步的判别以获得正确的line的ID或句柄。(例如再根据获取的line的szName成员进行判断)
// By component type例子
// 音量控制目标line的component类型为MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
mixerline.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
mmResult=mixerGetLineInfo((HMIXEROBJ)id,&mixerline,MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);

// 录音控制目标line的component类型为MIXERLINE_COMPONENTTYPE_DST_WAVEIN
mixerline.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mmResult=mixerGetLineInfo((HMIXEROBJ)hMixer,&mixerline,MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);

// 通过line的id号获取line的info
mixerline.dwLineID = 65537;
mmResult=mixerGetLineInfo((HMIXEROBJ)hMixer,&mixerline,MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_LINEID);

说明:因为线路的ID号是唯一的,即两条不同的线路的ID号也不同。因此不需要做进一
步的判断,但是这种方式不常使用,因为它的局限性:你必须先知道line的ID号,才可
以获取此line的信息,而且不知道“不同机器或不同系统”相同line的ID号是否一样?

// 通过目标线路索引号获取目标线路信息
MIXERCAPS的cDestinations成员为混音器设备的目标线路数量。下面的代码获取一个
混音器设备的所有目标线路信息。
for ( int index = 0; index < mixercaps.cDestinations; index++ )                 
{
       mixerline.dwDestination = index;
mmResult=mixerGetLineInfo((HMIXEROBJ)hMixer,&mixerline,MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_DESTINATION);
}

// 通过source线路索引号获取source线路信息
当MIXERLINE是一个目标线路时,它的cConnections成员表示此目标line的连接数
量(连接到此目标line的(source line)个数),cConnections成员只对目标line
有效,source line的cConnections成员值为0。
下面的代码用于获取一个目标线路的所有连接(连接到此目标线路的所有source线路)
DWORD dwConnections = mixerline.cConnections;
for ( int count = 0; count < dwConnections; count++ )
{
       mixerline.dwSource = count;
mmResult=mixerGetLineInfo((HMIXEROBJ)id,&mixerline,MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_SOURCE);
}

在Realtec AC97 Audio中连接到目标线路“录音控制”的source line有:Mono Mix,Stereo Mix,SPDIF,辅助,CD 唱机,线路输入,麦克风,电话线,总共8个。

下面是MSDN中关于MIXERLINE和mixerGetLineInfo()的一些解释:
先看MIXERLINE的几个member:
dwDestination
Destination line index. This member ranges from zero to one less than the value specified in the cDestinations member of the MIXERCAPS structure retrieved by the mixerGetDevCaps function. When the mixerGetLineInfo function is called with the MIXER_GETLINEINFOF_DESTINATION flag, properties for the destination line are returned. (The dwSource member must be set to zero in this case.) When called with the MIXER_GETLINEINFOF_SOURCE flag, the properties for the source given by the dwSource member that is associated with the dwDestination member are returned.
dwSource
Index for the audio source line associated with the dwDestination member. That is, this member specifies the nth audio source line associated with the specified audio destination line. This member is not used for destination lines and must be set to zero when MIXER_GETLINEINFOF_DESTINATION is specified in the mixerGetLineInfofunction. When the MIXER_GETLINEINFOF_SOURCE flag is specified, this member ranges from zero to one less than the value specified in the cConnections member for the audio destination line given in the dwDestination member.
dwLineID
An identifier defined by the mixer device that uniquely refers to the audio line described by the MIXERLINE structure. This identifier is unique for each mixer device and can be in any format. An application should use this identifier only as an abstract handle.
dwComponentType
Component type for this audio line
cChannels
Maximum number of separate channels that can be manipulated independently for the audio line. The minimum value for this field is 1 because a line must have at least one channel. Most modern audio cards for personal computers are stereo devices; for them, the value of this member is 2.
Channel 1 is assumed to be the left channel; channel 2 is assumed to be the right channel. A multichannel line might have one or more uniform controls (controls that affect all channels of a line uniformly) associated with it.
cConnections
Number of connections that are associated with the audio line. This member is used only for audio destination lines and specifies the number of audio source lines that are associated with it. This member is always zero for source lines and for destination lines that do not have any audio source lines associated with them.
cControls
Number of controls associated with the audio line. This value can be zero. If no controls are associated with the line, the line is likely to be a source that might be selected in a MIXERCONTROL_CONTROLTYPE_MUX or MIXERCONTROL_CONTROLTYPE_MIXER but allows no manipulation of the signal.
MSDN中关于mixerGetLineInfo()第三个参数的一些说明:
MIXER_GETLINEINFOF_COMPONENTTYPE:
The pmxl parameter will receive information about the first audio line of the type specified in the dwComponentType member of the MIXERLINE structure. This flag is used to retrieve information about an audio line of a specific component type. Remaining structure members except cbStruct require no further initialization.
MIXER_GETLINEINFOF_DESTINATION:
The pmxl parameter will receive information about the destination audio line specified by the dwDestination member of the MIXERLINE structure. This index ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure. All remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_LINEID:
The pmxl parameter will receive information about the audio line specified by the dwLineID member of the MIXERLINE structure. This is usually used to retrieve updated information about the state of an audio line. All remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_SOURCE:
The pmxl parameter will receive information about the source audio line specified by the dwDestination and dwSource members of the MIXERLINE structure. The index specified by dwDestination ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure. The index specified by dwSource ranges from zero to one less than the value in the cConnections member of the MIXERLINE structure returned for the audio line stored in the dwDestination member. All remaining structure members except cbStruct require no further initialization.

5.使用mixerGetLineControls()(retrieves one or more controls associated with an audio line.)获取对某一line的一个或多个控制。
此函数的第二个参数类型为LPMIXERLINECONTROLS,是一个[int,out]型参数。特别注意传入时需要进行的一些初始化动作。
a.如果mixerGetLineControls获取一个control by type(此时第三个参数为MIXER_GETLINECONTROLSF_ONEBYTYPE)时,需要对此结构的dwLineID和dwControlType进行设置,dwControlType用来说明控制的类型,而dwLineID用来说明对哪条line进行此种类型的控制。
b.如果mixerGetLineControls获取一个control by id(此时第三个参数为MIXER_GETLINECONTROLSF_ONEBYID)时,则需要初始化此结构的dwControlID成员,注意此时它的dwLineID成员不需要被初始化。

为什么前一种方式需要对dwLineID成员初始化,而后一种不需要呢?
难道是这样的:通过控制类型获取控制时,可能不同的line都有此控制类型,因此还要指定具体的line。而通过控制ID时,因为控制ID是唯一的,就没必要了?但经过debug发现,MIXERLINECONTROLS的dwControlID和dwControlType是一一对应的,而且还相等,也就是说对于不同的line,MIXERLINECONTROLS的dwControlID成员也是一样的,因此并不具有唯一性,难道上面的推论是错误的?偶然发现初始化MIXERLINECONTROLS的dwControlID后(先用ONEBYTYPE方式debug得到MIXERLINECONTROLS的dwControlID成员的值进行初始化),通过ONEBYID方式调用mixerGetLineControls,其返回值竟然不是MMSYSERR_NOERROR,这说明有问题,我马上想到:MIXERCONTROL结构也有一个dwControlID成员,这次用MIXERCONTROL结构的dwControlID成员的值初始化MIXERLINECONTROLS的dwControlID的值,这次成功了,而且得到了正确的结果,这也符合上面的推论,因为MIXERCONTROL的dwControlID是唯一的。但我们一般使用前一种方式,因为我们开始并不知道控制ID是多少。而且这种方式有画蛇添足之举,既然已经得到dwControlID,还有必要再重新获取一次吗?

下面是MSDN对MIXERLINECONTROLS结构的成员的一些描述;
dwLineID
Line identifier for which controls are being queried. This member is not used if the MIXER_GETLINECONTROLSF_ONEBYID flag is specified for the mixerGetLineControls function, but the mixer device still returns this member in this case. The dwControlID and dwControlType members are not used when MIXER_GETLINECONTROLSF_ALL is specified.
dwControlID
Control identifier of the desired control. This member is used with the MIXER_GETLINECONTROLSF_ONEBYID flag for the mixerGetLineControls function to retrieve the control information of the specified control. Note that the dwLineID member of the MIXERLINECONTROLS structure will be returned by the mixer device and is not required as an input parameter. This member overlaps with the dwControlType member and cannot be used in conjunction with the MIXER_GETLINECONTROLSF_ONEBYTYPE query type.
dwControlType
Class of the desired Control Types. This member is used with the MIXER_GETLINECONTROLSF_ONEBYTYPE flag for the mixerGetLineControls function to retrieve the first control of the specified class on the line specified by the dwLineID member of the MIXERLINECONTROLS structure. This member overlaps with the dwControlID member and cannot be used in conjunction with the MIXER_GETLINECONTROLSF_ONEBYID query type. See dwControlType member description in MIXERCONTROL.
cControls
Number of MIXERCONTROL structure elements to retrieve. This member must be initialized by the application before calling the mixerGetLineControls function. This member can be 1 only if MIXER_GETLINECONTROLSF_ONEBYID or MIXER_GETLINECONTROLSF_ONEBYTYPE is specified or the value returned in the cControls member of the MIXERLINE structure returned for an audio line. This member cannot be zero. If an audio line specifies that it has no controls, mixerGetLineControls should not be called.
pamxctrl
Pointer to one or more MIXERCONTROL structures to receive the properties of the requested audio line controls. This member cannot be NULL and must be initialized before calling the mixerGetLineControls function. Each element of the array of controls must be at least large enough to contain a base MIXERCONTROL structure. The cbmxctrl member must specify the size, in bytes, of each element in this array. No initialization of the buffer pointed to by this member is required by the application. All members are filled in by the mixer device (including the cbStruct member of each MIXERCONTROL structure) upon returning successfully.
下面是MSDN关于mixerGetLineControls第三个参数的一些说明:
MIXER_GETLINECONTROLSF_ONEBYID:
The pmxlc parameter references a single MIXERCONTROL structure that will receive information on the control identified by the dwControlID member of the MIXERLINECONTROLS structure. The cControls member must be initialized to 1. The cbmxctrl member must be initialized to the size, in bytes, of a single MIXERCONTROL structure. The pamxctrl member must point to a MIXERCONTROL structure to be filled. The dwLineID and dwControlType members are ignored for this query. This query is usually used to refresh a control after receiving a MM_MIXM_CONTROL_CHANGE control change notification message by the user-defined callback (see mixerOpen).

MIXER_GETLINECONTROLSF_ONEBYTYPE:
The mixerGetLineControls function retrieves information about the first control of a specific class for the audio line that is being queried. The pmxlc parameter references a single MIXERCONTROL structure that will receive information about the specific control. The audio line is identified by the dwLineID member. The control class is specified in the dwControlType member of the MIXERLINECONTROLS structure.
The dwControlID member is ignored for this query. This query can be used by an application to get information on a single control associated with a line. For example, you might want your application to use a peak meter only from a waveform-audio output line.

具体的一些代码如下:首先要初始化MIXERLINECONTROLS结构
MIXERCONTROL mc;
memset(&mc,0,sizeof(MIXERCONTROL);
mc.cbStruct = sizeof(MIXERCONTROL);

MIXERLINECONTROLS mlc;
memset(&mlc,0,sizeof(MIXERLINECONTROLS));
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.cControls = 1;
mlc.cbmxctrl = sizeof(MIXERCONTROL);                  
mlc.pamxctrl = &mc;
mlc.dwLineID = mixerline.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
mmResult=mixerGetLineControls((HMIXEROBJ)hMixer,&mlc,
MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);

调用mixerGetLineControls后,MIXERLINECONTROLS结构的pamxctrl成员所指
向的对象(一个MIXERCONTROL结构)将被填充,所有需要的控制信息都将写入其中,将
被用于进行控制动作时使用。

下面是MSDN中关于MIXERCONTROL结构的成员的一些知识:
dwControlID
Audio mixer-defined identifier that uniquely refers to the control described by the MIXERCONTROL structure. This identifier can be in any format supported by the mixer device. An application should use this identifier only as an abstract handle. No two controls for a single mixer device can ever have the same control identifier.
dwControlType
Class of the control for which the identifier is specified in dwControlID. An application must use this information to display the appropriate control for input from the user. An application can also display tailored graphics based on the control class or search for a particular control class on a specific line. If an application does not know about a control class, this control must be ignored. There are eight control class classifications, each with one or more standard control types
cMultipleItems
Number of items per channel that make up a MIXERCONTROL_CONTROLF_MULTIPLE control. This number is always two or greater for multiple-item controls. If the control is not a multiple-item control, do not use this member; it will be zero.
我们看到,MIXERLINECONTROLS和MIXERCONTROL都有dwControlID和
dwControlType成员,前者传入给mixerGetLineControls,用以说明需要
获取什么样的控制。而后者将作为mixerGetLineControls的输出,
保存有获取到的控制的ID号和type等信息,以备后面的使用。

 

6.使用mixerSetControlDetails(sets properties of a single control associated with
an audio line.)函数完成对控制的设置。

此函数的第二个参数为LPMIXERCONTROLDETAILS类型(Pointer to a
MIXERCONTROLDETAILS structure. This structure is used to reference control detail
structures that contain the desired state for the control.)
All members of the MIXERCONTROLDETAILS structure must be initialized before calling mixerSetControlDetails.
下面为MSDN对此函数第三个参数的一些说明:
MIXER_SETCONTROLDETAILSF_CUSTOM:
A custom dialog box for the specified custom mixer control is displayed. The mixer
device gathers the required information from the user and returns the data in the
specified buffer. The handle for the owning window is specified in the hwndOwner
member of the MIXERCONTROLDETAILS structure. (This handle can be set to NULL.)
The application can then save the data from the dialog box and use it later to reset the
control to the same state by using the MIXER_SETCONTROLDETAILSF_VALUE flag.

MIXER_SETCONTROLDETAILSF_VALUE:
The current value(s) for a control are set. The paDetails member of the
MIXERCONTROLDETAILS structure points to one or more mixer-control details
structures of the appropriate class for the control.

例子代码如下:
MIXERCONTROLDETAILS_BOOLEAN mxcdMute[8];
for ( int i = 0; i < mc.cMultipleItems; i++ )
{
        mxcdMute[i].fValue = FALSE;
}
mxcdMute[6].fValue = TRUE;
MIXERCONTROLDETAILS mixercontroldetails;
memset(&mixercontroldetails,0,sizeof(MIXERCONTROLDETAILS));

mixercontroldetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixercontroldetails.cbDetails=sizeof(MIXERCONTROLDETAILS_BOOLEAN;
mixercontroldetails.cChannels = 1;
mixercontroldetails.cMultipleItems = 0;
mixercontroldetails.paDetails = &mxcdMute[0];
mixercontroldetails.dwControlID = mc.dwControlID;
mixercontroldetails.cMultipleItems = mc.cMultipleItems;

mmResult=mixerSetControlDetails((HMIXEROBJ)hMixer,&mixercontroldetails,MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER);

这里要注意的几个地方是:MIXERCONTROLDETAILS的dwControlID是用前面得到的
MIXERCONTROL结构的dwControlID成员初始化,MIXERCONTROLDETAILS的
paDetails成员指向一个MIXERCONTROLDETAILS_BOOLEAN之类的结构,这个结构必
须先进行一定的初始化,它包含控制的具体内容。其中mc.cMultipleItems表示的是“录
音控制”这个destination audio line所map(对应)的source audio line的
项目数,这里的值为8,打开录音控制面板,你会发现里面有Mono Mix,Stereo
Mix,SPDIF,辅助,CD 唱机,线路输入,麦克风,电话线,也就是这8项拉!这里有一个细
节需要注意:按正常顺序,应该是mxcdMute[0]代表Mono Mix, mxcdMute[1]代表
Stereo Mix等等才对,如果这样设置那你就错了,这里的顺序刚好是相反的
mxcdMute[0]代表的是电话线,mxcdMute[1]代表的是麦克风,所以上面代码中的
mxcdMute[6]代表的才是Stereo Mix,所以使用mixerSetControlDetails时要注
意这点。而使用mixerGetLineInfo的顺序则与控制面板顺序相同:
DWORD dwConnections = mixerline.cConnections;                
for ( int count = 0; count < dwConnections; count++ )
{
       // 在这里当mixerline.dwSource等于0时,得到的mixerline是Mono Mix
       // 当等于1时,得到的是Stereo Mix
       mixerline.dwSource = count;
mmResult=mixerGetLineInfo((HMIXEROBJ)id,&mixerline,MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_SOURCE);
}

Mixer Architecture
The basic element of the mixer architecture is an audio line. An audio line consists of one or more channels of data originating from a single source or a system resource. For example, a stereo audio line has two data channels, but it is considered a single audio line because it originates from a single source.
The mixer architecture provides routing services to manage audio lines on a computer. You can use the routing services if you have adequate hardware devices and software drivers installed. The mixer architecture allows several audio source lines to map to a single destination audio line.
Each audio line can have mixer controls associated with it. A mixer control can perform any number of functions (such as control volume), depending on the characteristics of the associated audio line.
NOTE: 本文主要是对混音器编程的几个 API 函数进行介绍。在使用这些函数时,应从实际的需要出发。因此,首先必须明确程序需要对混音器进行哪种操作,从而确定需要取得哪种控制(即 control type ,控制类型),然后弄清此控制类型所属的 line
从先获取 destination line 信息,再从某一 destination line 获取其对应的 source line 信息来看,目标 line source line 之间的关系有点像 line subline 一样。但从 line component type 来看,它们只不过是不同类型的 line
Line 主要是起控制作用,不同 line 的本质区别就是起不同的控制作用。
决定 line 性质的两个要素: component type control type ,前者决定 line 控制的对象,后者决定 line 控制的方式。
具体编程时,首先应该确定要使用的是哪个 line ,确定 line 后就需要知道其 component type ,主要用于 mixerGetLineInfo 中以获取要使用的 line ID 号,然后根据控制的需要(需要进行什么样的控制)来确定 control type
Destination audio line:
音量控制       component type MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
录音控制       component type: MIXERLINE_COMPONENTTYPE_DST_WAVEIN
Source audio line:
麦克风    component type: MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
线路输入 component type: MIXERLINE_COMPONENTTYPE_SRC_LINE
Stereo Mix component type: MIXERLINE_COMPONENTTYPE_SRC_ANALOG
说明:一条 line 可能包含有一个或多个 control (控制),下面介绍一些 line 的主要控制。
Line :录音控制
Control type:
MIXERCONTROL_CONTROLTYPE_MUX

Multiplexer (MUX)
Restricts the line selection to one source line at a time.

Line :所有的 source audio line
Control type:
MIXERCONTROL_CONTROLTYPE_VOLUME

Volume
General volume fade control. The range of acceptable values is 0 through 65,535. For information about changing this range, see the documentation for your mixer device.

Line :音量控制中的所有 source audio line
Control type
MIXERCONTROL_CONTROLTYPE_MUTE

Mute
Mutes an audio line (suppressing the data flow of the line) or allows the audio data to play. This switch is frequently used to help control the lines feeding into the mixer.

你可能感兴趣的:(windows,properties,application,Class,audio,structure)