闪避通知的实施注意事项

当通信流打开时,系统提供的默认闪避体验会闪避系统中所有可用的非通信流。 如果媒体应用程序知道通信会话开始和结束的时间,就可以覆盖默认处理方式。

请考虑 DuckingMediaPlayer 示例中媒体应用程序实现的场景。 当收到“闪避”通知时,应用程序会暂停正在播放的音频流;当收到“取消闪避”通知时,应用程序就会恢复播放。 暂停和继续事件会反映在媒体应用程序的用户界面中。 这可通过两个应用程序定义的窗口消息 WM_APP_SESSION_DUCKED 和 WM_APP_SESSION_UNDUCKED 来实现。 闪避通知是在后台异步接收的,媒体应用程序不得阻止通知线程处理窗口消息。 窗口消息必须在用户界面线程上处理。

闪避行为是通过通知机制来实现的。 要提供自定义体验,媒体应用程序必须实现 IAudioVolumeDuckNotification 接口,并向音频系统注册该实现。 注册成功后,媒体应用程序会通过接口中的方法以回调形式接收事件通知。 处理通信会话的会话管理器会在通信流打开时调用 IAudioVolumeDuckNotification::OnVolumeDuckNotification,并在通信设备上关闭流时调用 IAudioVolumeDuckNotification::OnVolumeUnduckNotification

以下代码显示了 IAudioVolumeDuckNotification 接口的示例实现。 有关 CMediaPlayer::DuckingOptOut 的定义,请参阅“从通信设备获取闪避事件”。

class CMediaPlayer : public IAudioVolumeDuckNotification
{
    LONG _refCount;

    HWND _AppWindow;

    ~CMediaPlayer();

    STDMETHOD(OnVolumeDuckNotification) (LPCWSTR sessionID, 
                  UINT32 countCommunicationSessions);
    STDMETHOD(OnVolumeUnduckNotification) (LPCWSTR sessionID);

public:
    CDuckingImpl(HWND hWnd);
    HRESULT DuckingOptOut(bool GetDuckEvents);

    // IUnknown
    IFACEMETHODIMP QueryInterface(__in REFIID riid, __deref_out void **ppv);
    IFACEMETHODIMP_(ULONG) AddRef();
    IFACEMETHODIMP_(ULONG) Release();
};

CMediaPlayer::CMediaPlayer(HWND AppWindow) :
        _AppWindow(AppWindow),
        _refCount(1)
{
}
CMediaPlayer::~CMediaPlayer()
{
}

// When we receive a duck notification, 
// post a "Session Ducked" message to the application window.

STDMETHODIMP CMediaPlayer::OnVolumeDuckNotification(LPCWSTR SessionID, 
                                                    UINT32 CountCommunicationsSessions)
{
    PostMessage(_AppWindow, WM_APP_SESSION_DUCKED, 0, 0);
    return 0;
}


// When we receive an unduck notification, 
// post a "Session Unducked" message to the application window.

STDMETHODIMP CMediaPlayer::OnVolumeUnduckNotification(LPCWSTR SessionID)
{
    PostMessage(_AppWindow, WM_APP_SESSION_UNDUCKED, 0, 0);
    return 0;
}

IFACEMETHODIMP CMediaPlayer::QueryInterface(REFIID iid, void **pvObject)
{
    if (pvObject == NULL)
    {
        return E_POINTER;
    }
    *pvObject = NULL;
    if (iid == IID_IUnknown)
    {
        *pvObject = static_cast<IUnknown *>(static_cast<IAudioVolumeDuckNotification *>
                                                                              (this));
        AddRef();
    }
    else if (iid == __uuidof(IAudioVolumeDuckNotification))
    {
        *pvObject = static_cast<IAudioVolumeDuckNotification *>(this);
        AddRef();
    }
    else
    {
        return E_NOINTERFACE;
    }
    return S_OK;
}

IFACEMETHODIMP_(ULONG) CMediaPlayer::AddRef()
{
    return InterlockedIncrement(&_refCount);
}

IFACEMETHODIMP_(ULONG) CMediaPlayer::Release()
{
    LONG refs = InterlockedDecrement(&_refCount);

    if (refs == 0)
    {
        delete this; 
    }

    return refs;   
}

使用通信设备

默认闪避体验

禁用默认闪避体验

提供自定义闪避行为

获取闪避事件