windows_volume_catcher.cpp, now with comments!

also added volume_catcher.h to project
meow-7.2.2
Richard Linden 2010-04-16 12:10:57 -07:00
parent 882436ba06
commit e6daa50c58
2 changed files with 126 additions and 92 deletions

View File

@ -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}

View File

@ -32,8 +32,12 @@
*/
#include "volume_catcher.h"
#include <windows.h>
#include <windows.h>
//
// 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;
}