c++ - 如何以编程方式更改主音量?

标签 c++ c winapi windows-xp

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

提前致谢...

最佳答案

MSDN 库中 API 文档的起点是 here

可以通过搜索 MIXERC​​ONTROL_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;
}

关于c++ - 如何以编程方式更改主音量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14771775/

相关文章:

c++ - 通过外部包装程序访问exe程序中ListView的数据

c++ - Qt中如何启动windows注销

c++ - "error: invalid operands of types ' int ' and ' const char [2] ' to binary ' 运算符<< '|"

c++ - 比较数组相似性的最佳比较算法是什么?

c++ - 用特征值初始化 vector C++ 矩阵

c - C语言的结构

c - 我使用链表(没有数组)创建了一个堆栈,但我的 pop 函数不起作用

c - 从类型 'char*[length] '(矩阵 + 结构)分配给类型 'char*' 时的类型不兼容

c++ 自己实现信号量

c++ - C++ 中的图像 bmp 中的 Alpha 混合水印 bmp