背景描述
作为一个播放器, 除了能播放视频和声音外,音量控制是绝对不能缺少的功能; 本文在音视频播放的基础上,增加对音量的控制;
实现流程
- 调用mixerGetDevCaps获取音频输出设备列表;
- 打开指定的音频输出设备;
- 获取指定音频输出设备的音频属性;
- 获取和设置音量;
DWORD GetVolume();
int SetVolume(DWORD vol);
int Init(DWORD ComponentType,int *min,int *max);
int GetAudioOutputDeviceList(MIXER_DEVICE_INFO_T **devicelist, int *deviceNum);
int SetAudioDeviceId(int _deviceIdx);
代码实现
//获取音频输出设备列表
int CVolumeControl::GetAudioOutputDeviceList(MIXER_DEVICE_INFO_T **devicelist, int *deviceNum)
{
int idx = 0;
if (mDeviceNum < 1)
{
MIXERCAPS mxcaps;
UINT cMixerDevs = mixerGetNumDevs();
for (UINT iDevIndex = 0; iDevIndex < cMixerDevs && iDevIndex<MAX_MIXER_DEVICE_NUM; iDevIndex++)
{
mixerGetDevCaps(iDevIndex, &mxcaps, sizeof(mxcaps));
mixerDeviceList[iDevIndex].id = iDevIndex;
strcpy(mixerDeviceList[iDevIndex].name, mxcaps.szPname);
}
mDeviceNum = cMixerDevs;
}
if (NULL != deviceNum) *deviceNum = mDeviceNum;
if (NULL != devicelist) *devicelist = &mixerDeviceList[0];
return 0;
}
//获取音量
DWORD CVolumeControl::GetVolume()
{
int devIdx = mDeviceId;
if (devIdx < 0) return -1;
HMIXER hMixer;
MMRESULT mmhr;
mmhr = mixerOpen(&hMixer, devIdx, 0, 0, MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_DESTINATION);
if( mmhr != MMSYSERR_NOERROR )
{
_TRACE(TRACE_LOG_ERROR, "GetVolume::mixerOpen fail. %d\n", mmhr);
return 0;
}
MIXERCAPS tmixercaps;
if( mixerGetDevCaps( devIdx, &tmixercaps, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR )
{
mixerClose(hMixer);
return -1;
}
bool ffind = false;
MIXERLINE mxline;
for(int i = 0; i < (int)tmixercaps.cDestinations; i++ )
{
ZeroMemory( &mxline, sizeof(MIXERLINE) );
mxline.cbStruct = sizeof(MIXERLINE);
mxline.dwDestination = i;
mmhr = ::mixerGetLineInfo( (HMIXEROBJ)hMixer, &mxline, MIXER_OBJECTF_HMIXER);// | MIXER_GETLINEINFOF_COMPONENTTYPE );
if( mmhr != MMSYSERR_NOERROR ) {
continue;
}
else {
if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_DIGITAL )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
else if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_MONITOR )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
else if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
}
}
MIXERCONTROL mxcWaveoutMux;
memset(&mxcWaveoutMux, 0x00, sizeof(MIXERCONTROL));
_GetLineControls( hMixer, mxline, &mxcWaveoutMux, NULL, NULL );
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxdu;
memset(&mxdu, 0x00, sizeof(MIXERCONTROLDETAILS_UNSIGNED));
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.cMultipleItems = 0;
mxcd.cChannels = mxline.cChannels;
mxcd.dwControlID = mxcWaveoutMux.dwControlID;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxdu;
mmhr = mixerGetControlDetails((HMIXEROBJ)hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
if( mmhr != MMSYSERR_NOERROR )
{
_TRACE(TRACE_LOG_ERROR, "GetVolume::mixerGetControlDetails fail. %d\n", mmhr);
}
mixerClose(hMixer);
_TRACE(TRACE_LOG_DEBUG, "GetVolume: %d\n", mxdu.dwValue);
return mxdu.dwValue;
}
//设置音量
int CVolumeControl::SetVolume(DWORD vol)
{
int devIdx = mDeviceId;
if (devIdx < 0) return -1;
HMIXER hMixer;
MMRESULT mmhr;
mmhr = mixerOpen(&hMixer, 0, 0, 0, 0);
if (mmhr!= MMSYSERR_NOERROR)
{
_TRACE(TRACE_LOG_ERROR, "mixerOpen fail. %d\n", mmhr);
return -1;
}
MIXERCAPS tmixercaps;
if( mixerGetDevCaps( devIdx, &tmixercaps, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR )
{
mixerClose(hMixer);
return -1;
}
bool ffind = false;
MIXERLINE mxline;
for(int i = 0; i < (int)tmixercaps.cDestinations; i++ )
{
ZeroMemory( &mxline, sizeof(MIXERLINE) );
mxline.cbStruct = sizeof(MIXERLINE);
mxline.dwDestination = i;
mmhr = ::mixerGetLineInfo( (HMIXEROBJ)hMixer, &mxline, MIXER_OBJECTF_HMIXER);// | MIXER_GETLINEINFOF_COMPONENTTYPE );
if( mmhr != MMSYSERR_NOERROR ) {
continue;
}
else {
//
if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_DIGITAL )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
else if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_MONITOR )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
else if( mxline.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS )
{
if( 0 != (MIXERLINE_LINEF_ACTIVE & mxline.fdwLine) )
{
ffind = true;
break;
}
}
}
}
MIXERCONTROL mxcWaveoutMux;
memset(&mxcWaveoutMux, 0x00, sizeof(MIXERCONTROL));
_GetLineControls( hMixer, mxline, &mxcWaveoutMux, NULL, NULL );
int ret = 0;
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_UNSIGNED mxdu;
memset(&mxdu, 0x00, sizeof(MIXERCONTROLDETAILS_UNSIGNED));
mxdu.dwValue = vol;
mxcd.cMultipleItems = 0;
mxcd.cChannels = mxline.cChannels;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxcWaveoutMux.dwControlID;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxdu;
mmhr = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd, MIXER_SETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER);
if (mmhr != MMSYSERR_NOERROR)
{
ret = -1;
}
mixerClose(hMixer);
return ret;
}
关于EasyPlayerPro播放器
EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP、RTMP、HTTP、HLS、UDP、RTP、File等多种流媒体协议播放、支持本地文件播放,支持本地抓拍、本地录像、播放旋转、多屏播放、倍数播放等多种功能特性,核心基于ffmpeg,稳定、高效、可靠、可控,支持Windows、Android、iOS三个平台,目前在多家教育、安防、行业型公司,都得到的应用,广受好评!
EasyPlayerPro:https://github.com/EasyDSS/EasyPlayerPro
点击链接加入群【EasyPlayer & EasyPlayerPro】:544917793
技术支持
QQ交流群:544917793
获取更多信息
EasyDarwin开源流媒体服务器:www.EasyDarwin.org
EasyDSS商用流媒体解决方案:www.EasyDSS.com
EasyNVR无插件直播方案:www.EasyNVR.com
Copyright © EasyDarwin Team 2012-2017