From ba35fdd97c0eedb698a026f889092caa1c41b61b Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 15 Apr 2010 17:22:35 -0700 Subject: EXT-6888 - Implement per-media instance volume control --- indra/media_plugins/webkit/CMakeLists.txt | 2 + .../webkit/windows_volume_catcher.cpp | 291 +++++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 indra/media_plugins/webkit/windows_volume_catcher.cpp (limited to 'indra/media_plugins') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 4f183cddeb..40722622a4 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -59,6 +59,8 @@ elseif (DARWIN) ${CORESERVICES_LIBRARY} # for Component Manager calls ${AUDIOUNIT_LIBRARY} # for AudioUnit calls ) +elseif (WINDOWS) + list(APPEND media_plugin_webkit_SOURCE_FILES windows_volume_catcher.cpp) else (LINUX AND PULSEAUDIO) # All other platforms use the dummy volume catcher for now. list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp) diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/webkit/windows_volume_catcher.cpp new file mode 100644 index 0000000000..b01986db56 --- /dev/null +++ b/indra/media_plugins/webkit/windows_volume_catcher.cpp @@ -0,0 +1,291 @@ +/** + * @file windows_volume_catcher.cpp + * @brief A Windows implementation of volume level control of all audio channels opened by a process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + * @endcond + */ + +#include "volume_catcher.h" +#include + +class Mixer +{ +public: + static Mixer* create(U32 index); + ~Mixer(); + + void setMute(bool mute); + void setVolume(F32 volume_left, F32 volume_right); + +private: + Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_volume, U32 max_volume); + + HMIXER mHandle; + U32 mMuteControlID; + U32 mVolumeControlID; + U32 mMinVolume; + U32 mMaxVolume; +}; + +Mixer* Mixer::create(U32 index) +{ + 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) + { + // get control id + MIXERCONTROL mixer_control; + MIXERLINECONTROLS mixer_line_controls; + mixer_line_controls.cbStruct = sizeof( MIXERLINECONTROLS ); + mixer_line_controls.dwLineID = mixer_line.dwLineID; + mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; + mixer_line_controls.cControls = 1; + mixer_line_controls.cbmxctrl = sizeof( MIXERCONTROL ); + mixer_line_controls.pamxctrl = &mixer_control; + + result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ), + &mixer_line_controls, + MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ); + if (result == MMSYSERR_NOERROR ) + { + // We have a mute mixer. Remember the mute control id + U32 mute_control_id = mixer_control.dwControlID; + + // now query for volume controls + 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 remember it + return new Mixer(mixer_handle, + mute_control_id, + mixer_control.dwControlID, + mixer_control.Bounds.dwMinimum, + mixer_control.Bounds.dwMaximum); + } + } + } + } + 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() +{ +} + +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 ); +} + +void Mixer::setVolume(F32 volume_left, F32 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))); + 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 +{ +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; + + F32 mVolume; + F32 mPan; + typedef std::vector 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), + mPan(0.f) // 0 is centered +{ + 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); + } + } +} + +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); + + for(mixer_vector_t::iterator it = mMixers.begin(), end_it = mMixers.end(); + it != end_it; + ++it) + { + (*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; +} + +void VolumeCatcherImpl::setPan(F32 pan) +{ + mPan = pan; +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = VolumeCatcherImpl::getInstance(); +} + +VolumeCatcher::~VolumeCatcher() +{ + // Let the instance persist until exit. +} + +void VolumeCatcher::setVolume(F32 volume) +{ + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ + // No periodic tasks are necessary for this implementation. +} + -- cgit v1.2.3 From e6daa50c5878885b27f4145eeeeee9745e12086a Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Fri, 16 Apr 2010 12:10:57 -0700 Subject: windows_volume_catcher.cpp, now with comments! also added volume_catcher.h to project --- indra/media_plugins/webkit/CMakeLists.txt | 9 + .../webkit/windows_volume_catcher.cpp | 209 ++++++++++++--------- 2 files changed, 126 insertions(+), 92 deletions(-) (limited to 'indra/media_plugins') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index 40722622a4..c33a26b637 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -36,6 +36,10 @@ set(media_plugin_webkit_SOURCE_FILES media_plugin_webkit.cpp ) +set(media_plugin_webkit_HEADER_FILES + volume_catcher.h + ) + set(media_plugin_webkit_LINK_LIBRARIES ${LLPLUGIN_LIBRARIES} ${MEDIA_PLUGIN_BASE_LIBRARIES} @@ -66,6 +70,11 @@ else (LINUX AND PULSEAUDIO) list(APPEND media_plugin_webkit_SOURCE_FILES dummy_volume_catcher.cpp) endif (LINUX AND PULSEAUDIO) +set_source_files_properties(${media_plugin_webkit_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND media_plugin_webkit_SOURCE_FILES ${media_plugin_webkit_HEADER_FILES}) + add_library(media_plugin_webkit SHARED ${media_plugin_webkit_SOURCE_FILES} diff --git a/indra/media_plugins/webkit/windows_volume_catcher.cpp b/indra/media_plugins/webkit/windows_volume_catcher.cpp index b01986db56..1c1ef0b42f 100644 --- a/indra/media_plugins/webkit/windows_volume_catcher.cpp +++ b/indra/media_plugins/webkit/windows_volume_catcher.cpp @@ -32,8 +32,12 @@ */ #include "volume_catcher.h" -#include +#include +// +// Abstracts a Win32 mixer line and associated state +// for muting and changing volume on a given output +// class Mixer { public: @@ -44,81 +48,91 @@ public: 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; - U32 mVolumeControlID; - U32 mMinVolume; - U32 mMaxVolume; + 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 ); + 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 + 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 ); - } + 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) - { - // get control id - MIXERCONTROL mixer_control; - MIXERLINECONTROLS mixer_line_controls; - mixer_line_controls.cbStruct = sizeof( MIXERLINECONTROLS ); - mixer_line_controls.dwLineID = mixer_line.dwLineID; - mixer_line_controls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; - mixer_line_controls.cControls = 1; - mixer_line_controls.cbmxctrl = sizeof( MIXERCONTROL ); - mixer_line_controls.pamxctrl = &mixer_control; - - result = mixerGetLineControls( reinterpret_cast< HMIXEROBJ >( mixer_handle ), - &mixer_line_controls, - MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE ); - if (result == MMSYSERR_NOERROR ) - { - // We have a mute mixer. Remember the mute control id - U32 mute_control_id = mixer_control.dwControlID; - - // now query for volume controls - 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 remember it - return new Mixer(mixer_handle, - mute_control_id, - mixer_control.dwControlID, - mixer_control.Bounds.dwMinimum, - mixer_control.Bounds.dwMaximum); - } - } - } + { // 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; } @@ -131,47 +145,55 @@ Mixer::Mixer(HMIXER handle, U32 mute_control_id, U32 volume_control_id, U32 min_ {} 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 ); + 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))); - 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 ); -} + // 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 { @@ -207,9 +229,10 @@ VolumeCatcherImpl *VolumeCatcherImpl::getInstance() } VolumeCatcherImpl::VolumeCatcherImpl() -: mVolume(1.0f), - mPan(0.f) // 0 is centered +: mVolume(1.0f), // default volume is max + mPan(0.f) // default pan is centered { + // 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) { @@ -241,7 +264,9 @@ void VolumeCatcherImpl::setVolume(F32 volume) 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) @@ -258,7 +283,7 @@ void VolumeCatcherImpl::setVolume(F32 volume) } void VolumeCatcherImpl::setPan(F32 pan) -{ +{ // remember pan for calculating individual channel levels later mPan = pan; } -- cgit v1.2.3 From 8cb7af4f73c0a703b5842a708e94d80aea26b6db Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Fri, 16 Apr 2010 14:48:05 -0700 Subject: removed tabs from cmakelist.txt --- indra/media_plugins/webkit/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/media_plugins') diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt index c33a26b637..1a559ed39c 100644 --- a/indra/media_plugins/webkit/CMakeLists.txt +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -37,9 +37,9 @@ set(media_plugin_webkit_SOURCE_FILES ) set(media_plugin_webkit_HEADER_FILES - volume_catcher.h - ) - + volume_catcher.h + ) + set(media_plugin_webkit_LINK_LIBRARIES ${LLPLUGIN_LIBRARIES} ${MEDIA_PLUGIN_BASE_LIBRARIES} -- cgit v1.2.3