📄 px_win_wmme.c
字号:
/* * PortMixer * Windows WMME Implementation * * Copyright (c) 2002 * * Written by Dominic Mazzoni and Augustus Saunders * * PortMixer is intended to work side-by-side with PortAudio, * the Portable Real-Time Audio Library by Ross Bencina and * Phil Burk. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */#include <Windows.h>#include <stdio.h>#include "portaudio.h"#include "pa_host.h"#include "portmixer.h"typedef struct PaWMMEStreamData{ /* Input -------------- */ HWAVEIN hWaveIn; WAVEHDR *inputBuffers; int currentInputBuffer; int bytesPerHostInputBuffer; int bytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ HWAVEOUT hWaveOut;} PaWMMEStreamData;typedef struct PxSrcInfo{ char name[256]; DWORD lineID; DWORD controlID;} PxSrcInfo;typedef struct PxInfo{ HMIXEROBJ hInputMixer; HMIXEROBJ hOutputMixer; int numInputs; PxSrcInfo src[32]; int useMuxID; DWORD muxID; DWORD inputID; DWORD speakerID; DWORD waveID;} PxInfo;// alternate volume control initialization routinesMMRESULT _Px_InitInputVolumeControls( PxInfo* mixer, int hWaveIn ) ;MMRESULT _Px_InitOutputVolumeControls( PxInfo* mixer, int hWaveOut ) ;// toggle microphone boost functionMMRESULT _Px_SetMicrophoneBoost( PxMixer* mixer, int enable ) ;int _Px_GetMicrophoneBoost( PxMixer* mixer ) ;// set input source by nameMMRESULT _Px_SetCurrentInputSourceByName( PxInfo* mixer, const char* line_name ) ;int Px_GetNumMixers( void *pa_stream ){ return 1;}const char *Px_GetMixerName( void *pa_stream, int index ){ return "Mixer";}PxMixer *Px_OpenMixer( void *pa_stream, int index ){ /* initialize new mixer object */ PxInfo* mixer = ( PxMixer* )( malloc( sizeof( PxInfo ) ) ) ; mixer->hInputMixer = NULL ; mixer->hOutputMixer = NULL ; internalPortAudioStream* past = ( internalPortAudioStream* )( pa_stream ) ; PaWMMEStreamData* wmmeStreamData = ( PaWMMEStreamData* )( past->past_DeviceData ) ; MMRESULT result ; if ( wmmeStreamData->hWaveIn != NULL ) { /* initialize input volume controls */ result = _Px_InitInputVolumeControls( ( PxInfo* )( mixer ), ( UINT )( wmmeStreamData->hWaveIn ) ) ; if ( result != MMSYSERR_NOERROR ) { free( mixer ) ; return NULL ; } } if ( wmmeStreamData->hWaveOut != NULL ) { /* initialize output volume controls */ result = _Px_InitOutputVolumeControls( ( PxInfo* )( mixer ), ( UINT )( wmmeStreamData->hWaveOut ) ) ; if ( result != MMSYSERR_NOERROR ) { free( mixer ) ; return NULL ; } } // report found info// fprintf( stdout, "useMuxID => %d, muxID => %u, inputID => %u, speakerID => %u, waveID => %u\n", // mixer->useMuxID, mixer->muxID, mixer->inputID, mixer->speakerID, mixer->waveID ) ; return mixer ;}void VolumeFunction(HMIXEROBJ hMixer, DWORD controlID, PxVolume *volume){ MIXERCONTROLDETAILS details; MMRESULT result; MIXERCONTROLDETAILS_UNSIGNED value; memset(&value, 0, sizeof(MIXERCONTROLDETAILS_UNSIGNED)); details.cbStruct = sizeof(MIXERCONTROLDETAILS); details.dwControlID = controlID; details.cChannels = 1; /* all channels */ details.cMultipleItems = 0; details.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); details.paDetails = &value; result = mixerGetControlDetails(hMixer, &details, MIXER_GETCONTROLDETAILSF_VALUE); if (*volume < 0.0) { *volume = (PxVolume)(value.dwValue / 65535.0); } else { if (result != MMSYSERR_NOERROR) return; value.dwValue = (unsigned short)(*volume * 65535.0); mixerSetControlDetails(hMixer, &details, MIXER_GETCONTROLDETAILSF_VALUE); }}/* Px_CloseMixer() closes a mixer opened using Px_OpenMixer and frees any memory associated with it. */void Px_CloseMixer(PxMixer *mixer){ PxInfo *info = (PxInfo *)mixer; if (info->hInputMixer) mixerClose((HMIXER)info->hInputMixer); if (info->hOutputMixer) mixerClose((HMIXER)info->hOutputMixer); free( mixer );}/* Master (output) volume*/PxVolume Px_GetMasterVolume( PxMixer *mixer ){ PxInfo *info = (PxInfo *)mixer; PxVolume vol; vol = -1.0; VolumeFunction(info->hOutputMixer, info->speakerID, &vol); return vol;}void Px_SetMasterVolume( PxMixer *mixer, PxVolume volume ){ PxInfo *info = (PxInfo *)mixer; VolumeFunction(info->hOutputMixer, info->speakerID, &volume);}/* PCM output volume*/int Px_SupportsPCMOutputVolume( PxMixer* mixer ) { PxInfo* info = ( PxInfo* )( mixer ) ; return ( info->waveID == -1 ) ? 0 : 1 ;}PxVolume Px_GetPCMOutputVolume( PxMixer *mixer ){ PxVolume volume = -1.0 ; PxInfo* info = ( PxInfo* )( mixer ) ; if ( info == NULL ) return volume ; VolumeFunction( info->hOutputMixer, info->waveID, &volume ) ; return volume ;}void Px_SetPCMOutputVolume( PxMixer *mixer, PxVolume volume ){ PxInfo* info = ( PxInfo* )( mixer ) ; if ( info == NULL ) return ; VolumeFunction( info->hOutputMixer, info->waveID, &volume ) ;}/* All output volumes*/int Px_GetNumOutputVolumes( PxMixer *mixer ){ PxInfo *info = (PxInfo *)mixer; return 2;}const char *Px_GetOutputVolumeName( PxMixer *mixer, int i ){ PxInfo *info = (PxInfo *)mixer; if (i==1) return "Wave Out"; else return "Master Volume";}PxVolume Px_GetOutputVolume( PxMixer *mixer, int i ){ PxInfo *info = (PxInfo *)mixer; if (i==1) return Px_GetPCMOutputVolume(mixer); else return Px_GetMasterVolume(mixer);}void Px_SetOutputVolume( PxMixer *mixer, int i, PxVolume volume ){ PxInfo *info = (PxInfo *)mixer; if (i==1) Px_SetPCMOutputVolume(mixer, volume); else Px_SetMasterVolume(mixer, volume);}/* Input sources*/int Px_GetNumInputSources( PxMixer *mixer ){ PxInfo *info = (PxInfo *)mixer; return info->numInputs;}const char *Px_GetInputSourceName( PxMixer *mixer, int i){ PxInfo *info = (PxInfo *)mixer; return info->src[i].name;}int Px_GetCurrentInputSource( PxMixer *mixer ){ PxInfo* info = ( PxInfo* )( mixer ) ; if ( info->useMuxID == 1 ) { MIXERCONTROLDETAILS_BOOLEAN flags[32] ; MIXERCONTROLDETAILS details ; details.cbStruct = sizeof( MIXERCONTROLDETAILS ) ; details.dwControlID = info->muxID ; details.cChannels = 1 ; details.cMultipleItems = info->numInputs ; details.cbDetails = sizeof( MIXERCONTROLDETAILS_BOOLEAN ) ; details.paDetails = ( LPMIXERCONTROLDETAILS_BOOLEAN )&flags[0] ; MMRESULT result = mixerGetControlDetails( ( HMIXEROBJ )( info->hInputMixer ), ( LPMIXERCONTROLDETAILS )&details, MIXER_GETCONTROLDETAILSF_VALUE ) ; if ( result == MMSYSERR_NOERROR ) { int i = 0 ; for ( ; i < info->numInputs ; ++i ) { if ( flags[i].fValue ) return i ; } } else { // !!! handle errors !!! } } else { // use altenate input control id return info->inputID ; } return 0 ;}void Px_SetCurrentInputSource( PxMixer *mixer, int source_index ){ PxInfo* info = ( PxInfo* )( mixer ) ; if ( info->useMuxID == 1 ) { MIXERCONTROLDETAILS_BOOLEAN flags[32] ; memset( &flags, 0x0, sizeof( flags ) ) ; flags[ source_index ].fValue = 1 ; MIXERCONTROLDETAILS details ; details.cbStruct = sizeof( MIXERCONTROLDETAILS ) ; details.dwControlID = info->muxID ; details.cMultipleItems = info->numInputs ; details.cChannels = 1 ; details.cbDetails = sizeof( MIXERCONTROLDETAILS_BOOLEAN ) ; details.paDetails = ( LPMIXERCONTROLDETAILS_BOOLEAN )&flags[0] ; MMRESULT result = mixerSetControlDetails( ( HMIXEROBJ )( info->hInputMixer ), ( LPMIXERCONTROLDETAILS )&details, MIXER_SETCONTROLDETAILSF_VALUE ) ; // !!! handle errors !!! } else { // we don't have a mux or mixer to work with, // so we use the control id directly info->inputID = info->src[source_index].controlID ; } return ;}/* Input volume*/PxVolume Px_GetInputVolume( PxMixer *mixer ){ PxVolume volume = -1.0 ; PxInfo* info = ( PxInfo* )( mixer ) ; if ( info == NULL ) return volume ; if ( info->useMuxID == 1 ) { int src = Px_GetCurrentInputSource( mixer ) ; VolumeFunction( info->hInputMixer, info->src[src].controlID, &volume ) ; } else { VolumeFunction( info->hInputMixer, info->inputID, &volume ) ; } return volume ;}void Px_SetInputVolume( PxMixer *mixer, PxVolume volume ){ PxInfo* info = ( PxInfo* )( mixer ) ; if ( info == NULL ) return ; if ( info->useMuxID == 1 ) { int src = Px_GetCurrentInputSource( mixer ) ; VolumeFunction( info->hInputMixer, info->src[src].controlID, &volume ) ; } else { VolumeFunction( info->hInputMixer, info->inputID, &volume ) ; } return ;}/* Balance*/int Px_SupportsOutputBalance( PxMixer *mixer ){ return 0;}PxBalance Px_GetOutputBalance( PxMixer *mixer ){ return 0.0;}void Px_SetOutputBalance( PxMixer *mixer, PxBalance balance ){}/* Playthrough*/int Px_SupportsPlaythrough( PxMixer *mixer ){ return 0;}PxVolume Px_GetPlaythrough( PxMixer *mixer ){ return 0.0;}void Px_SetPlaythrough( PxMixer *mixer, PxVolume volume ){}//// alternate control initialization functions//MMRESULT_Px_InitInputVolumeControls( PxInfo* mixer, int hWaveIn ) { MMRESULT mmr ; // cast void pointer PxInfo* info = ( PxInfo* )( mixer ) ; if ( info == NULL ) return MMSYSERR_ERROR ; // // open the mixer device // mmr = mixerOpen( ( LPHMIXER )( &mixer->hInputMixer ), ( UINT )( hWaveIn ), 0, 0, MIXER_OBJECTF_HWAVEIN ) ; if ( mmr != MMSYSERR_NOERROR ) return mmr ; // // get the line info for the wavein line // MIXERLINE mixerLine ; mixerLine.cbStruct = sizeof( MIXERLINE ) ; mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN ; mmr = mixerGetLineInfo( ( HMIXEROBJ )( mixer->hInputMixer ), &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE ) ; if ( mmr != MMSYSERR_NOERROR ) { mixerClose( (HMIXER)( mixer->hInputMixer ) ) ; return mmr ; } // we now know the number of inputs mixer->numInputs = mixerLine.cConnections ; // // find a mux or mixer control for the wavein line // // set defaults mixer->useMuxID = 0 ; LPMIXERCONTROL muxControl = malloc( sizeof( MIXERCONTROL ) * mixerLine.cControls ) ; MIXERLINECONTROLS muxLineControls ; muxLineControls.cbStruct = sizeof( MIXERLINECONTROLS ) ; muxLineControls.dwLineID = mixerLine.dwLineID ; muxLineControls.cControls = mixerLine.cControls ; muxLineControls.cbmxctrl = sizeof( MIXERCONTROL ) ; muxLineControls.pamxctrl = ( LPMIXERCONTROL )( muxControl ) ; mmr = mixerGetLineControls( mixer->hInputMixer, &muxLineControls, MIXER_GETLINECONTROLSF_ALL ) ; int i = 0 ; for ( ; i < mixerLine.cControls ; ++i ) { if ( muxControl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX || muxControl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_MIXER ) { // okay, we have a mux control, let's use it mixer->muxID = muxControl[i].dwControlID ; mixer->useMuxID = 1 ; } else if ( muxControl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME ) { // normally the master volume, use as our default inputID mixer->inputID = muxControl[i].dwControlID ; } } free( muxControl ) ; // // gather information about the wavein line volume controls // if ( mixer->useMuxID == 1 ) { // use mux controls MIXERCONTROLDETAILS_LISTTEXT mixList[32] ; MIXERCONTROLDETAILS details ; details.cbStruct = sizeof( MIXERCONTROLDETAILS ) ; details.dwControlID = mixer->muxID ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -