508 lines
11 KiB
C++
508 lines
11 KiB
C++
|
// File: audioctl.cpp
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include "resource.h"
|
||
|
#include "audioctl.h"
|
||
|
#include "mixer.h"
|
||
|
#include "confpolicies.h"
|
||
|
|
||
|
CAudioControl::CAudioControl(HWND hwnd) :
|
||
|
m_pRecMixer(NULL),
|
||
|
m_pSpkMixer(NULL),
|
||
|
m_fMicMuted(FALSE),
|
||
|
m_fSpkMuted(FALSE),
|
||
|
m_pChannelMic(NULL),
|
||
|
m_pChannelSpk(NULL),
|
||
|
m_pAudioEvent(NULL),
|
||
|
m_dwRecordDevice(0),
|
||
|
m_dwPlaybackDevice(0),
|
||
|
m_dwSilenceLevel(DEFAULT_MICROPHONE_SENSITIVITY * 10),
|
||
|
m_hwndParent(hwnd)
|
||
|
{
|
||
|
m_dwMicVolume.leftVolume = 0xFFFFFFFF,
|
||
|
m_dwMicVolume.rightVolume = 0xFFFFFFFF;
|
||
|
m_dwSpkVolume.leftVolume = 0xFFFFFFFF;
|
||
|
m_dwSpkVolume.rightVolume = 0xFFFFFFFF;
|
||
|
m_dwSpkVolumeOld.leftVolume = 0xFFFFFFFF;
|
||
|
m_dwSpkVolumeOld.rightVolume = 0xFFFFFFFF;
|
||
|
|
||
|
LoadSettings();
|
||
|
OnDeviceChanged();
|
||
|
OnAGC_Changed();
|
||
|
OnSilenceLevelChanged();
|
||
|
}
|
||
|
|
||
|
CAudioControl::~CAudioControl()
|
||
|
{
|
||
|
SaveSettings();
|
||
|
|
||
|
// restore speaker volume
|
||
|
if (m_pSpkMixer && (m_dwSpkVolumeOld.leftVolume <= 0x0000ffff || m_dwSpkVolumeOld.rightVolume <= 0x0000ffff))
|
||
|
{
|
||
|
m_pSpkMixer->SetVolume(&m_dwSpkVolumeOld);
|
||
|
}
|
||
|
|
||
|
|
||
|
delete m_pRecMixer;
|
||
|
delete m_pSpkMixer;
|
||
|
|
||
|
if (NULL != m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic->Release();
|
||
|
}
|
||
|
if (NULL != m_pChannelSpk)
|
||
|
{
|
||
|
m_pChannelSpk->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CLASS: CAudioControl
|
||
|
*
|
||
|
* MEMBER: OnChannelChanged()
|
||
|
*
|
||
|
* PURPOSE: Tracks audio channel changes
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void CAudioControl::OnChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pChannel)
|
||
|
{
|
||
|
INmChannelAudio* pChannelAudio;
|
||
|
if (SUCCEEDED(pChannel->QueryInterface(IID_INmChannelAudio, (void**)&pChannelAudio)))
|
||
|
{
|
||
|
if (S_OK == pChannelAudio->IsActive())
|
||
|
{
|
||
|
if (S_OK == pChannelAudio->IsIncoming())
|
||
|
{
|
||
|
if (NULL == m_pChannelSpk)
|
||
|
{
|
||
|
m_pChannelSpk = pChannelAudio;
|
||
|
m_pChannelSpk->AddRef();
|
||
|
m_pChannelSpk->SetProperty(NM_AUDPROP_PAUSE, m_fSpkMuted);
|
||
|
m_pChannelSpk->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwPlaybackDevice);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (NULL == m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic = pChannelAudio;
|
||
|
m_pChannelMic->AddRef();
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_PAUSE, m_fMicMuted);
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_LEVEL, m_dwSilenceLevel);
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwRecordDevice);
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_AUTOMIX, m_fAutoMix);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (S_OK == pChannelAudio->IsIncoming())
|
||
|
{
|
||
|
// were done with the speaker channel
|
||
|
if (pChannelAudio == m_pChannelSpk)
|
||
|
{
|
||
|
m_pChannelSpk->Release();
|
||
|
m_pChannelSpk = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// were done with the speaker channel
|
||
|
if (pChannelAudio == m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic->Release();
|
||
|
m_pChannelMic = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pChannelAudio->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CLASS: CAudioControl
|
||
|
*
|
||
|
* MEMBER: RefreshMixer()
|
||
|
*
|
||
|
* PURPOSE: Refreshes all controls that are mixer dependent
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
void CAudioControl::RefreshMixer()
|
||
|
{
|
||
|
if (NULL != m_pSpkMixer)
|
||
|
{
|
||
|
MIXVOLUME dwVol;
|
||
|
BOOL fValid;
|
||
|
fValid = m_pSpkMixer->GetVolume(&dwVol);
|
||
|
|
||
|
if (fValid && (dwVol.leftVolume != m_dwSpkVolume.leftVolume || dwVol.rightVolume != m_dwSpkVolume.rightVolume))
|
||
|
{
|
||
|
m_dwSpkVolume.leftVolume = dwVol.leftVolume;
|
||
|
m_dwSpkVolume.rightVolume = dwVol.rightVolume;
|
||
|
|
||
|
if (NULL != m_pAudioEvent)
|
||
|
{
|
||
|
m_pAudioEvent->OnLevelChange(TRUE /* fSpeaker */, max(m_dwSpkVolume.leftVolume , m_dwSpkVolume.rightVolume));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != m_pRecMixer)
|
||
|
{
|
||
|
BOOL fChanged = FALSE;
|
||
|
|
||
|
MIXVOLUME dwMainVol = {0,0};
|
||
|
BOOL fValidMain = m_pRecMixer->GetMainVolume(&dwMainVol);
|
||
|
|
||
|
MIXVOLUME dwMicVol = {0,0};
|
||
|
BOOL fValidMic = m_pRecMixer->GetSubVolume(&dwMicVol);
|
||
|
|
||
|
if (fValidMain && (m_dwMicVolume.leftVolume != dwMainVol.leftVolume || m_dwMicVolume.rightVolume != dwMainVol.rightVolume))
|
||
|
{
|
||
|
m_dwMicVolume.leftVolume = dwMainVol.leftVolume;
|
||
|
m_dwMicVolume.rightVolume = dwMainVol.rightVolume;
|
||
|
|
||
|
// Force the mic vol to equal the main vol
|
||
|
SetRecorderVolume(&dwMainVol);
|
||
|
fChanged = TRUE;
|
||
|
}
|
||
|
else if (fValidMic && (m_dwMicVolume.leftVolume != dwMicVol.leftVolume || m_dwMicVolume.rightVolume != dwMicVol.rightVolume))
|
||
|
{
|
||
|
m_dwMicVolume.leftVolume = dwMicVol.leftVolume;
|
||
|
m_dwMicVolume.rightVolume = dwMicVol.rightVolume;
|
||
|
|
||
|
// Force the main vol to equal the mic vol
|
||
|
SetRecorderVolume(&dwMicVol);
|
||
|
fChanged = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fChanged)
|
||
|
{
|
||
|
if (NULL != m_pAudioEvent)
|
||
|
{
|
||
|
m_pAudioEvent->OnLevelChange(FALSE /* fSpeaker */, max(m_dwMicVolume.leftVolume , m_dwMicVolume.rightVolume));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CLASS: CAudioControl
|
||
|
*
|
||
|
* MEMBER: MuteAudio(BOOL fSpeaker, BOOL fMute)
|
||
|
*
|
||
|
* PURPOSE: Internal routine to mute an audio device
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
VOID CAudioControl::MuteAudio(BOOL fSpeaker, BOOL fMute)
|
||
|
{
|
||
|
INmChannelAudio *pChannel;
|
||
|
if (fSpeaker)
|
||
|
{
|
||
|
m_fSpkMuted = fMute;
|
||
|
pChannel = m_pChannelSpk;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_fMicMuted = fMute;
|
||
|
pChannel = m_pChannelMic;
|
||
|
}
|
||
|
|
||
|
if (NULL != pChannel)
|
||
|
{
|
||
|
pChannel->SetProperty(NM_AUDPROP_PAUSE, fMute);
|
||
|
}
|
||
|
|
||
|
if (NULL != m_pAudioEvent)
|
||
|
{
|
||
|
m_pAudioEvent->OnMuteChange(fSpeaker, fMute);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CLASS: CAudioControl
|
||
|
*
|
||
|
* MEMBER: GetAudioSignalLevel(BOOL fSpeaker)
|
||
|
*
|
||
|
* PURPOSE: Internal routine to get the audio signal level
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
DWORD CAudioControl::GetAudioSignalLevel(BOOL fSpeaker)
|
||
|
{
|
||
|
DWORD_PTR dwLevel = 0;
|
||
|
INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
|
||
|
|
||
|
if (NULL != pChannel)
|
||
|
{
|
||
|
pChannel->GetProperty(NM_AUDPROP_LEVEL, &dwLevel);
|
||
|
}
|
||
|
|
||
|
return (DWORD)dwLevel;
|
||
|
}
|
||
|
|
||
|
BOOL CAudioControl::CanSetRecorderVolume()
|
||
|
{
|
||
|
if (NULL != m_pRecMixer)
|
||
|
{
|
||
|
return m_pRecMixer->CanSetVolume();
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CAudioControl::CanSetSpeakerVolume()
|
||
|
{
|
||
|
if (NULL != m_pSpkMixer)
|
||
|
{
|
||
|
return m_pSpkMixer->CanSetVolume();
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void CAudioControl::SetRecorderVolume(MIXVOLUME * pdwVolume)
|
||
|
{
|
||
|
if (NULL != m_pRecMixer)
|
||
|
{
|
||
|
m_pRecMixer->SetVolume(pdwVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CAudioControl::SetSpeakerVolume(MIXVOLUME * pdwVolume)
|
||
|
{
|
||
|
if (NULL != m_pSpkMixer)
|
||
|
{
|
||
|
m_pSpkMixer->SetVolume(pdwVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CAudioControl::GetRecorderVolume(MIXVOLUME * pdwVolume)
|
||
|
{
|
||
|
if (NULL != m_pRecMixer)
|
||
|
{
|
||
|
m_pRecMixer->GetVolume(pdwVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CAudioControl::GetSpeakerVolume(MIXVOLUME * pdwVolume)
|
||
|
{
|
||
|
if (NULL != m_pSpkMixer)
|
||
|
{
|
||
|
m_pSpkMixer->GetVolume(pdwVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CAudioControl::SetRecorderVolume(DWORD dwVolume)
|
||
|
{
|
||
|
MIXVOLUME mixVol;
|
||
|
MIXVOLUME mixNewVol;
|
||
|
|
||
|
GetRecorderVolume(&mixVol);
|
||
|
|
||
|
NewMixVolume(&mixNewVol, mixVol, dwVolume);
|
||
|
|
||
|
SetRecorderVolume(&mixNewVol);
|
||
|
|
||
|
}
|
||
|
|
||
|
void CAudioControl::SetSpeakerVolume(DWORD dwVolume)
|
||
|
{
|
||
|
MIXVOLUME mixVol;
|
||
|
MIXVOLUME mixNewVol;
|
||
|
|
||
|
GetSpeakerVolume(&mixVol);
|
||
|
|
||
|
NewMixVolume(&mixNewVol, mixVol, dwVolume);
|
||
|
|
||
|
SetSpeakerVolume(&mixNewVol);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void CAudioControl::OnDeviceChanged()
|
||
|
{
|
||
|
MIXVOLUME dwMicVolume;
|
||
|
DWORD dwNewPlaybackDevice;
|
||
|
|
||
|
RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER );
|
||
|
|
||
|
dwNewPlaybackDevice = re.GetNumber(REGVAL_WAVEOUTDEVICEID, 0);
|
||
|
|
||
|
// restore the speaker setting before changing to the new device
|
||
|
// verify that we aren't changing to the same device
|
||
|
if (m_pSpkMixer && (m_dwSpkVolumeOld.leftVolume <= 0x0000ffff || m_dwSpkVolumeOld.rightVolume <= 0x0000ffff) &&
|
||
|
(m_dwPlaybackDevice != dwNewPlaybackDevice) )
|
||
|
{
|
||
|
m_pSpkMixer->SetVolume(&m_dwSpkVolumeOld);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Initialize the proper record/playback devices:
|
||
|
delete m_pRecMixer;
|
||
|
m_dwRecordDevice = re.GetNumber(REGVAL_WAVEINDEVICEID, 0);
|
||
|
m_pRecMixer = CMixerDevice::GetMixerForWaveDevice(
|
||
|
m_hwndParent,
|
||
|
m_dwRecordDevice,
|
||
|
MIXER_OBJECTF_WAVEIN);
|
||
|
|
||
|
delete m_pSpkMixer;
|
||
|
m_dwPlaybackDevice = dwNewPlaybackDevice;
|
||
|
m_pSpkMixer = CMixerDevice::GetMixerForWaveDevice(
|
||
|
m_hwndParent,
|
||
|
m_dwPlaybackDevice,
|
||
|
MIXER_OBJECTF_WAVEOUT);
|
||
|
|
||
|
if (NULL != m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwRecordDevice);
|
||
|
}
|
||
|
|
||
|
if (NULL != m_pChannelSpk)
|
||
|
{
|
||
|
m_pChannelSpk->SetProperty(NM_AUDPROP_WAVE_DEVICE, m_dwPlaybackDevice);
|
||
|
}
|
||
|
|
||
|
// restore the microphone setting from whatever it was in the tuning wizard
|
||
|
if (m_pRecMixer)
|
||
|
{
|
||
|
dwMicVolume.leftVolume = dwMicVolume.rightVolume = re.GetNumber(REGVAL_CALIBRATEDVOL, 0x00ff);
|
||
|
m_pRecMixer->SetVolume(&dwMicVolume);
|
||
|
}
|
||
|
|
||
|
// remember the old speaker volume
|
||
|
if (m_pSpkMixer)
|
||
|
{
|
||
|
m_pSpkMixer->GetVolume(&m_dwSpkVolumeOld);
|
||
|
}
|
||
|
|
||
|
|
||
|
RefreshMixer();
|
||
|
}
|
||
|
|
||
|
void CAudioControl::OnAGC_Changed()
|
||
|
{
|
||
|
RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
|
||
|
|
||
|
BOOL fAgc = ( reAudio.GetNumber(REGVAL_AUTOGAIN,AUTOGAIN_ENABLED) == AUTOGAIN_ENABLED );
|
||
|
|
||
|
|
||
|
m_fAutoMix = (reAudio.GetNumber(REGVAL_AUTOMIX, AUTOMIX_ENABLED) == AUTOMIX_ENABLED);
|
||
|
|
||
|
if (NULL != m_pRecMixer)
|
||
|
{
|
||
|
m_pRecMixer->SetAGC(fAgc);
|
||
|
}
|
||
|
|
||
|
if (NULL != m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_AUTOMIX, m_fAutoMix);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CAudioControl::OnSilenceLevelChanged()
|
||
|
{
|
||
|
RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
|
||
|
|
||
|
if (MICROPHONE_AUTO_NO == reAudio.GetNumber(REGVAL_MICROPHONE_AUTO,
|
||
|
MICROPHONE_AUTO_YES))
|
||
|
{
|
||
|
// Use "manual" mode:
|
||
|
|
||
|
// BUGBUG - there is a mismatch in terminology between
|
||
|
// "sensitivity" and "threshhold", which reverses the
|
||
|
// sense of this value. A low threshhold implies a high
|
||
|
// sensitivity, etc.
|
||
|
// Reverse the sense of this value before setting the
|
||
|
// Nac value, and resolve the terminology problem later.
|
||
|
// PROP_SILENCE_LEVEL property is in units of 0.1%, so scale it.
|
||
|
m_dwSilenceLevel = (MAX_MICROPHONE_SENSITIVITY -
|
||
|
reAudio.GetNumber(REGVAL_MICROPHONE_SENSITIVITY,
|
||
|
DEFAULT_MICROPHONE_SENSITIVITY))*10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Use "automatic" mode: This is actually controlled by
|
||
|
// PROP_SILENCE_LEVEL. If at maximum (100%), then it is
|
||
|
// in "automatic" mode
|
||
|
m_dwSilenceLevel = 100*10; // remember units are 0.1%
|
||
|
|
||
|
}
|
||
|
|
||
|
if (NULL != m_pChannelMic)
|
||
|
{
|
||
|
m_pChannelMic->SetProperty(NM_AUDPROP_LEVEL, m_dwSilenceLevel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL CAudioControl::LoadSettings()
|
||
|
{
|
||
|
RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
|
||
|
|
||
|
m_fSpkMuted = reAudio.GetNumber(REGVAL_SPKMUTE, FALSE);
|
||
|
m_fMicMuted = reAudio.GetNumber(REGVAL_RECMUTE, FALSE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CAudioControl::SaveSettings()
|
||
|
{
|
||
|
RegEntry reAudio( AUDIO_KEY, HKEY_CURRENT_USER );
|
||
|
|
||
|
reAudio.SetValue(REGVAL_SPKMUTE, m_fSpkMuted);
|
||
|
reAudio.SetValue(REGVAL_RECMUTE, m_fMicMuted);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check if the microphone got changed during this section
|
||
|
//
|
||
|
if(m_pRecMixer)
|
||
|
{
|
||
|
MIXVOLUME dwMicVol = {0,0};
|
||
|
m_pRecMixer->GetVolume(&dwMicVol);
|
||
|
|
||
|
DWORD oldVolume = reAudio.GetNumber(REGVAL_CALIBRATEDVOL, 0x00ff);
|
||
|
DWORD newVolume = max(dwMicVol.leftVolume,dwMicVol.rightVolume);
|
||
|
|
||
|
if(oldVolume != newVolume)
|
||
|
{
|
||
|
reAudio.SetValue(REGVAL_CALIBRATEDVOL, newVolume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HRESULT CAudioControl::SetProperty(BOOL fSpeaker, NM_AUDPROP uID, ULONG_PTR uValue)
|
||
|
{
|
||
|
INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
|
||
|
if (NULL != pChannel)
|
||
|
{
|
||
|
return(pChannel->SetProperty(uID, uValue));
|
||
|
}
|
||
|
|
||
|
return(E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
HRESULT CAudioControl::GetProperty(BOOL fSpeaker, NM_AUDPROP uID, ULONG_PTR *puValue)
|
||
|
{
|
||
|
INmChannelAudio *pChannel = fSpeaker ? m_pChannelSpk : m_pChannelMic;
|
||
|
if (NULL != pChannel)
|
||
|
{
|
||
|
return(pChannel->GetProperty(uID, puValue));
|
||
|
}
|
||
|
|
||
|
return(E_UNEXPECTED);
|
||
|
}
|
||
|
|