用Mixer API函數實現音頻設置

        如果你用過windows的音頻設備,比如播放音樂或者錄音,聊天,調節麥克或者聲音的大小,以及設置靜音,都可以通過控制面板中的音頻設置面板來調節,你對於下面的兩個設置面板肯定不陌生。 3、下面演示一下如何設置Volume設備的靜音

  這裏提供了兩個函數,GetMute用來獲取系統設置中是否對某個音頻線路進行了靜音操作,SetMute是用來對系統的某個音頻線路進行靜音操作。

BOOL CMixer::SetMute(DWORD dwSrcType, BOOL bValue)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_MUTE))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_BOOLEAN mxcd_f;

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cChannels = 1;
 mxcd.cMultipleItems = 0;
 mxcd.cbDetails = sizeof(mxcd_f);
 mxcd.paDetails = &mxcd_f;
 
 mxcd_f.fValue = bValue;

 if (! SetControlDetails(&mxcd, MIXER_OBJECTF_MIXER))
  return FALSE;

 return TRUE;
}

BOOL CMixer::GetMute(DWORD dwSrcType, BOOL* pbValue)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT ))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_BOOLEAN mxcd_f;

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cChannels = 1;
 mxcd.cMultipleItems = 0;
 mxcd.cbDetails = sizeof(mxcd_f);
 mxcd.paDetails = &mxcd_f;

 if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE))
  return FALSE;

 *pbValue = mxcd_f.fValue;

 return TRUE;
}

  如果用這兩個函數呢,下面我演示瞭如何設置和獲取Volume音頻線路的靜音操作。

BOOL bValue = TRUE;
SetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, bValue);
GetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &bValue);

  4、下面看看當系統的設置改變時,mixer是如何通知我們的吧。

  還記得我前面講過的,當我們調用mixeropen時可以傳遞一個窗口的句柄作爲回調窗口,當系統的設置改變,比如音量改變,某個音頻線路被靜音時,mixer都會給我們的回調窗口發送消息的。

  一般只有兩個消息,如下

afx_msg void OnMLChange(WPARAM wParam, LPARAM lParam);
afx_msg void OnMCChange(WPARAM wParam, LPARAM lParam);

ON_MESSAGE(MM_MIXM_LINE_CHANGE, OnMLChange)
ON_MESSAGE(MM_MIXM_CONTROL_CHANGE, OnMCChange)

  其中MM_MIXM_CONTROL_CHANGE 消息中,發送消息的兩個參數代表的意思如下

wParam = (WPARAM) hMixer
lParam = (LPARAM) dwControlID

  在MM_MIXM_LINE_CHANGE 消息中,發送消息的參數代表的意思如下

wParam = (WPARAM) hMixer
lParam = (LPARAM) dwLineID

  在我們的應用程序中,我們可以在這兩個消息處理函數中調整我們的設置,以對應於系統的改變,比如你的代碼可以這樣寫:

void CMixerControlDlg::OnMCChange(WPARAM wParam, LPARAM lParam)
{
 DWORD dwLValue;
 DWORD dwRValue;
 GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &dwLValue,&dwRValue);
 //GetVolume函數的定義見下面,然後根據返回的值調整滑動條的位置
 m_SliderVolR.SetPos(MAX_VOL_VALUE - dwLValue);
 m_SliderVolL.SetPos(MAX_VOL_VALUE - dwRValue);
 //你也可以在這裏調用GetMute查看Volume是否被靜音,
}


  如此你的程序就可以自動的響應系統設置的改變了。

  關於mixer API的應用開發就介紹到這裏,記着最後要關閉mixer如此:mixerClose(m_hmx);

關於工程的建立我就不多少了,很簡單的,就是一個基於對話框的工程,上面放了一些控件。下面我主要講一下每個功能是如何實現的。主要有三個功能1 如何調整左右聲道音量的大小,2 如何將某個設備靜音,3 如何選擇錄音設備。

  這裏關於mixer函數的用法還要先嘮叨幾句。一般來說,對音頻線路的操作流程如下:

  1、通過GetLineInfo獲取指定音頻線路的信息,返回一個MIXERLINE結構

  2、然後通過GetLineControl獲取音頻線路相關的控制的通用信息,通過MIXERCONTROL結構返回。

  3、通過GetConrolDetails獲取指定控制的屬性值

  4、通過SetControlDetails設置指定控制的屬性值,

  對於每個線路設備,mixer都用一個類型值來標示,比如:

  Volume對應的值 MIXERLINE_COMPONENTTYPE_DST_SPEAKERS

  CD 對於的值 MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC

  Midi對應的值爲 MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER

  Wave對應的值爲 MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT

  Line in對應的值爲 MIXERLINE_COMPONENTTYPE_SRC_LINE

  Microphone對應的值爲 MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE

  我們可以通過音頻線路的類型值獲得相應的線路的信息,也可以通過音頻線路的設備ID來獲取相應的線路的信息。

  下面開始我們編程吧。

  首先定義三個變量

UINT m_uMxId; //mixer的ID
HWND m_hWnd; //回調窗口句柄
HMIXER m_hmx; //

  然後就是要打開mixer,可以在對話的初始化中作這些工作。

#define MAX_VOL_VALUE 65535
if (MMSYSERR_NOERROR != mixerOpen(&m_hmx, m_uMxId,(DWORD)m_hWnd, 0, CALLBACK_WINDOW))
{
 return FALSE;
}
if (MMSYSERR_NOERROR == mixerGetID((HMIXEROBJ)m_hmx, &m_uMxId, MIXER_OBJECTF_HMIXER))
{
 return m_uMxId;
}
//設置Volume的滑動條的範圍這裏只以Volume爲例。
m_SliderWaveL.SetRange(0, MAX_VOL_VALUE, TRUE);
m_SliderWaveR.SetRange(0, MAX_VOL_VALUE, TRUE);

  接着我先演示一下如何獲取和設置錄音設備的左右聲道的音量值,以及如何靜音放音設備,這裏以Volume爲例,其他的設備類似,你可以照着我的代碼,套用即可。

  1、如何獲取Volume設備的音量大小

DWORD dwLValue;
DWORD dwRValue;
GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &dwLValue,&dwRValue);
//GetVolume函數的定義見下面,然後根據返回的值調整滑動條的位置
m_SliderVolR.SetPos(MAX_VOL_VALUE - dwLValue);
m_SliderVolL.SetPos(MAX_VOL_VALUE - dwRValue);

  2、如何根據滑動條的位置來調整系統音量的大小

void CMixerControlDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
 // m_dwSpkR和m_dwSpkL是用來記錄Volume左右聲道的音量值,0~~65535
 CSliderCtrl *pSlider = (CSliderCtrl *)pScrollBar;
 int nValue = MAX_VOL_VALUE - pSlider->GetPos(); //獲取滑動條的位置pos
 else if (m_SliderVolR.m_hWnd == pSlider->m_hWnd)
 {
  //如果拖動的是Volume的左聲道
  m_dwSpkR = nValue;
  // 設置Volume的音量值
  SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, m_dwSpkL, m_dwSpkR);
 }
 else if (m_SliderVolL.m_hWnd == pSlider->m_hWnd)
 {
  //Volume右聲道
  m_dwSpkL = nValue;
  // 設置Volume的音量值
  SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, m_dwSpkL, m_dwSpkR);
 }
 //其他音頻線路可以依次類推在下面添加
}

  GetVolume和SetVolume函數的定義下面給出

BOOL CMixer::SetVolume(DWORD dwSrcType, DWORD dwLValue, DWORD dwRValue, BOOL bMono)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_VOLUME))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_UNSIGNED mxcd_u1;
 MIXERCONTROLDETAILS_UNSIGNED mxcd_u[2];

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cMultipleItems = 0;

 if (bMono)
 {
  mxcd.cChannels = 1;
  mxcd.cbDetails = sizeof(mxcd_u1);
  mxcd.paDetails = &mxcd_u1;
  mxcd_u1.dwValue = dwLValue;
 }
 else
 {
  mxcd.cChannels = mxl.cChannels;
  mxcd.cbDetails = sizeof(*mxcd_u);
  mxcd.paDetails = mxcd_u;
  mxcd_u[0].dwValue = dwLValue;
  mxcd_u[1].dwValue = dwRValue;
 }

 if (! SetControlDetails(&mxcd, MIXER_OBJECTF_MIXER))
  return FALSE;

 return TRUE;
}

BOOL CMixer::GetVolume(DWORD dwSrcType, DWORD* pdwLValue, DWORD* pdwRValue, BOOL bMono)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_VOLUME))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_UNSIGNED mxcd_u1;
 MIXERCONTROLDETAILS_UNSIGNED mxcd_u[2];

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cMultipleItems = 0;

 if (bMono)
 {
  mxcd.cChannels = 1;
  mxcd.cbDetails = sizeof(mxcd_u1);
  mxcd.paDetails = &mxcd_u1;

  if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE))
   return FALSE;

  *pdwLValue = mxcd_u1.dwValue;
 }
 else
 {
  mxcd.cChannels = mxl.cChannels;
  mxcd.cbDetails = sizeof(*mxcd_u);
  mxcd.paDetails = mxcd_u;

  if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE))
   return FALSE;

  *pdwLValue = mxcd_u[0].dwValue;
  *pdwRValue = mxcd_u[1].dwValue;
 }
 return TRUE;
}


BOOL GetLineInfo(LPMIXERLINE pmxl, DWORD dwDstType, DWORD dwSrcType)
{
 MIXERCAPS mxcaps;
 if (! GetDevCaps(&mxcaps))
  return FALSE;

 UINT u=0;
 do
 {
  pmxl->cbStruct = sizeof(*pmxl);
  pmxl->dwDestination = u;
  u++;
  if (MMSYSERR_NOERROR != mixerGetLineControls((HMIXEROBJ)m_uMxId, pmxl, MIXER_GETLINEINFOF_DESTINATION))
  {
   return FALSE;
  }

 } while ((u < mxcaps.cDestinations) && (pmxl->dwComponentType != dwDstType));

 if (u > mxcaps.cDestinations)
  return FALSE;

 if (dwDstType == dwSrcType)
  return TRUE;

 pmxl->dwDestination = u;
 UINT cConnections = (UINT)pmxl->cConnections;

 UINT v=0;
 u--;
 do
 {
  pmxl->cbStruct = sizeof(*pmxl);
  pmxl->dwDestination = u;
  pmxl->dwSource = v;
  v++;

  if (MMSYSERR_NOERROR != mixerGetLineControls((HMIXEROBJ)m_uMxId, pmxl, MIXER_GETLINEINFOF_SOURCE))
  {
   return FALSE;
  }
 } while ((v < cConnections) && (pmxl->dwComponentType != dwSrcType));

 if((v > cConnections) || (pmxl->dwComponentType !=dwSrcType))
  return FALSE;

 return TRUE;
}

BOOL GetLineControl(LPMIXERCONTROL pmxc, LPMIXERLINE pmxl, DWORD dwType)
{
 LPMIXERCONTROL pamxctrl;
 DWORD cbmxctrls = sizeof(*pamxctrl) * (UINT)pmxl->cControls;
 pamxctrl = (LPMIXERCONTROL)LocalAlloc(LPTR, cbmxctrls);

 MIXERLINECONTROLS mxlc;
 mxlc.cbStruct = sizeof(mxlc);
 mxlc.dwLineID = pmxl->dwLineID;
 mxlc.dwControlType = dwType;
 mxlc.cControls = pmxl->cControls;
 mxlc.cbmxctrl = sizeof(*pamxctrl);
 mxlc.pamxctrl = pamxctrl;

 if (MMSYSERR_NOERROR != mixerGetControlDetails((HMIXEROBJ)m_uMxId, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE))
 {
  return FALSE;
 }
 memcpy(pmxc, pamxctrl, sizeof(*pamxctrl));
 LocalFree(pamxctrl);
 return TRUE;
}

3、下面演示一下如何設置Volume設備的靜音

  這裏提供了兩個函數,GetMute用來獲取系統設置中是否對某個音頻線路進行了靜音操作,SetMute是用來對系統的某個音頻線路進行靜音操作。

BOOL CMixer::SetMute(DWORD dwSrcType, BOOL bValue)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_MUTE))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_BOOLEAN mxcd_f;

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cChannels = 1;
 mxcd.cMultipleItems = 0;
 mxcd.cbDetails = sizeof(mxcd_f);
 mxcd.paDetails = &mxcd_f;
 
 mxcd_f.fValue = bValue;

 if (! SetControlDetails(&mxcd, MIXER_OBJECTF_MIXER))
  return FALSE;

 return TRUE;
}

BOOL CMixer::GetMute(DWORD dwSrcType, BOOL* pbValue)
{
 MIXERLINE mxl;
 if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType))
  return FALSE;

 MIXERCONTROL mxc;
 if (! GetLineControl(&mxc, &mxl, MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT ))
  return FALSE;

 MIXERCONTROLDETAILS mxcd;
 MIXERCONTROLDETAILS_BOOLEAN mxcd_f;

 mxcd.cbStruct = sizeof(mxcd);
 mxcd.dwControlID = mxc.dwControlID;
 mxcd.cChannels = 1;
 mxcd.cMultipleItems = 0;
 mxcd.cbDetails = sizeof(mxcd_f);
 mxcd.paDetails = &mxcd_f;

 if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE))
  return FALSE;

 *pbValue = mxcd_f.fValue;

 return TRUE;
}

  如果用這兩個函數呢,下面我演示瞭如何設置和獲取Volume音頻線路的靜音操作。

BOOL bValue = TRUE;
SetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, bValue);
GetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &bValue);

  4、下面看看當系統的設置改變時,mixer是如何通知我們的吧。

  還記得我前面講過的,當我們調用mixeropen時可以傳遞一個窗口的句柄作爲回調窗口,當系統的設置改變,比如音量改變,某個音頻線路被靜音時,mixer都會給我們的回調窗口發送消息的。

  一般只有兩個消息,如下

afx_msg void OnMLChange(WPARAM wParam, LPARAM lParam);
afx_msg void OnMCChange(WPARAM wParam, LPARAM lParam);

ON_MESSAGE(MM_MIXM_LINE_CHANGE, OnMLChange)
ON_MESSAGE(MM_MIXM_CONTROL_CHANGE, OnMCChange)

  其中MM_MIXM_CONTROL_CHANGE 消息中,發送消息的兩個參數代表的意思如下

wParam = (WPARAM) hMixer
lParam = (LPARAM) dwControlID

  在MM_MIXM_LINE_CHANGE 消息中,發送消息的參數代表的意思如下

wParam = (WPARAM) hMixer
lParam = (LPARAM) dwLineID

  在我們的應用程序中,我們可以在這兩個消息處理函數中調整我們的設置,以對應於系統的改變,比如你的代碼可以這樣寫:

void CMixerControlDlg::OnMCChange(WPARAM wParam, LPARAM lParam)
{
 DWORD dwLValue;
 DWORD dwRValue;
 GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &dwLValue,&dwRValue);
 //GetVolume函數的定義見下面,然後根據返回的值調整滑動條的位置
 m_SliderVolR.SetPos(MAX_VOL_VALUE - dwLValue);
 m_SliderVolL.SetPos(MAX_VOL_VALUE - dwRValue);
 //你也可以在這裏調用GetMute查看Volume是否被靜音,
}

  如此你的程序就可以自動的響應系統設置的改變了。

  關於mixer API的應用開發就介紹到這裏,記着最後要關閉mixer如此:mixerClose(m_hmx);
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章