From 403eee4d871d389a54e9e3b41dca092d7eac9bac Mon Sep 17 00:00:00 2001 From: Lev Zelenskiy Date: Wed, 25 Jul 2012 13:23:57 +1000 Subject: [PATCH] Volume control for QAudioInput windows backend. Change-Id: I1245a38c68254fc48373a856dc44e8ad8142636e Reviewed-by: Ling Hu --- src/multimedia/audio/qaudioinput_win32_p.cpp | 108 +++++++++++++++++++++++++++ src/multimedia/audio/qaudioinput_win32_p.h | 7 ++ 2 files changed, 115 insertions(+) diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp index 1ed68d2..a5e124c 100644 --- a/src/multimedia/audio/qaudioinput_win32_p.cpp +++ b/src/multimedia/audio/qaudioinput_win32_p.cpp @@ -72,11 +72,16 @@ QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) resuming = false; finished = false; waveBlockOffset = 0; + + mixerID = 0; + memset(&mixerLineControls, 0, sizeof(mixerLineControls)); + initMixer(); } QAudioInputPrivate::~QAudioInputPrivate() { stop(); + closeMixer(); } void QT_WIN_CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg, @@ -163,6 +168,71 @@ QAudio::State QAudioInputPrivate::state() const return deviceState; } +#ifndef DRVM_MAPPER_CONSOLEVOICECOM_GET + #ifndef DRVM_MAPPER + #define DRVM_MAPPER 0x2000 + #endif + #ifndef DRVM_MAPPER_STATUS + #define DRVM_MAPPER_STATUS (DRVM_MAPPER+0) + #endif + #define DRVM_USER 0x4000 + #define DRVM_MAPPER_RECONFIGURE (DRVM_MAPPER+1) + #define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21) + #define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER+23) +#endif + +void QAudioInputPrivate::setVolume(qreal volume) +{ + for (DWORD i = 0; i < mixerLineControls.cControls; i++) { + + MIXERCONTROLDETAILS controlDetails; + controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); + controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID; + controlDetails.cChannels = 1; + + if ((mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_FADER) || + (mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) { + MIXERCONTROLDETAILS_UNSIGNED controlDetailsUnsigned; + controlDetailsUnsigned.dwValue = qBound(DWORD(0), DWORD(65535.0 * volume + 0.5), DWORD(65535)); + controlDetails.cMultipleItems = 0; + controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + controlDetails.paDetails = &controlDetailsUnsigned; + mixerSetControlDetails((HMIXEROBJ)mixerID, &controlDetails, MIXER_SETCONTROLDETAILSF_VALUE); + } + } +} + +qreal QAudioInputPrivate::volume() const +{ + DWORD volume = 0; + for (DWORD i = 0; i < mixerLineControls.cControls; i++) { + if ((mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_FADER) && + (mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_VOLUME)) { + continue; + } + + MIXERCONTROLDETAILS controlDetails; + controlDetails.cbStruct = sizeof(controlDetails); + controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID; + controlDetails.cChannels = 1; + controlDetails.cMultipleItems = 0; + controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + MIXERCONTROLDETAILS_UNSIGNED detailsUnsigned; + controlDetails.paDetails = &detailsUnsigned; + memset(controlDetails.paDetails, 0, controlDetails.cbDetails); + + MMRESULT result = mixerGetControlDetails((HMIXEROBJ)mixerID, &controlDetails, MIXER_GETCONTROLDETAILSF_VALUE); + if (result != MMSYSERR_NOERROR) + continue; + if (controlDetails.cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED)) + continue; + volume = detailsUnsigned.dwValue; + break; + } + + return volume / 65535.0; +} + void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) { if (deviceState == QAudio::StoppedState) @@ -351,6 +421,44 @@ void QAudioInputPrivate::close() } } +void QAudioInputPrivate::initMixer() +{ + QDataStream ds(&m_device, QIODevice::ReadOnly); + quint32 inputDevice; + ds >> inputDevice; + + if (int(inputDevice) < 0) + return; + + // Get the Mixer ID from the Sound Device ID + if (mixerGetID((HMIXEROBJ)inputDevice, &mixerID, MIXER_OBJECTF_WAVEIN) != MMSYSERR_NOERROR) + return; + + // Get the Destination (Recording) Line Infomation + MIXERLINE mixerLine; + mixerLine.cbStruct = sizeof(MIXERLINE); + mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; + if (mixerGetLineInfo((HMIXEROBJ)mixerID, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR) + return; + + // Set all the Destination (Recording) Line Controls + if (mixerLine.cControls > 0) { + mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS); + mixerLineControls.dwLineID = mixerLine.dwLineID; + mixerLineControls.cControls = mixerLine.cControls; + mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL); + mixerLineControls.pamxctrl = new MIXERCONTROL[mixerLineControls.cControls]; + if (mixerGetLineControls((HMIXEROBJ)mixerID, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL) != MMSYSERR_NOERROR) + closeMixer(); + } +} + +void QAudioInputPrivate::closeMixer() +{ + delete[] mixerLineControls.pamxctrl; + memset(&mixerLineControls, 0, sizeof(mixerLineControls)); +} + int QAudioInputPrivate::bytesReady() const { if(period_size == 0 || buffer_size == 0) diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h index 1c9c7fa..723433f 100644 --- a/src/multimedia/audio/qaudioinput_win32_p.h +++ b/src/multimedia/audio/qaudioinput_win32_p.h @@ -114,6 +114,8 @@ public: qint64 elapsedUSecs() const; QAudio::Error error() const; QAudio::State state() const; + void setVolume(qreal volume); + qreal volume() const; QIODevice* audioSource; QAudioFormat settings; @@ -150,6 +152,11 @@ private: bool open(); void close(); + void initMixer(); + void closeMixer(); + UINT mixerID; + MIXERLINECONTROLS mixerLineControls; + private slots: void feedback(); bool deviceReady(); -- 2.7.4