【问题标题】:How to change master volume programmatically?如何以编程方式更改主音量?
【发布时间】:2013-01-24 04:07:40
【问题描述】:

在 windows xp 上的 C/C++ 中如何获取主音量或如何更改主音量...?

提前谢谢...

【问题讨论】:

  • [这里][1] 讨论了一个类似的问题,但在 Delphi 中。 [1]:stackoverflow.com/questions/4504944/…
  • @DevSolar 那么,我可以使用什么方法.. 如果你有任何教程,请发布它
  • 可能的解释here
  • 显示没有研究工作。

标签: c++ c winapi windows-xp


【解决方案1】:

MSDN 库中 API 文档的起点是 here

可以通过搜索MIXERCONTROL_CONTROLTYPE_VOLUME找到有用的代码,产生类似这样的代码(取自here

static const unsigned MAXIMUM_VOLUME_LEVEL_DEFINED_BY_USER = 100;

Win32VolumeControl::Win32VolumeControl(const AudioDevice & audioDevice) {
      std::string deviceName = audioDevice.getData()[0];
      //String deviceId = audioDevice.getData()[1];
      EnumDeviceType::DeviceType deviceType = EnumDeviceType::toDeviceType(audioDevice.getData()[2]);

      _hMixer = NULL;

      int deviceId = Win32AudioDeviceId::getMixerDeviceId(deviceName);

      MMRESULT mr = initVolumeControl(deviceId, deviceType);
      if (mr != MMSYSERR_NOERROR) {
            _hMixer = NULL;
            _isSettable = false;
            if (deviceType == EnumDeviceType::DeviceTypeWaveIn) {
                  deviceType = EnumDeviceType::DeviceTypeMicrophoneIn;
                  MMRESULT mr = initVolumeControl(deviceId, deviceType);
                  if (mr == MMSYSERR_NOERROR) {
                        _isSettable = true;
                  }
            }
      } else {
            _isSettable = true;
      }
}

Win32VolumeControl::~Win32VolumeControl() {
      close();
}

int Win32VolumeControl::getLevel() {
      if (!_isSettable) {
            return 0;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_VOLUME);
      if (mr != MMSYSERR_NOERROR) {
            return -1;
      }

      const unsigned MINIMUM_VOLUME_LEVEL = _mxc.Bounds.dwMinimum;
      const unsigned MAXIMUM_VOLUME_LEVEL  = _mxc.Bounds.dwMaximum;

      MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
      mxcd.paDetails = &mxcdVolume;

      mr = ::mixerGetControlDetailsA((HMIXEROBJ) _hMixer, &mxcd,
            MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't get the volume level, mixerGetControlDetailsA() failed");
            return -1;
      }

      return (int) (((float) ((mxcdVolume.dwValue - MINIMUM_VOLUME_LEVEL) * MAXIMUM_VOLUME_LEVEL_DEFINED_BY_USER) /
            (float) (MAXIMUM_VOLUME_LEVEL - MINIMUM_VOLUME_LEVEL)) + 0.5);
}

bool Win32VolumeControl::setLevel(unsigned level) {
      if (!_isSettable) {
            return false;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_VOLUME);
      if (mr != MMSYSERR_NOERROR) {
            return false;
      }

      const unsigned MINIMUM_VOLUME_LEVEL = _mxc.Bounds.dwMinimum;
      const unsigned MAXIMUM_VOLUME_LEVEL  = _mxc.Bounds.dwMaximum;

      MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
      mxcdVolume.dwValue = level * (MAXIMUM_VOLUME_LEVEL - MINIMUM_VOLUME_LEVEL) / MAXIMUM_VOLUME_LEVEL_DEFINED_BY_USER;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
      mxcd.paDetails = &mxcdVolume;

      mr = ::mixerSetControlDetails((HMIXEROBJ) _hMixer, &mxcd,
            MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't set the volume level, mixerSetControlDetails() failed");
            return false;
      }

      return true;
}

bool Win32VolumeControl::setMute(bool mute) {
      if (!_isSettable) {
            return false;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_MUTE);
      if (mr != MMSYSERR_NOERROR) {
            return false;
      }

      MIXERCONTROLDETAILS_BOOLEAN mxcbMute;
      mxcbMute.fValue = mute;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
      mxcd.paDetails = &mxcbMute;

      mr = ::mixerSetControlDetails((HMIXEROBJ) _hMixer, &mxcd,
                        MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't mute/unmute the audio device, mixerSetControlDetails() failed");
            return false;
      }

      return true;
}

bool Win32VolumeControl::isMuted() {
      if (!_isSettable) {
            return false;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_MUTE);
      if (mr != MMSYSERR_NOERROR) {
            return false;
      }

      MIXERCONTROLDETAILS_BOOLEAN mxcbMute;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
      mxcd.paDetails = &mxcbMute;

      mr = ::mixerGetControlDetailsA((HMIXEROBJ) _hMixer, &mxcd,
                        MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't get if the audio device is mute/unmute, mixerGetControlDetailsA() failed");
            return false;
      }

      return mxcbMute.fValue;
}

bool Win32VolumeControl::selectAsRecordDevice() {
      if (!_isSettable) {
            return false;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_MUX);
      if (mr != MMSYSERR_NOERROR) {
            return false;
      }

      MIXERCONTROLDETAILS_BOOLEAN mxcbSelect;
      mxcbSelect.fValue = true;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
      mxcd.paDetails = &mxcbSelect;

      mr = ::mixerSetControlDetails((HMIXEROBJ) _hMixer, &mxcd,
                        MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't select the audio device as the record device, mixerSetControlDetails() failed");
            return false;
      }

      return true;
}

bool Win32VolumeControl::isSelectedAsRecordDevice() {
      if (!_isSettable) {
            return false;
      }

      MMRESULT mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_MUX);
      if (mr != MMSYSERR_NOERROR) {
            return false;
      }

      MIXERCONTROLDETAILS_BOOLEAN mxcbSelect;

      MIXERCONTROLDETAILS mxcd;
      mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
      mxcd.dwControlID = _mxc.dwControlID;
      mxcd.cChannels = 1;
      mxcd.cMultipleItems = 0;
      mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
      mxcd.paDetails = &mxcbSelect;

      mr = ::mixerGetControlDetailsA((HMIXEROBJ) _hMixer, &mxcd,
            MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("couldn't select the audio device as the record device, mixerSetControlDetails() failed");
            return false;
      }

      return mxcbSelect.fValue;
}

bool Win32VolumeControl::close() {
      if (!_isSettable) {
            return false;
      }

      if (_hMixer) {
            MMRESULT mr = ::mixerClose(_hMixer);
            if (mr != MMSYSERR_NOERROR) {
                  LOG_ERROR("couldn't close the mixer, mixerClose() failed");
                  return false;
            }
            return true;
      }

      return false;
}

Win32VolumeControl::initVolumeControl(unsigned deviceId, EnumDeviceType::DeviceType deviceType) {
      MMRESULT mr = ::mixerOpen(&_hMixer, deviceId, NULL, NULL, MIXER_OBJECTF_MIXER);
      if (mr != MMSYSERR_NOERROR) {
            _hMixer = NULL;
            return mr;
      }

      MIXERCAPSA mxcaps;
      mr = ::mixerGetDevCapsA(deviceId, &mxcaps, sizeof(MIXERCAPSA));
      if (mr != MMSYSERR_NOERROR) {
            return mr;
      }

      LOG_DEBUG("manufacturer's name for the mixer=" +
            std::string(mxcaps.szPname) + " " +
            String::fromNumber(mxcaps.wMid) + " " +
            String::fromNumber(mxcaps.wPid));

      DWORD dwComponentType;

      switch (deviceType) {
      case EnumDeviceType::DeviceTypeWaveOut:
            dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
            break;

      case EnumDeviceType::DeviceTypeWaveIn:
            dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
            break;

      case EnumDeviceType::DeviceTypeCDOut:
            dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
            break;

      case EnumDeviceType::DeviceTypeMicrophoneOut:
            dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
            break;

      case EnumDeviceType::DeviceTypeMicrophoneIn:
            dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
            break;

      case EnumDeviceType::DeviceTypeMasterVolume:
            dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
            break;

      default:
            LOG_FATAL("unknow device type=" + EnumDeviceType::toString(deviceType));
      }

      mr = createMixerLine(dwComponentType);
      if (mr != MMSYSERR_NOERROR) {
            return mr;
      }

      //For microphone in, we first look for the wave in mixer
      //and then for the microphone
      if (deviceType == EnumDeviceType::DeviceTypeMicrophoneIn) {
            mr = createSecondMixerLine(MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE);
            if (mr != MMSYSERR_NOERROR) {
                  return mr;
            }
      }
      //

      mr = createMixerControl(MIXERCONTROL_CONTROLTYPE_VOLUME);
      if (mr != MMSYSERR_NOERROR) {
            return mr;
      }

      LOG_DEBUG("destination line name=" + std::string(_mxl.szName) +
            " volume controller name=" + std::string(_mxc.szName));

      //Everything went fine
      return mr;
}

MMRESULT Win32VolumeControl::createMixerLine(DWORD dwComponentType) {
      _mxl.cbStruct = sizeof(MIXERLINEA);
      _mxl.dwComponentType = dwComponentType;

      MMRESULT mr = ::mixerGetLineInfoA((HMIXEROBJ) _hMixer, &_mxl,
            MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("mixerGetLineInfoA() failed using dwComponentType=" + String::fromNumber(dwComponentType));
      }

      return mr;
}

MMRESULT Win32VolumeControl::createSecondMixerLine(DWORD dwComponentType) {
      unsigned connections = _mxl.cConnections;
      DWORD destination = _mxl.dwDestination;
      MMRESULT mr;

      for (unsigned i = 0; i < connections; ++i) {
            _mxl.cbStruct = sizeof(MIXERLINEA);
            _mxl.dwSource = i;
            _mxl.dwDestination = destination;

            mr = ::mixerGetLineInfoA((HMIXEROBJ) _hMixer, &_mxl,
                                    MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE);

            if (mr == MMSYSERR_NOERROR && _mxl.dwComponentType == dwComponentType) {
                  break;
            }
      }

      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("mixerGetLineInfoA() failed using dwComponentType=" + String::fromNumber(dwComponentType));
      }

      return mr;
}

MMRESULT Win32VolumeControl::createMixerControl(DWORD dwControlType) {
      _mxlc.cbStruct = sizeof(MIXERLINECONTROLSA);
      _mxlc.dwLineID = _mxl.dwLineID;

      //MIXERCONTROL_CONTROLTYPE_VOLUME
      //MIXERCONTROL_CONTROLTYPE_MIXER
      //MIXERCONTROL_CONTROLTYPE_MUX
      //MIXERCONTROL_CONTROLTYPE_MUTE
      _mxlc.dwControlType = dwControlType;

      _mxlc.cControls = 1;
      _mxlc.cbmxctrl = sizeof(MIXERCONTROLA);
      _mxlc.pamxctrl = &_mxc;

      MMRESULT mr = ::mixerGetLineControlsA((HMIXEROBJ) _hMixer, &_mxlc,
            MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
      if (mr != MMSYSERR_NOERROR) {
            LOG_ERROR("mixerGetLineControlsA() failed using dwControType=" + String::fromNumber(dwControlType));
      }

      return mr;
}

【讨论】:

  • 感谢您的帮助...@DevSolar
  • 但我需要将音量设置为 40% 或 50%,Windows 主音量如何?
  • @YumYumYum:我认为从现有答案中可以明显看出这一点。真的。是的。
  • paste.ubuntu.com/23898336 - 我试过这个,但它不起作用。不改变音量,不静音,什么都不做。
  • @YumYumYum:由于您的程序没有产生任何音频输出,这不足为奇。
【解决方案2】:

这里。

#include <windows.h>
#pragma comment(lib, "winmm")

// to mute:
waveOutSetVolume(NULL, 0);

// full volume:
waveOutSetVolume(NULL, 0xFFFF);

【讨论】:

  • 但我需要将音量设置为 40% 或 50% 如何?
【解决方案3】:

旧式混音器 API 可能难以使用。我建议使用 WASAPI API。

WASAPI - http://msdn.microsoft.com/en-us/library/dd371455(v=VS.85).aspx

【讨论】:

  • (WASAPI是Vista+,Q是XP)
  • @RomanR。 - 你是对的。我知道,但一定是误读了这个问题。
猜你喜欢
  • 1970-01-01
  • 2012-05-31
  • 2023-04-11
  • 2023-03-14
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 2013-07-16
  • 1970-01-01
相关资源
最近更新 更多