对声卡输出进行录音的设置.

一般正常的录音都是对Line in进行录音,但有些需要对line out进行录音,因为有些音源是没有line in的.

如即时聊天时录取对方的语音.但这些声音都要经过声卡播放,所以它们的音源就是声卡输出.

对于声卡的输出,在录音控制中有两个,就是Mono mix和stereo mix,当然最好是选取 stereo mix,效果更好.

编程打开录音设备时,是不能控制打开的设备上的输出还是输入通道的.所在要在打开设备前就设置好.

用Mixer的API可以对输出源进行牧举,不过不同的设备的定义不同,对于SoundMax能够正确区别stereo mix和Mono mix的区别,但AC 97的声卡它都是相似的输出源.所以只能多次地优选列举.代码逻辑不是完美,但只能如此.否则只能让用户手工选择,致少要按6次mouse才行.

以下是自己定义的结构,在第一次没有找到正确的输出源时将所有输出源保的index,swLineID和name保存起来.下面

在结构数组中再优选,而不要再对设备牧举

typedef struct ControlEnumData{
 INT index;
 CString szName;
 DWORD dwLineID;
}  CTRL_ENUM_DATA,* LPCTRL_ENUM_DATA;

 

 

BOOL   XXX::setOutSource()

   UINT deviceCount 
=  ::mixerGetNumDevs();
    
if (deviceCount  <   1 ){
        MessageBox(
" 没有找到混音设备,请手工选择录音设备的混音输出! " );
        
return  TRUE;
    }
    BOOL found 
=  FALSE;

    
for (UINT devID  =   0 ;devID  <  deviceCount; devID ++ ){
        HMIXER hMixer;
        
if  (mixerOpen( & hMixer, devID, (DWORD) 0 0 , CALLBACK_WINDOW)  !=  MMSYSERR_NOERROR)
        {
        ::mixerClose(hMixer);
            
continue ;
        }

        MIXERLINE line;
        line.cbStruct 
=   sizeof (MIXERLINE);
        
// 注意我们要查找的是录音设备.所以dwComponentType 应该是 MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
        line.dwComponentType  =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
        
if (::mixerGetLineInfo((HMIXEROBJ)hMixer, & line,
            MIXER_OBJECTF_HMIXER
| MIXER_GETLINEINFOF_COMPONENTTYPE)  !=  MMSYSERR_NOERROR){
        ::mixerClose(hMixer);
            
continue ;
        }
        DWORD dwConnections 
=  line.cConnections;
        DWORD selectIndex 
=   - 1 ;
        MIXERLINE linesub;
        CTRL_ENUM_DATA enumData[
8 ];
        
int  enumIndex  =   0 ;
        
// 然后看录音设备上共一连结了几个线路
         for (DWORD i  =   0 ;i <  dwConnections ;i ++ ){     // 列举出波形混音输出源的索引并最声音设置最大
            linesub.cbStruct  =   sizeof (MIXERLINE);   
            linesub.dwSource   
=    i;   
            linesub.dwDestination 
=  line.dwDestination;
            
if (mixerGetLineInfo((HMIXEROBJ)hMixer, & linesub,
                MIXER_OBJECTF_HMIXER
| MIXER_GETLINEINFOF_SOURCE)  ==  MMSYSERR_NOERROR){
                
if (linesub.dwComponentType  ==  MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT){
                    
// 这是stereo mix的输出源.如果能明确找到,就直接定位到这个index上.
                    
// 并把这个设备选中并把音量调到最大.
                    MIXERCONTROL   mxc;   
                    MIXERLINECONTROLS   mxlc;   
                    mxlc.cbStruct   
=     sizeof (MIXERLINECONTROLS);   
                    mxlc.dwLineID   
=    linesub.dwLineID;
                    DWORD  dwControlType 
=  MIXERCONTROL_CONTROLTYPE_VOLUME; 
                    mxlc.dwControlType   
=    dwControlType;   
                    mxlc.cControls   
=     1 ;   
                    mxlc.cbmxctrl   
=     sizeof (MIXERCONTROL);   
                    mxlc.pamxctrl   
=     & mxc;   
                    
if    (::mixerGetLineControls((HMIXEROBJ)hMixer, & mxlc,
                        MIXER_OBJECTF_HMIXER
| MIXER_GETLINECONTROLSF_ONEBYTYPE)  ==  MMSYSERR_NOERROR)   
                    {   
                        MIXERCONTROLDETAILS_BOOLEAN vumVal[
1 ];
                        MIXERCONTROLDETAILS   mxcd;   
                        mxcd.cbStruct   
=     sizeof (MIXERCONTROLDETAILS);   
                        mxcd.dwControlID   
=    mxc.dwControlID; // 在上面的&mxc得到   
                        mxcd.cChannels    =     1 ;   
                        mxcd.cMultipleItems  
=  mxc.cMultipleItems;  
                        mxcd.cbDetails   
=     sizeof (MIXERCONTROLDETAILS_BOOLEAN);   
                        mxcd.paDetails   
=   & vumVal;
                        vumVal[
0 ].fValue  =   65535 ;
                        
// 将设备音量调至最大
                        ::mixerSetControlDetails((HMIXEROBJ)hMixer, & mxcd,
                            MIXER_OBJECTF_HMIXER
| MIXER_GETCONTROLDETAILSF_VALUE);

                    }
                    selectIndex 
=  i;
                    
break // 如果明确找到 MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,break出去

                }
                
if (linesub.dwComponentType  ==  MIXERLINE_COMPONENTTYPE_SRC_ANALOG){ 
                    
// 否则是MIXERLINE_COMPONENTTYPE_SRC_ANALOG的话,保存起来
                    enumData[enumIndex].index  =  i;
                    enumData[enumIndex].dwLineID 
=  linesub.dwLineID;
                    enumData[enumIndex
++ ].szName  =  linesub.szName;
                }
            }

        }
        
if (selectIndex  ==   - 1   &&  enumIndex  <   1 ) {
        ::mixerClose(hMixer);
        
continue ;
    }
        
// 既没有找到MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,也没有找到MIXERLINE_COMPONENTTYPE_SRC_ANALOG.

        DWORD vumLineID;    
// 这个ID用于下面对找到的输出源调整音量
         if (selectIndex  ==   - 1 ){     // 第一次优选,找STEREO
             for (INT i  =   0 ;i  <  enumIndex;i ++ ){
                
if (enumData[i].szName.MakeUpper().Find( " STEREO " !=   - 1 )
                {    
                    selectIndex 
=  enumData[i].index;
                    vumLineID 
=  enumData[i].dwLineID;
                    
break ;
                }
            }
        }
        
if (selectIndex  ==   - 1 ){     // 第二次优选,找MONO
             for (INT i  =   0 ;i  <  enumIndex;i ++ ){
                
if (enumData[i].szName.MakeUpper().Find( " MONO " !=   - 1 )
                {    
                    selectIndex 
=  enumData[i].index;
                    vumLineID 
=  enumData[i].dwLineID;
                    
break ;
                }
            }
        }
        
if (selectIndex  ==   - 1 ){  // 都没有就默认第一个吧.无奈 :(
            selectIndex  =  enumData[ 0 ].index;
            vumLineID 
=  enumData[ 0 ].dwLineID;
        }
        
if (selectIndex  !=   - 1 ){    
                    
// 此时肯selectIndex肯定不为-1,加了条件是想在{}内重新定义mxc,mxlc
                    
// 来设置音量,不和下面的设置选中的mxc,mxlc冲突.
            MIXERCONTROL   mxc;   
            MIXERLINECONTROLS   mxlc;   
            mxlc.cbStruct   
=     sizeof (MIXERLINECONTROLS);   
            mxlc.dwLineID   
=    vumLineID;
            DWORD  dwControlType 
=  MIXERCONTROL_CONTROLTYPE_VOLUME; 
            mxlc.dwControlType   
=    dwControlType;   
            mxlc.cControls   
=     1 ;   
            mxlc.cbmxctrl   
=     sizeof (MIXERCONTROL);   
            mxlc.pamxctrl   
=     & mxc;   
            
if    (::mixerGetLineControls((HMIXEROBJ)hMixer, & mxlc,
                MIXER_OBJECTF_HMIXER
| MIXER_GETLINECONTROLSF_ONEBYTYPE)  ==  MMSYSERR_NOERROR)   
            {   
                MIXERCONTROLDETAILS_BOOLEAN vumVal[
1 ];
                MIXERCONTROLDETAILS   mxcd;   
                mxcd.cbStruct   
=     sizeof (MIXERCONTROLDETAILS);   
                mxcd.dwControlID   
=    mxc.dwControlID;
                mxcd.cChannels   
=     1 ;   
                mxcd.cMultipleItems  
=  mxc.cMultipleItems;  
                mxcd.cbDetails   
=     sizeof (MIXERCONTROLDETAILS_BOOLEAN);   
                mxcd.paDetails   
=   & vumVal;
                vumVal[
0 ].fValue  =   65535 ;
                
// 将设备音量调至最大
                ::mixerSetControlDetails((HMIXEROBJ)hMixer, & mxcd,
                    MIXER_OBJECTF_HMIXER
| MIXER_GETCONTROLDETAILSF_VALUE);

            }


        }
        
// 得到了index就能正确定位该输出源并将其选中,这里调试的时候浪费了很多时间,网上的代码
        
// 都是错误的.录音通道列表和控制面板中录音属性中顺序是一致的,但是对其选中的控件的顺序
        
// 是反的.这一点我调试了好久才发现,没有找到相关文档.KAO,网上可以看到的文章都是错误的.

        found 
= TRUE;
        MIXERCONTROL   mxc;   
        MIXERLINECONTROLS   mxlc;   
        mxlc.cbStruct   
=     sizeof (MIXERLINECONTROLS);   
        mxlc.dwLineID   
=    line.dwLineID;
        
// 注意不能在linesub中查找MIXERCONTROL_CONTROLTYPE_MUX,因为"选中"互斥控件是整个录音控制的
        
// 即 MIXERLINE_COMPONENTTYPE_DST_WAVEIN,不是波形混音输出源所独有的.
        DWORD  dwControlType  =  MIXERCONTROL_CONTROLTYPE_MUX; 
        mxlc.dwControlType   
=    dwControlType;   
        mxlc.cControls   
=     1 ;   
        mxlc.cbmxctrl   
=     sizeof (MIXERCONTROL);   
        mxlc.pamxctrl   
=     & mxc;   
        
if (::mixerGetLineControls((HMIXEROBJ)hMixer, & mxlc,
            MIXER_OBJECTF_HMIXER
| MIXER_GETLINECONTROLSF_ONEBYTYPE)  !=  MMSYSERR_NOERROR)   
        {   
            MessageBox(
" 无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备! " );
            
return    FALSE;   
        }

        MIXERCONTROLDETAILS_BOOLEAN vumVal[
8 ];
        MIXERCONTROLDETAILS  mxcd;   
        mxcd.cbStruct   
=     sizeof (MIXERCONTROLDETAILS);   
        mxcd.dwControlID   
=    mxc.dwControlID;
        mxcd.cChannels   
=     1 ;   
        mxcd.cMultipleItems  
=  mxc.cMultipleItems;  
        mxcd.cbDetails   
=     sizeof (MIXERCONTROLDETAILS_BOOLEAN);   
        mxcd.paDetails   
=& vumVal;

        
if (::mixerGetControlDetails((HMIXEROBJ)hMixer, & mxcd,
            MIXER_OBJECTF_HMIXER
| MIXER_GETCONTROLDETAILSF_VALUE)  !=  MMSYSERR_NOERROR)
        {   
            MessageBox(
" 无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备! " );
            
return    FALSE;   
        }     
        
for (DWORD i  =   0 ;i < mxc.cMultipleItems;i ++ ){
            vumVal[i].fValue 
=  FALSE;
        }
        vumVal[mxc.cMultipleItems
- selectIndex - 1 ].fValue  =  TRUE;
        
// 选中控件顺序和设备顺序相反,TMD
         if (::mixerSetControlDetails((HMIXEROBJ)hMixer, & mxcd,
            MIXER_OBJECTF_HMIXER
| MIXER_GETCONTROLDETAILSF_VALUE)  !=  MMSYSERR_NOERROR)
        {   
            MessageBox(
" 无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备! " );
            
return    FALSE;   
        }      
        ::mixerClose(hMixer);
        
break ;     // 如果到这里已经正确设置了,break出去.
    }
    
if ( ! found){
        MessageBox(
" 没有找到录音设备的混音输出,请手工选择! " );
    }
    
return  TRUE;
}

 

 

另外,因为混音输出是各种声音的在声卡的输出,所以在录音前最好把所有输入源设为禁音,这样可以保证质量.

并将其它的输出源的音量设为最小(这个是否有影响没有测试)

 

 

你可能感兴趣的