diff options
author | Richard Nelson <none@none> | 2010-04-27 09:41:33 -0700 |
---|---|---|
committer | Richard Nelson <none@none> | 2010-04-27 09:41:33 -0700 |
commit | bd08f1989461b8b81ed04df6f8dc2097862a20e8 (patch) | |
tree | 491873fa21a9da11d812e4e98410890407ce289e /indra/media_plugins/webkit | |
parent | 3a7490e492b35d5dc55f6124d2e1acbca3bd4d79 (diff) |
EXT-6921 - Windows Xp/Vista unified volume control
Diffstat (limited to 'indra/media_plugins/webkit')
-rw-r--r-- | indra/media_plugins/webkit/windows_volume_catcher.cpp | 246 |
1 files changed, 23 insertions, 223 deletions
diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/webkit/windows_volume_catcher.cpp index 8debe8fac6..fdff28c2c1 100644 --- a/indra/media_plugins/webkit/windows_volume_catcher.cpp +++ b/indra/media_plugins/webkit/windows_volume_catcher.cpp @@ -33,262 +33,62 @@ #include "volume_catcher.h" #include <windows.h> +#include "llsingleton.h" -// -// Abstracts a Win32 mixer line and associated state -// for muting and changing volume on a given output -// -class Mixer -{ -public: - static Mixer* create(U32 index); - ~Mixer(); - - void setMute(bool mute); - void setVolume(F32 volume_left, F32 volume_right); - -private: - // use create(index) to create a Mixer - Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_volume, U32 max_volume); - - HMIXER mHandle; - U32 mMuteControlID; // handle to mixer controller for muting - U32 mVolumeControlID; // handle to mixer controller for changing volume - U32 mMinVolume; // value that specifies minimum volume as reported by mixer - U32 mMaxVolume; // value that specifies maximum volume as reported by mixer -}; - -// factory function that attempts to create a Mixer object associated with a given mixer line index -// returns NULL if creation failed -// static -Mixer* Mixer::create(U32 index) -{ - // get handle to mixer object - HMIXER mixer_handle; - MMRESULT result = mixerOpen( &mixer_handle, - index, - 0, // HWND to call when state changes - not used - 0, // user data for callback - not used - MIXER_OBJECTF_MIXER ); - - if (result == MMSYSERR_NOERROR) - { - MIXERLINE mixer_line; - mixer_line.cbStruct = sizeof( MIXERLINE ); - - // try speakers first - mixer_line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; - - MMRESULT result = mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer_handle ), - &mixer_line, - MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE ); - if (result != MMSYSERR_NOERROR) - { // failed - try headphones next - mixer_line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES; - result = mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer_handle ), - &mixer_line, - MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE ); - } - - if (result == MMSYSERR_NOERROR) - { // successfully found mixer line object, now use it to get volume and mute controls - - // reuse these objects to query for both volume and mute controls - MIXERCONTROL mixer_control; - MIXERLINECONTROLS mixer_line_controls; - mixer_line_controls.cbStruct = sizeof( MIXERLINECONTROLS ); - mixer_line_controls.dwLineID = mixer_line.dwLineID; - mixer_line_controls.cControls = 1; - mixer_line_controls.cbmxctrl = sizeof( MIXERCONTROL ); - mixer_line_controls.pamxctrl = &mixer_control; - - // first, query for mute - mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; - - // get control id for mute controls - result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ), - &mixer_line_controls, - MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ); - if (result == MMSYSERR_NOERROR ) - { // we have a mute controls. Remember the mute control id and then query for - // volume controls using the same struct, but different dwControlType - - U32 mute_control_id = mixer_control.dwControlID; - mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; - result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ), - &mixer_line_controls, - MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ); - - if (result == MMSYSERR_NOERROR) - { // we have both mute and volume controls for this mixer, so we're keeping it - return new Mixer(mixer_handle, - mute_control_id, - mixer_control.dwControlID, - mixer_control.Bounds.dwMinimum, - mixer_control.Bounds.dwMaximum); - } - } - } - } - - // if we got here, we didn't successfully create a Mixer object - mixerClose(mixer_handle); - return NULL; -} - -Mixer::Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_volume, U32 max_volume) -: mHandle(handle), - mMuteControlID(mute_control_id), - mVolumeControlID(volume_control_id), - mMinVolume(min_volume), - mMaxVolume(max_volume) -{} - -Mixer::~Mixer() -{} - -// toggle mute for this mixer -// if mute is set, then volume level will be ignored -void Mixer::setMute(bool mute) -{ - MIXERCONTROLDETAILS_BOOLEAN mixer_control_details_bool = { mute }; - MIXERCONTROLDETAILS mixer_control_details; - mixer_control_details.cbStruct = sizeof( MIXERCONTROLDETAILS ); - mixer_control_details.dwControlID = mMuteControlID; - mixer_control_details.cChannels = 1; - mixer_control_details.cMultipleItems = 0; - mixer_control_details.cbDetails = sizeof( MIXERCONTROLDETAILS_BOOLEAN ); - mixer_control_details.paDetails = &mixer_control_details_bool; - - mixerSetControlDetails( reinterpret_cast< HMIXEROBJ >( mHandle ), - &mixer_control_details, - MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE ); -} - -// set individual volume levels for left and right channels -// if mute is set, then these values will apply once mute is unset -void Mixer::setVolume(F32 volume_left, F32 volume_right) -{ - // assuming pan is in range [-1, 1] set volume levels accordingly - // if pan == -1 then volume_left_mixer = volume_left && volume_right_mixer = 0 - // if pan == 0 then volume_left_mixer = volume_left && volume_right_mixer = volume_right - // if pan == 1 then volume_left_mixer = 0 && volume_right_mixer = volume_right - U32 volume_left_mixer = (U32) - ((F32)mMinVolume - + (volume_left * ((F32)mMaxVolume - (F32)mMinVolume))); - U32 volume_right_mixer = (U32) - ((F32)mMinVolume - + (volume_right * ((F32)mMaxVolume - (F32)mMinVolume))); - - // pass volume levels on to mixer - MIXERCONTROLDETAILS_UNSIGNED mixer_control_details_unsigned[ 2 ] = { volume_left_mixer, volume_right_mixer }; - MIXERCONTROLDETAILS mixer_control_details; - mixer_control_details.cbStruct = sizeof( MIXERCONTROLDETAILS ); - mixer_control_details.dwControlID = mVolumeControlID; - mixer_control_details.cChannels = 2; - mixer_control_details.cMultipleItems = 0; - mixer_control_details.cbDetails = sizeof( MIXERCONTROLDETAILS_UNSIGNED ); - mixer_control_details.paDetails = &mixer_control_details_unsigned; - - mixerSetControlDetails( reinterpret_cast< HMIXEROBJ >( mHandle ), - &mixer_control_details, - MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE ); -} - -class VolumeCatcherImpl +class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl> { +friend LLSingleton<VolumeCatcherImpl>; public: void setVolume(F32 volume); void setPan(F32 pan); - static VolumeCatcherImpl *getInstance(); private: // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. VolumeCatcherImpl(); ~VolumeCatcherImpl(); - static VolumeCatcherImpl *sInstance; - + typedef void (*set_volume_func_t)(F32); + typedef void (*set_mute_func_t)(bool); + + set_volume_func_t mSetVolumeFunc; + set_mute_func_t mSetMuteFunc; + F32 mVolume; F32 mPan; - typedef std::vector<Mixer*> mixer_vector_t; - mixer_vector_t mMixers; }; -VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL; - -VolumeCatcherImpl *VolumeCatcherImpl::getInstance() -{ - if(!sInstance) - { - sInstance = new VolumeCatcherImpl; - } - - return sInstance; -} - VolumeCatcherImpl::VolumeCatcherImpl() : mVolume(1.0f), // default volume is max mPan(0.f) // default pan is centered { - OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later - - ::GetVersionEx((POSVERSIONINFO)&V); - - // disable volume on XP and below - if (V.dwPlatformId == VER_PLATFORM_WIN32_NT && V.dwMajorVersion >= 6) + HMODULE handle = ::LoadLibrary(L"winmm.dll"); + if(handle) { - // for each reported mixer "device", create a proxy object and add to list - U32 num_mixers = mixerGetNumDevs(); - for (U32 mixer_index = 0; mixer_index < num_mixers; ++mixer_index) - { - Mixer* mixerp = Mixer::create(mixer_index); - if (mixerp) - { - mMixers.push_back(mixerp); - } - } + mSetVolumeFunc = (set_volume_func_t)::GetProcAddress(handle, "setPluginVolume"); + mSetMuteFunc = (set_mute_func_t)::GetProcAddress(handle, "setPluginMute"); } } VolumeCatcherImpl::~VolumeCatcherImpl() { - for(mixer_vector_t::iterator it = mMixers.begin(), end_it = mMixers.end(); - it != end_it; - ++it) - { - delete *it; - *it = NULL; - } } void VolumeCatcherImpl::setVolume(F32 volume) { - F32 left_volume = volume * min(1.f, 1.f - mPan); - F32 right_volume = volume * max(0.f, 1.f + mPan); + //F32 left_volume = volume * min(1.f, 1.f - mPan); + //F32 right_volume = volume * max(0.f, 1.f + mPan); - for(mixer_vector_t::iterator it = mMixers.begin(), end_it = mMixers.end(); - it != end_it; - ++it) - { // set volume levels and mute for each mixer - // note that a muted mixer will ignore this volume level - - (*it)->setVolume(left_volume, right_volume); - - if (volume == 0.f && mVolume != 0.f) - { - (*it)->setMute(true); - } - else if (mVolume == 0.f && volume != 0.f) - { - (*it)->setMute(false); - } - - } - mVolume = volume; + if (mSetMuteFunc) + { + mSetMuteFunc(volume == 0.f); + } + if (mSetVolumeFunc) + { + mSetVolumeFunc(mVolume); + } } void VolumeCatcherImpl::setPan(F32 pan) |