设置WMP音量级

时间:2015-09-14 13:26:44

标签: c++ com wasapi

我想要做的是设置Windows Media Player的音量级别。默认情况下,当例如音量降低10%时点击向下或向上菜单项(播放 - >音量 - >向上),但在我看来,这不够好(特别是在听音乐的时候与某人同步)。

媒体播放器应保持独立申请 目前我正在使用一个小工具,通过SendMessage将app命令发送到播放器,参数如spy ++中所示。

我想到了实现目标的三种方法:

  • 使用WASAPI获取媒体播放器的音频会话并动态设置音量
  • 通过点
  • 将鼠标按下/向上事件发送到媒体播放器主机控件的音量滑块
  • 通过IWMPPlayer4获取媒体播放器控件的实例
  • 在Windows窗体主机中的WPF应用程序中包含媒体播放器控件(由于失去独立性而不是首选)

点2似乎相当难看,因为媒体播放器控件是一个COM元素,并且间谍++只显示一个句柄,这意味着我必须确定音量滑块的确切位置并发送非常精确的鼠标事件。另外我不知道这是否会起作用。

第3点的前提是可以通过句柄获取COM元素的实例。由于我还没有使用COM元素,我不知道这是否可行。
更新:可以使用IWMPPlayer4界面获取远程mediay播放器的实例。虽然我必须看看是否可以改变设置。

第1点给我的印象是,没有太多努力就可以实现。 虽然我将面临下一个问题:识别媒体播放器音频会话。使用IAudioSessionManager2枚举它们并使用

显示名称
IAudioSessionControl2 ctrl2 = NULL;
// ...
hr = ctrl2->GetDisplayName(&name);

if (FAILED(hr))
{
    SafeRelease(ctrl);
    SafeRelease(ctrl2);
    continue;
}

String ^sessionName = gcnew String(name);
Console::WriteLine("Session name: '" + sessionName + "'");
除了Mozilla Firefox和System Sounds之外,

大多数时间打印一个emtpy字符串(其他进程可能没有设置会话名称,因为他们自己=>;选择了默认名称,GetDisplayName返回一个空字符串。)< / p>

更新2: 正如Simon Mourier所指出的那样,人们可以比较流程ID以获得正确的ISimpleAudioVolume实例,并且只要WMP采用这些更改就可以。上述实例是以下列方式获得的:

IMMDeviceEnumerator *pEnumerator = NULL;
ISimpleAudioVolume *pVolume = NULL;
IMMDevice *pDevice = NULL;
IAudioSessionManager2 *pManager = NULL;
IAudioSessionEnumerator *pSessionEnumerator = NULL;
int sessionCount = 0;

CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
    CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
pEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &pDevice);
pDevice->GetState(&deviceState);
pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&pManager);
pManager->GetSessionEnumerator(&pSessionEnumerator);
pSessionEnumerator->GetCount(&sessionCount);

for (int i = 0; i < sessionCount; i++)
{
    IAudioSessionControl *ctrl = NULL;
    IAudioSessionControl2 *ctrl2 = NULL;
    DWORD processId = 0;

    hr = pSessionEnumerator->GetSession(i, &ctrl);

    if (FAILED(hr))
    {
        continue;
    }

    hr = ctrl->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&ctrl2);

    if (FAILED(hr))
    {
        SafeRelease(ctrl);
        continue;
    }

    hr = ctrl2->GetProcessId(&processId);

    if (FAILED(hr))
    {
        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        continue;
    }

    if (processId == wmpProcessId)
    {
        hr = ctrl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&pVolume);
        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        break;
    }

    SafeRelease(ctrl);
    SafeRelease(ctrl2);
}

通过ISimpleAudioVolume实例化IAudioClient实例时,必须提供会话ID,以便向活动订阅者报告卷更改。使用这种方法可以吗?

虽然我知道在我的应用程序中添加媒体播放器控件是最简单的方法,但如果可能,我不想使用此选项。

1 个答案:

答案 0 :(得分:1)

我不知道在我最初尝试设置媒体播放器的音量级别时会发生什么,但以下代码有效(排除了大多数异常处理):

HRESULT                 hr;
IMMDeviceEnumerator     *pEnumerator = NULL;
ISimpleAudioVolume      *pVolume = NULL;
IMMDevice               *pDevice = NULL;
IAudioSessionManager2   *pManager = NULL;
IAudioSessionEnumerator *pSessionEnumerator = NULL;
int                      sessionCount = 0;
int                      wmpProcess = GetWmpProcessId(); // Aquire WMPs process id

// Get the device enumerator and initialize the application for COM
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
         __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);

// Get the default device
hr = pEnumerator->GetDefaultAudioEndpoint(EDataFlow::eRender,
         ERole::eMultimedia, &pDevice);

// Get the session 2 manager
hr = pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL,
         NULL, (void**)&pManager);

// Get the session enumerator
hr = pManager->GetSessionEnumerator(&pSessionEnumerator);

// Get the session count
hr = pSessionEnumerator->GetCount(&sessionCount);

// Loop through all sessions
for (int i = 0; i < sessionCount; i++)
{
    IAudioSessionControl *ctrl = NULL;
    IAudioSessionControl2 *ctrl2 = NULL;
    DWORD processId = 0;

    hr = pSessionEnumerator->GetSession(i, &ctrl);

    if (FAILED(hr))
    {
        continue;
    }

    hr = ctrl->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&ctrl2);

    if (FAILED(hr))
    {
        SafeRelease(ctrl);
        continue;
    }

    //Identify WMP process
    hr = ctrl2->GetProcessId(&processId);

    if (FAILED(hr))
    {
        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        continue;
    }

    if (processId != wmpProcess)
    {
        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        continue;
    }

    hr = ctrl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void**)&pVolume);

    if (FAILED(hr))
    {
        Error(hr, "Failed to get ISimpleAudioVolume.");

        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        continue;
    }

    // Set the master volume
    hr = pVolume->SetMasterVolume(1.0, NULL);

    if (FAILED(hr))
    {
        Error(hr, "Failed to set the master volume.");
        SafeRelease(ctrl);
        SafeRelease(ctrl2);
        SafeRelease(pVolume);
        continue;
    }

    SafeRelease(ctrl);
    SafeRelease(ctrl2);
    SafeRelease(pVolume);
}