0

私がやりたいことは、Windows Media Player の音量レベルを設定することです。デフォルトでは、例えば下または上メニュー項目をクリックすると (再生 -> 音量 -> アップ)、音量は 10% 減少しますが、私の意見では、これでは十分ではありません (特に、誰かとスカイプをしているときに)音楽を聴く)。

メディア プレーヤーは、独立したアプリケーションのままにする必要があります。
現在、Spy++ で見られるパラメータを使用して、SendMessage を介してアプリ コマンドをプレーヤーに送信する小さなツールを使用しています。

目標を達成するために、次の 3 つの方法を考えました。

  • WASAPI を使用してメディア プレーヤーのオーディオ セッションを取得し、音量レベルを動的に設定する
  • メディア プレーヤー ホスト コントロールのボリューム スライダーにマウス ダウン/アップ イベントをポイント単位で送信する
  • IWMPlayer4 を介してメディア プレーヤー コントロールのインスタンスを取得する
  • Windowsフォームホスト内のWPFアプリケーションにメディアプレーヤーコントロールを含める(独立性が失われるため、推奨されません)

ポイント 2 は、メディア プレーヤー コントロールが COM 要素であり、spy++ がハンドルを 1 つしか表示しないため、ボリューム スライダーの正確な位置を特定し、非常に正確なマウス イベントを送信する必要があるため、かなり見苦しく見えます。さらに、これがまったく機能するかどうかはわかりません。

ポイント 3 には、ハンドルによって COM 要素のインスタンスを取得できるという前提があります。私はまだ COM 要素を扱っていないので、これが可能かどうかはわかりません。
更新:インターフェイスを使用して、リモートのメディア プレーヤーのインスタンスを取得できIWMPPlayer4ます。設定を変更できるかどうかを確認する必要がありますが。

ポイント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 とシステム サウンドを除いて、ほとんどの場合空の文字列を出力します (他のプロセス自体がセッション名を設定していない可能性があります => デフォルトの名前が選択されGetDisplayName、空の文字列が返されます)。

更新 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);
}

ISimpleAudioVolume1 を介してインスタンスを取得する場合IAudioClient、セッション ID を提供して、ボリュームの変更をイベント サブスクライバーに報告する必要があります。これは、このアプローチを使用して可能ですか?

アプリケーションにメディア プレーヤー コントロールを追加するのが最も簡単な方法であることはわかっていますが、可能であればこのオプションを使用したくありません。

4

1 に答える 1

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);
}
于 2015-09-21T14:57:27.100 に答える