Рекомендации по реализации для уведомлений о утках
Интерфейс уток по умолчанию, предоставляемый системой, уткает все потоки, не относящиеся к обмену данными, доступные в системе при открытии потока коммуникации. Приложение мультимедиа может переопределить обработку по умолчанию, если он знает, когда сеанс обмена данными начинается и заканчивается.
Рассмотрим сценарий, реализованный приложением мультимедиа в примере DuckingMediaPlayer . Приложение приостанавливает воспроизведение звукового потока, который он воспроизводит при получении уведомления о утках и продолжает воспроизведение при получении уведомления об ошибке. События приостановки и продолжения отражаются в пользовательском интерфейсе приложения мультимедиа. Это поддерживается с помощью двух сообщений окна, WM_APP_SESSION_DUCKED и WM_APP_SESSION_UNDUCKED. Уведомления о утках получаются асинхронно в фоновом режиме, а приложение мультимедиа не должно блокировать поток уведомлений для обработки сообщений окна. Сообщения окна должны обрабатываться в потоке пользовательского интерфейса.
Поведение утки работает с помощью механизма уведомлений. Чтобы обеспечить настраиваемый интерфейс, приложение мультимедиа должно реализовать интерфейс IAudioVolumeDuckNotification и зарегистрировать реализацию в звуковой системе. После успешной регистрации приложение мультимедиа получает уведомления о событиях в виде обратных вызовов с помощью методов в интерфейсе. Диспетчер сеансов, обрабатываемый сеансом связи, вызывает IAudioVolumeDuckNotification::OnVolumeDuckNotification при открытии потока связи, а затем вызывает IAudioVolumeDuckNotification::OnVolumeUnduckNotification при закрытии потока на устройстве связи.
В следующем коде показан пример реализации интерфейса IAudioVolumeDuckNotification. Определение CMediaPlayer::D uckingOptOut см. в разделе "Получение уток событий с устройства связи".
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;
}
См. также