How to Get Events from the Network Source

The source resolver enables an application to create a network source and open a connection to a specific URL. The network source raises events to mark the beginning and the end of the asynchronous operation of opening a connection. An application can register for these events by using the IMFSourceOpenMonitor interface.

This interface exposes the IMFSourceOpenMonitor::OnSourceEvent method that the network source calls directly when it opens the URL asynchronously. The network source notifies the application when it starts opening the URL by raising the MEConnectStart event. The network source then raises the MEConnectEnd event when it completes the open operation.

Note

To send these events to the application, the network source does not use the IMFMediaEventGenerator interface because these events are raised before the network source is created. The application can get all other network source events by using the Media Session's IMFMediaEventGenerator interface.

 

To get events from the network source

  1. Implement the IMFSourceOpenMonitor interface. In your implementation of IMFSourceOpenMonitor::OnSourceEvent method, do the following:
    1. Get the event status by calling IMFMediaEvent::GetStatus. This method indicates whether the operation that triggered the event, such as a source resolver method call, succeeded. If the operation is not successful, the status is a failure code.
    2. Process the event based on the event type: MEConnectStart or MEConnectEnd, which the application can get by calling IMFMediaEvent::GetType.
  2. Configure a key-value pair in a property store object to store a pointer to the IMFSourceOpenMonitor implementation described in step 1.
    1. Create a property store object by calling the PSCreateMemoryPropertyStore function.
    2. Set the MFPKEY_SourceOpenMonitor property in a PROPERTYKEY structure.
    3. Provide the VT_UNKNOWN type data value in a PROPVARIANT structure by setting the IUnknown pointer to the application's implementation of the IMFSourceOpenMonitor interface.
    4. Set the key-value pair in the property store by calling IPropertyStore::SetValue.
  3. Pass the property store pointer to the source resolver methods that the application is using to create the network source, such as IMFSourceResolver::CreateObjectFromURL and others.

Example

The following example shows how to implement the IMFSourceOpenMonitor interface to get events from the network source.

class CSourceOpenMonitor : public IMFSourceOpenMonitor
{
public:
    CSourceOpenMonitor () : m_cRef(1) { }

    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] = 
        {
            QITABENT(CSourceOpenMonitor, IMFSourceOpenMonitor),
            { 0 }
        };
        return QISearch(this, qit, riid, ppv);
    }

    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHODIMP_(ULONG) Release()
    {
        LONG cRef = InterlockedDecrement(&m_cRef);
        if (cRef == 0)
        {
            delete this;
        }
        // For thread safety, return a temporary variable.
        return cRef;
    }


    STDMETHODIMP OnSourceEvent(IMFMediaEvent* pEvent)
    {
        MediaEventType eventType = MEUnknown;   // Event type
        HRESULT hrStatus = S_OK;                // Event status

        // Get the event type.
        HRESULT hr = pEvent->GetType(&eventType);

        // Get the event status. If the operation that triggered the event
        // did not succeed, the status is a failure code.
        if (SUCCEEDED(hr))
        {
            hr = pEvent->GetStatus(&hrStatus);
        }

        if (FAILED(hrStatus))
        {
            hr = hrStatus;
        }

        if (SUCCEEDED(hr))
        {
            // Switch on the event type.
            switch(eventType)
            {
                case MEConnectStart:
                    // The application does something. (Not shown.)
                    OutputDebugString(L"Connecting...\n");
                    break;

                case MEConnectEnd:
                    // The application does something. (Not shown.)
                    OutputDebugString(L"Connect End.\n");
                    break;
            }
        }
        else
        {
            // Event failed.
            // The application handled a failure. (Not shown.)
        }
        return S_OK;
    }
private:
    long    m_cRef;
};

The following example shows how to set the MFPKEY_SourceOpenMonitor property on the network source when you open the URL:

HRESULT CreateMediaSourceWithSourceOpenMonitor(
    PCWSTR pszURL, 
    IMFMediaSource **ppSource
    )
{
    IPropertyStore *pConfig = NULL;

    CSourceOpenMonitor *pMonitor = new (std::nothrow) CSourceOpenMonitor();

    if (pMonitor == NULL)
    {
        return E_OUTOFMEMORY;
    }

    // Configure the property store.
    HRESULT hr = PSCreateMemoryPropertyStore(IID_PPV_ARGS(&pConfig));

    if (SUCCEEDED(hr))
    {
        PROPVARIANT var;
        var.vt = VT_UNKNOWN;
        pMonitor->QueryInterface(IID_PPV_ARGS(&var.punkVal));

        hr = pConfig->SetValue(MFPKEY_SourceOpenMonitor, var);

        PropVariantClear(&var);
    }

    // Create the source media source.
    if (SUCCEEDED(hr))
    {
        hr = CreateMediaSource(pszURL, pConfig, ppSource);
    }

    SafeRelease(&pConfig);
    SafeRelease(&pMonitor);

    return hr;
}

Networking in Media Foundation