Share via


IBroadcastEvent Interface

This topic applies to Windows XP or later.

The IBroadcastEvent interface enables an object to receive events from another object without setting up a direct connection point. Applications typically do not need to use this interface.

Methods

The IBroadcastEvent interface inherits the methods of the IUnknown interface.

In addition, IBroadcastEvent defines the following method.

Method Description

Fire

Fires an event.

Remarks

Broadcast events enable communication among DirectShow filters, Video Control features, and Video Control device objects. To send a broadcast event, an object calls IBroadcastEvent::Fire on the Broadcast Event Service object. Other objects can listen for events by setting up a connection point with the Broadcast Event Service object. The listener implements IBroadcastEvent and the Broadcast Event Service object calls the listener's Fire method whenever there is a new broadcast event.

Broadcast events are useful for several reasons:

  • The DirectShow event mechanism, IMediaEventSink, does not support multiple listeners. DirectShow events go onto a queue, and retrieving an event removes it from the queue.
  • COM connection points require the sink object to locate the source object. With broadcast events, the Broadcast Event Service acts as a relay between the source object and the sink object.
  • In a connection point, the source must fire events on the same thread that the sink used to establish the connection, or else marshal the event interface pointer. Filter graphs are multithreaded, so the Broadcast Event Service object implements the necessary marshaling. It uses a background thread to distribute events to all the registered listeners.

The IBroadcastEvent interface is a service, which can be obtained through the Filter Graph Manager's IServiceProvider interface. To do so, call IServiceProvider::QueryService and specify the following values:

  • Service identifier: SID_SBroadcastEventService
  • Interface identifier: IID_IBroadcastEvent

A failure code from QueryService indicates that no object has yet registered the Broadcast Event Service object with the Filter Graph Manager. In that case, do the following:

  1. Create a new Broadcast Event Service object, using CoCreateInstance.
  2. Query the Filter Graph Manager for IRegisterServiceProvider.
  3. Call IRegisterServiceProvider::RegisterService with the service identifier.

Once you have a pointer to the IBroadcastEvent interface, you can use it either to send events or to sink events. To send events, call the Fire method. To sink events, implement IBroadcastEvent on the sink object, query the Broadcast Event Service for IConnectionPoint, and call IConnectionPoint::Advise to establish the connection. For a list of defined broadcast events, see IBroadcastEvent::Fire.

Examples

The following example implements a class that can source or sink broadcast events:

class TunerEvent : public IBroadcastEvent
{

private:
    long m_nRefCount; // Holds the reference count.
public:
    // IUnknown methods
    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&m_nRefCount);
    }
    STDMETHODIMP_(ULONG) Release()
    {
        _ASSERT(m_nRefCount >= 0);
        ULONG uCount = InterlockedDecrement(&m_nRefCount);
        if (uCount == 0)
        {
            delete this;
        }
        // Return the temporary variable, not the member
        // variable, for thread safety.
        return uCount;
    }
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
    {
        if (NULL == ppvObject)
            return E_POINTER;
        if (riid == __uuidof(IUnknown))
            *ppvObject = static_cast<IUnknown*>(this);
        else if (riid == __uuidof(IBroadcastEvent))
            *ppvObject = static_cast<IBroadcastEvent*>(this);
        else 
            return E_NOINTERFACE;
        AddRef();
        return S_OK;
    }

    // The one IBroadcastEvent method.
    STDMETHOD(Fire)(GUID eventID)
    {
        // The one defined event.
        if (eventID == EVENTID_TuningChanged)
        {
            // The tuner changed stations or channels.
        }
        
        return S_OK;
    }

    TunerEvent() : m_dwBroadcastEventCookie(0), m_nRefCount(1) {};

private:
    HRESULT HookupGraphEventService(IFilterGraph *pGraph);
    HRESULT RegisterForTunerEvents();
    HRESULT UnRegisterForTunerEvents();
    HRESULT Fire_Event(GUID eventID);

    CComPtr<IBroadcastEvent>   m_spBroadcastEvent; 
    DWORD m_dwBroadcastEventCookie;
};

// Query the Filter Graph Manager for the broadcast event service.
// If not found, create it and register it.
HRESULT TunerEvent::HookupGraphEventService(IFilterGraph *pGraph)
{
    HRESULT hr = S_OK;
    if (!m_spBroadcastEvent)
    {
        CComQIPtr<IServiceProvider> spServiceProvider(pGraph);
        if (!spServiceProvider)
        {
            return E_NOINTERFACE;
        }
        hr = spServiceProvider->QueryService(SID_SBroadcastEventService, 
            IID_IBroadcastEvent, 
            reinterpret_cast<void**>(&m_spBroadcastEvent));
        if (FAILED(hr))
        {
            // Create the Broadcast Event Service object.
            hr = m_spBroadcastEvent.CoCreateInstance(
                CLSID_BroadcastEventService,
                NULL, CLSCTX_INPROC_SERVER);
            if (FAILED(hr))
            {
                return hr; 
            }
            
            CComQIPtr<IRegisterServiceProvider> spRegService(pGraph);
            if (!spRegService)
            {
                return E_NOINTERFACE;
            }
            
            // Register the Broadcast Event Service object as a service.
            hr = spRegService->RegisterService(
                SID_SBroadcastEventService,
                m_spBroadcastEvent);
        }
    }
    return hr;
}

// Establish the connection point to receive events.
HRESULT TunerEvent::RegisterForTunerEvents()
{
    if (!m_spBroadcastEvent)
    {
        return E_FAIL;  // Forgot to call HookupGraphEventService.
    }
    if(m_dwBroadcastEventCookie)
    {
        return S_FALSE;  // There is already a connection; nothing to do.
    }
    CComQIPtr<IConnectionPoint> spConnectionPoint(m_spBroadcastEvent);
    if(!spConnectionPoint)
    {
        return E_NOINTERFACE;
    }
    return spConnectionPoint->Advise(static_cast<IBroadcastEvent*>(this),
        &m_dwBroadcastEventCookie);
}

// Unregister for events.
HRESULT TunerEvent::UnRegisterForTunerEvents()
{
    HRESULT hr = S_OK;
    if(!m_dwBroadcastEventCookie)
    {
        return S_OK; // Not registered for events; nothing to do.
    }
    CComQIPtr<IConnectionPoint> spConnectionPoint(m_spBroadcastEvent);
    if(!spConnectionPoint)
    {
        return E_NOINTERFACE;
    }
    
    // Release the connection point.
    hr = spConnectionPoint->Unadvise(m_dwBroadcastEventCookie);
    if (FAILED(hr))
    {
        // Error: Unable to unadvise the connection point.
        return hr;
    }
    m_dwBroadcastEventCookie = 0;
    m_spBroadcastEvent.Release();
    return S_OK;
}

// Send an event (for source objects).
HRESULT TunerEvent::Fire_Event(GUID eventID)
{
    if (!m_spBroadcastEvent)
    {
        return E_FAIL; // Forgot to call HookupGraphEventService.
    }
    return m_spBroadcastEvent->Fire(eventID);
}

See Also

Video Control Interfaces

Send comments about this topic to Microsoft

Build date: 12/4/2008