获取闪避事件

当系统中的通信流打开或关闭时,希望提供定制闪避体验的媒体应用程序必须侦听事件通知。 自定义实现可通过使用核心音频 API 的 MediaFoundation、DirectShow 或 DirectSound 来提供。 如果直接 WASAPI 客户端知道通信会话开始和结束的时间,它也可以覆盖默认处理方式。

要提供自定义实现,媒体应用程序需要在通信应用程序启动或结束通信流时从系统获取通知。 媒体应用程序必须实现 IAudioVolumeDuckNotification 接口,并向音频系统注册该实现。 注册成功后,媒体应用程序会通过接口中的方法以回调形式接收事件通知。 有关详细信息,请参阅闪避通知的实施注意事项

要发送闪避通知,音频系统必须知道哪个音频会话正在侦听闪避事件。 每个音频会话都使用 GUID 会话实例标识符进行唯一标识。 会话管理器允许应用程序获取有关会话的信息,如音频会话的标题、呈现状态和会话实例标识符。 可使用策略控制接口 IAudioSessionControl2 来检索标识符。

以下步骤概述了获取媒体应用程序会话实例标识符的过程:

  1. 实例化设备枚举器,并用它获取媒体应用程序用来呈现非通信流的设备终结点的引用。
  2. 从设备终结点激活会话管理器,并获取会话管理器 IAudioSessionManager2 接口的引用。
  3. 通过使用 IAudioSessionManager2 指针,获取会话管理器 IAudioSessionControl 接口的引用。
  4. IAudioSessionControl 接口查询 IAudioSessionControl2
  5. 调用 IAudioSessionControl2::GetSessionInstanceIdentifier 并检索包含当前音频会话标识符的字符串。

要获取有关通信流的闪避通知,媒体应用程序需要调用 IAudioSessionManager2::RegisterDuckNotification。 媒体应用程序向音频系统提供会话实例标识符和指向 IAudioVolumeDuckNotification 实现的指针。 现在,当通信设备上的流打开时,应用程序就能收到事件通知。 要停止接收通知,媒体应用程序必须调用 IAudioSessionManager2::UnregisterDuckNotification

以下代码展示了应用程序如何注册以获取闪避通知。 CMediaPlayer 类在闪避通知的实施注意事项中定义。 DuckingMediaPlayer 示例实现这一功能。

////////////////////////////////////////////////////////////////////
//Description: Registers for duck notifications depending on the 
//             the ducking options specified by the caller.
//Parameters: 
//    If DuckingOptOutChecked is TRUE, the client is registered for
//    to receive ducking notifications; 
//    FALSE, the client's registration is deleted.
////////////////////////////////////////////////////////////////////

HRESULT CMediaPlayer::DuckingOptOut(bool DuckingOptOutChecked)
{
    HRESULT hr = S_OK;

    IMMDeviceEnumerator* pDeviceEnumerator NULL;
    IMMDevice* pEndpoint = NULL;
    IAudioSessionManager2* pSessionManager2 = NULL;
    IAudioSessionControl* pSessionControl = NULL;
    IAudioSessionControl2* pSessionControl2 = NULL;

    LPWSTR sessionId = NULL;

    //  Start with the default endpoint.

    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), 
                          NULL, 
                          CLSCTX_INPROC_SERVER, 
                          IID_PPV_ARGS(&pDeviceEnumerator));
    
    if (SUCCEEDED(hr))
    {
        hr = pDeviceEnumerator>GetDefaultAudioEndpoint(
              eRender, eConsole, &pEndpoint);

        pDeviceEnumerator>Release();
        pDeviceEnumerator = NULL;
    }

    // Activate the session manager.
    if (SUCCEEDED(hr))
    {
        hr = pEndpoint->Activate(__uuidof(IAudioSessionManager2), 
                                 CLSCTX_INPROC_SERVER,
                                 NULL, 
                                 reinterpret_cast<void **>
                                 (&pSessionManager2));
        pEndpoint->Release();
        pEndpoint = NULL;
    }
    if (SUCCEEDED(hr))
    {
        hr = pSessionManager2->GetAudioSessionControl(
                                  NULL, 0, &pSessionControl);
        
    }

    if (SUCCEEDED(hr))
    {
        hr = pSessionControl->QueryInterface(
                               IID_PPV_ARGS(&pSessionControl2));
                
        pSessionControl->Release();
        pSessionControl = NULL;
    }

    // Get the session instance identifier.
    
    if (SUCCEEDED(hr))
    {
        hr = pSessionControl2->GetSessionInstanceIdentifier(
                                 sessionId);
                
        pSessionControl2->Release();
        pSessionControl2 = NULL;
    }

    //  Register for ducking events depending on 
    //  the specified preference.

    if (SUCCEEDED(hr))
    {
        if (DuckingOptOutChecked)
        {
            hr = pSessionManager2->RegisterDuckNotification(
                                    sessionId, this);
        }
        else
        {
            hr = pSessionManager2->UnregisterDuckNotification
                                      (FALSE);
        }
        pSessionManager2->Release();
        pSessionManager2 = NULL;
    }
    return hr;
}

使用通信设备

默认闪避体验

禁用默认闪避体验

提供自定义闪避行为

闪避通知的实施注意事项