windows平台下音量调节主要分两种情况,一种是调节操作系统的音量,即是相当于操作电脑右下角的声音调节,另一种是调节当前应用程序的音量或者当前播放的音频的音量。具体使用那种方式实现,可以根据个人项目中的情况选择。
调节操作系统的音量的方法可以直接调用windows系统提供的API,调节应用程序本身的音频播放的音量的实现思路是调节送入声卡播放的PCM数据的音量,这种实现方式就需要对音频播放有一定的了解,常见的音频文件MP3/AAC之类的都是音频文件的容器格式,需要结果解封装——>解码——>PCM数据送入声卡播放,调节PCM数据音量就是在PCM数据送入声卡前进行的处理。
废话不多话,下面就是两种方式调节音量的代码
#include <windows.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <audioclient.h>
//设置系统音量(音量范围:0~100,音量为0时静音)
bool SetVolum(int volume)
{
bool ret = false;
HRESULT hr;
IMMDeviceEnumerator* pDeviceEnumerator=0;
IMMDevice* pDevice=0;
IAudioEndpointVolume* pAudioEndpointVolume=0;
IAudioClient* pAudioClient=0;
try{
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pDeviceEnumerator);
if (FAILED(hr)) throw "CoCreateInstance";
hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
if (FAILED(hr)) throw "GetDefaultAudioEndpoint";
hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndpointVolume);
if (FAILED(hr)) throw "pDevice->Active";
hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
if (FAILED(hr)) throw "pDevice->Active";
float fVolume;
fVolume = volume / 100.0f;
hr = pAudioEndpointVolume->SetMasterVolumeLevelScalar(fVolume, &GUID_NULL);
if (FAILED(hr)) throw "SetMasterVolumeLevelScalar";
pAudioClient->Release();
pAudioEndpointVolume->Release();
pDevice->Release();
pDeviceEnumerator->Release();
ret = true;
}
catch(...){
if (pAudioClient) pAudioClient->Release();
if (pAudioEndpointVolume) pAudioEndpointVolume->Release();
if (pDevice) pDevice->Release();
if (pDeviceEnumerator) pDeviceEnumerator->Release();
throw;
}
return ret;
}
//获取系统音量
int GetVolume()
{
int volumeValue = 0;
HRESULT hr;
IMMDeviceEnumerator* pDeviceEnumerator = 0;
IMMDevice* pDevice = 0;
IAudioEndpointVolume* pAudioEndpointVolume = 0;
IAudioClient* pAudioClient = 0;
try{
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pDeviceEnumerator);
if (FAILED(hr)) throw "CoCreateInstance";
hr = pDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice);
if (FAILED(hr)) throw "GetDefaultAudioEndpoint";
hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndpointVolume);
if (FAILED(hr)) throw "pDevice->Active";
hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
if (FAILED(hr)) throw "pDevice->Active";
float fVolume;
hr = pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fVolume);
if (FAILED(hr)) throw "SetMasterVolumeLevelScalar";
pAudioClient->Release();
pAudioEndpointVolume->Release();
pDevice->Release();
pDeviceEnumerator->Release();
volumeValue = fVolume * 100;
}
catch (...){
if (pAudioClient) pAudioClient->Release();
if (pAudioEndpointVolume) pAudioEndpointVolume->Release();
if (pDevice) pDevice->Release();
if (pDeviceEnumerator) pDeviceEnumerator->Release();
throw;
}
return volumeValue;
}
//buf为需要调节音量的音频数据块首地址指针,
//size为长度
//uRepeat为重复次数,通常设为1
//vol为增益倍数,可以小于1
void RaisePCMVolume(char* buf, UINT32 size, UINT32 uRepeat, double vol)
{
if (!size)
{
return;
}
for (int i = 0; i < size; i += 2)
{
short wData;
wData = MAKEWORD(buf[i], buf[i + 1]);
long dwData = wData;
for (int j = 0; j < uRepeat; j++)
{
dwData = dwData * vol;
if (dwData < -0x8000)
{
dwData = -0x8000;
}
else if (dwData > 0x7FFF)
{
dwData = 0x7FFF;
}
}
wData = LOWORD(dwData);
buf[i] = LOBYTE(wData);
buf[i + 1] = HIBYTE(wData);
}
}
int main(int argc, char** argv)
{
CoInitialize(0);
int volumeValue = GetVolume();
printf("当前音量为:%d.\r\n",volumeValue);
SetVolum(50);
CoUninitialize();
getchar();
return 0;
}
以上两种调节音量的方法本人都已测试验证,从代码中可以看出操作系统的音量调节理论上是有一个固定的范围值的,而调节PCM音量理论上是可以无限放大的, 但是放大自然会带来声音播放失真有噪音之类的损失。