windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/audioctl.cpp
2020-09-26 16:20:57 +08:00

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);
}