简介
项目中需要在windows和linux系统下对系统的声音进行控制,相关操作包括获取系统的音量,设置系统的音量,获取系统的静音状态和静音,特此记录相关的C++实现。
主要涉及的系统有windows和ubuntu系统。
实现
-
windows
windows下使用WASAPI来获取设置音量。
-
linux
在linux上使用amixer的文本方式控制音量。alsamixer是Linux 音频架构ALSA中的Alsa工具的其中一个,用于配置音频的各个参数。
amixer,是alsamixer的文本模式,即命令行模式,需要用amixer命令的形式去配置你的声卡的各个选项。
-
其帮助文档相关参数如下:
-
使用到的相关设置:
# 获取声音状态 # -D 指定声音脉冲 # sget 获取主通道Master状态 # awk '/%/{print $5,$6}' OFS="," 查找含有%号的字符行,并以逗号格式化输出音量和是否静音 # uniq 去重 # tr -d [/] 删除多余的括号 amixer -D pulse sget "Master" | awk '/%/{print $5,$6}' OFS="," | uniq | tr -d '['/']' # 设置系统音量为10% amixer -D pulse sset "Master" 10% # 设置系统音量静音,取消静音为:unmute amixer -D pulse sset "Master" mute
-
相关代码实现了windows和linux的相关声音控制,代码已测试可用。
-
工具库头文件
#include "utility.h" #include <iostream> int main() { int iVolume = 0; bool mute = false; // 获取系统声音信息 Utility::getSysSoundInfo(iVolume, mute); std::cout << "volume:" << iVolume << ",mute:" << mute << std::endl; // 设置音量 std::cout << "set the volume(0-100):" << std::endl; std::cin >> iVolume; Utility::setSysVolume(iVolume); // 设置静音 int tmpMut = 1; std::cout << "set the mute(1:mute,0:unmute):" << std::endl; std::cin >> tmpMut; Utility::setSysMutex(tmpMut == 1); // 再次获取系统声音信息 iVolume = 0; mute = false; Utility::getSysSoundInfo(iVolume, mute); std::cout << "volume:" << iVolume << ",mute:" << mute << std::endl; return 0; }
-
工具库实现文件
#include "utility.h" #ifdef WIN32 #include <windows.h> #include <mmdeviceapi.h> #include <endpointvolume.h> #include <Audioclient.h> #pragma comment(lib, "Ole32.lib") #endif Utility::Utility() { } std::vector<std::string> Utility::splitStr(const std::string &str, const std::string &delim) { std::vector<std::string> vec; try { std::regex regex(delim); return std::vector<std::string>{ std::sregex_token_iterator(str.begin(), str.end(), regex, -1), std::sregex_token_iterator() }; } catch(const std::exception &e) { return std::vector<std::string>(); } } bool Utility::getSysSoundInfo(int &ivolume, bool &mute) { #ifdef WIN32 return getWindowsSoundInfo(ivolume, mute); #else return getLinuxSoundInfo(ivolume, mute); #endif } bool Utility::setSysVolume(int iVolume) { #ifdef WIN32 return setWindowsVolume(iVolume); #else return Utility::setLinuxVolume(iVolume); #endif } bool Utility::setSysMutex(bool mute) { #ifdef WIN32 return setWindowsMutex(mute); #else return Utility::setLinuxMutex(mute); #endif } std::string Utility::exeCmd(const std::string &cmd) { FILE* fp = popen(cmd.data(), "r"); if (fp == nullptr) { return ""; } std::string result; char buf[1024] = {0}; while (fgets(buf, sizeof(buf), fp)) { result += buf; } pclose(fp); auto size = result.size(); if (size > 0 && result[size - 0] == '\n') { result = result.substr(0, size -1); } return result; } #ifdef WIN32 bool Utility::getWindowsSoundInfo(int &iVolume, bool &mute) { CoInitialize(nullptr); HRESULT hr; bool result = false; IMMDeviceEnumerator* pDeviceEnum = nullptr; IMMDevice* pDevice = nullptr; IAudioEndpointVolume* pAudioVolume = nullptr; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (VOID **)&pDeviceEnum); if (FAILED(hr)) { goto exit; } hr = pDeviceEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); if (FAILED(hr)) { goto exit; } hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, (void **)&pAudioVolume); if (FAILED(hr)) { goto exit; } // 音量 float tmpVolume; pAudioVolume->GetMasterVolumeLevelScalar(&tmpVolume); iVolume = (int)(tmpVolume * 100); // 是否静音 BOOL tmpMute; pAudioVolume->GetMute(&tmpMute); mute = tmpMute; result = true; exit: if (pAudioVolume != nullptr) { pAudioVolume->Release(); } if (pDevice != nullptr) { pDevice->Release(); } if (pDeviceEnum != nullptr) { pDeviceEnum->Release(); } CoUninitialize(); return result; } bool Utility::setWindowsVolume(int iVolume) { CoInitialize(nullptr); float tmpVolume = iVolume / 100.0f; HRESULT hr; bool result = false; IMMDeviceEnumerator* pDeviceEnum = nullptr; IMMDevice* pDevice = nullptr; IAudioEndpointVolume* pAudioVolume = nullptr; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (VOID **)&pDeviceEnum); if (FAILED(hr)) { goto exit; } hr = pDeviceEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); if (FAILED(hr)) { goto exit; } hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, (void **)&pAudioVolume); if (FAILED(hr)) { goto exit; } // 设置音量 pAudioVolume->SetMasterVolumeLevelScalar(tmpVolume, &GUID_NULL); result = true; exit: if (pAudioVolume != nullptr) { pAudioVolume->Release(); } if (pDevice != nullptr) { pDevice->Release(); } if (pDeviceEnum != nullptr) { pDeviceEnum->Release(); } CoUninitialize(); return result; } bool Utility::setWindowsMutex(bool mute) { CoInitialize(nullptr); HRESULT hr; bool result = false; IMMDeviceEnumerator* pDeviceEnum = nullptr; IMMDevice* pDevice = nullptr; IAudioEndpointVolume* pAudioVolume = nullptr; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (VOID **)&pDeviceEnum); if (FAILED(hr)) { goto exit; } hr = pDeviceEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDevice); if (FAILED(hr)) { goto exit; } hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, nullptr, (void **)&pAudioVolume); if (FAILED(hr)) { goto exit; } // 设置音量 pAudioVolume->SetMute(mute, &GUID_NULL); result = true; exit: if (pAudioVolume != nullptr) { pAudioVolume->Release(); } if (pDevice != nullptr) { pDevice->Release(); } if (pDeviceEnum != nullptr) { pDeviceEnum->Release(); } CoUninitialize(); return result; } #else bool Utility::getLinuxSoundInfo(int &iVolume, bool &mute) { std::string cmd = "amixer -D pulse sget \"Master\" | awk '/%/{print $5,$6}' OFS=\",\" | uniq | tr -d '['/']'/'\n'"; auto result = Utility::exeCmd(cmd); auto vec = Utility::splitStr(result, ","); if (vec.size() >= 2) { iVolume = std::stoi(vec[0]); mute = (vec[1] == "off"); return true; } else { return false; } } bool Utility::setLinuxVolume(int iVolume) { std::string cmd = std::string("amixer -D pulse sset \"Master\" ") + std::to_string(iVolume) + "%"; Utility::exeCmd(cmd); return true; } bool Utility::setLinuxMutex(bool mute) { auto cmd = std::string("amixer -D pulse sset \"Master\" ") + (mute ? "mute" : "unmute"); Utility::exeCmd(cmd); return true; } #endif
-
测试代码
#include "utility.h" #include <iostream> int main() { int iVolume = 0; bool mute = false; // 获取系统声音信息 Utility::getSysSoundInfo(iVolume, mute); std::cout << "volume:" << iVolume << ",mute:" << mute << std::endl; // 设置音量 std::cout << "set the volume(0-100):" << std::endl; std::cin >> iVolume; Utility::setSysVolume(iVolume); // 设置静音 int tmpMut = 1; std::cout << "set the mute(1:mute,0:unmute):" << std::endl; std::cin >> tmpMut; Utility::setSysMutex(tmpMut == 1); // 再次获取系统声音信息 iVolume = 0; mute = false; Utility::getSysSoundInfo(iVolume, mute); std::cout << "volume:" << iVolume << ",mute:" << mute << std::endl; return 0; }