diff options
Diffstat (limited to 'indra/media_plugins/webkit')
| -rw-r--r-- | indra/media_plugins/webkit/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/media_plugins/webkit/windows_volume_catcher.cpp | 291 | 
2 files changed, 293 insertions, 0 deletions
| 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 <windows.h>
 + +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*> 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. +} + | 
