Callbacks in DVDSample

Callback functions are used throughout DVDSample to communicate events that take place during DVD-Video playback. There are two fundamental callback sources in DVDSample: the DVD drive and the DVD-Video API. Events from the DVD drive deal with the physical state of the drive and, most importantly, whether the drive is ready to begin playback. Events from the DVD-Video API deal with changes in the authored content such as transitions to new program chains.

DVDSample has two internal classes, CDevMon and CDVDSampleEventSink, that directly handle the drive and API callback sources. Taken together, these two classes account for all of the possible playback events that DVDSample can act upon. Some of these events are only of interest to the internal operation of DVDSample while others will signal changes that the end user will want to know about. DVDSample's internal callback interface, IDVDCallback, is used to forward the callback messages of end user interest from the CDvdCore object, which controls all DVD playback functions, to the main CApp application object.

To see the relationship between the callbacks within DVDSample see Architectural Overview of DVDSample.

For information about general callback design for DVD-Video applications see Callbacks.

CDevMon

The CDevMon object constantly monitors the status of the DVD drive to determine whether it is ready to begin, or continue, reading data from the disc. The CDevMon::Notify method is called whenever a change in the drive's readiness state occurs. The following code example shows the implementation for this method.

void CDevMon::Notify(bool bReady)
{
  EnterCriticalSection(&m_cs);
  DWORD msgDvdReady = (bReady ? WM_DVD_DriveReady :
                                WM_DVD_DriveNotReady);
  if (m_hWnd)
    PostMessage((HWND)m_hWnd, msgDvdReady, 0, 0);    
  LeaveCriticalSection(&m_cs);
}

In the preceding code, m_hWnd is the handle is for the CDvdCore object window, which receives all messages for the monitoring thread. The drive readiness message is posted within a critical section to assure that asynchronous status changes in the DVD drive do not cause drive-readiness messages to be posted out of order.

CDVDSampleEventSink

The CDVDSampleEventSink object contains methods that implement all of the callbacks for the IDVDNavDataStatusSink and IDVDNavigatorSink interfaces. The methods from these DVD-Video API interfaces and the methods from CDVDSampleEventSink initially exist as two separate groups of entities. The former has all of the associations with the DVD-Video API but none of the implementations, and the latter has all of the implementations but is not connected to the DVD-Video API. The CDVDSampleEventSink::Connect method binds the two groups together. The following code example shows half of the implementation for the Connect method.

HRESULT CDVDSampleEventSink::Connect()
{
  HRESULT hr = S_OK;
  IConnectionPointContainer *pCPContainer = 0;

  //Setup connection with data object
  if (m_pDataObject)
  {
    hr = m_pDataObject->QueryInterface(IID_IConnectionPointContainer,
                                       (LPVOID *)&pCPContainer);
    ASSERT(SUCCEEDED(hr));
    if (pCPContainer)
    {
      IConnectionPoint *pCP = 0;
      hr = pCPContainer->FindConnectionPoint(IID_IDVDNavDataStatusSink,
                                             &pCP);
      ASSERT(SUCCEEDED(hr));
      if (pCP)
      {
        hr = pCP->Advise((IDVDNavDataStatusSink *)this,
                          &m_dwDataAdvice);
        ASSERT(SUCCEEDED(hr));
        pCP->Release();
      }
      pCPContainer->Release();
    }
  }

  if (FAILED(hr))
  return hr;

  // ...  
  // ... Similar code for connecting to the navigator object ...
  // ... 

}

In the preceding code m_pDataObject is a pointer to an instance of a DVDData object instantiated earlier through calls to the DVD-Video API. The code shows how the IConnectionPoint and IConnectionPointContainer interfaces are used to match callback interfaces with implementation methods.

IDVDCallback

The IDVDCallback interface is the conduit for passing information from the monitoring thread to the main application thread. The architectural significance of the technique is discussed in Callbacks. IDVDCallback is an interface to the CDvdCore object. The implementations for its methods are in the CAppState object. The following snippets of code show how the interface and implementations are bound together.

The following code shows how the IDVDCallback class is defined with virtual functions.

class IDvdCallback
{
public:
  virtual void OnAngleChange(int cAngles, int nAngle) { }
  virtual void OnAudioStreamChange(int nAudio, LCID lcidAudio) { }
  virtual void OnChapterChange(int nChapter) { }
  virtual void OnParentalLevelChange(int nLevel) { }
  virtual void OnPlaybackStateChange(EDDVDPlaybackState edvdState) { }
  virtual void OnSubpictureStreamChange(int nSubpicture,
                                        LCID lcidSubpicture) { }
  virtual void OnTitleChange(int nTitle) { }
  virtual void OnProhibitedChange(DVD_UOP_PROHIBITED edvdOperation,
                                  bool bProhibited) { }
  virtual void OnDvdDriveReady(bool bReady) { }
  virtual void OnTimeStart(long lTitleLenFrames,
                           int nFramesPerSecond) { }
  virtual void OnTimeEnd() { }
  virtual void OnTimeChange(DVD_HMSF_TIMECODE time) { }
  virtual void OnMenu(bool bInMenu) { }
  virtual void Exit(void) { } // used to notify the app that the
                              // playback window was closed
  virtual RECT GetAppWindow(void) { RECT r = {0,0,0,0}; return r; }
protected:
    IDvdCallback() {  } // so no one can instantiate this class
                        // directly.
};

The following code shows how the CAppState class both inherits from the IDvdCallback class and provides implementations for the common methods.

class CAppState : public IDvdCallback
{
public:

  /* .. */

  // IDvdCallback methods
  void OnAngleChange(int cAngles, int nAngle);
  void OnAudioStreamChange(int nAudio, LCID lcidAudio);
  void OnChapterChange(int nChapter);
  void OnParentalLevelChange(int nLevel);
  void OnPlaybackStateChange(EDDVDPlaybackState edvdState);
  void OnSubpictureStreamChange(int nSubpicture,
                                LCID lcidSubpicture);
  void OnTitleChange(int nTitle);
  void OnProhibitedChange(DVD_UOP_PROHIBITED edvdOperation,
                          bool bProhibited);
  void OnDvdDriveReady(bool bReady);
  void OnTimeStart(long lTitleLenFrames, int nFramesPerSecond);
  void OnTimeEnd();
  void OnTimeChange(DVD_HMSF_TIMECODE time);
  void OnMenu(bool bInMenu);
  void Exit();
  RECT GetAppWindow();

  /* .. */

}

The following code shows a portion of the constructor for the CDvdCore class.

CDvdCore::CDvdCore(HINSTANCE hInstance, IDvdCallback * pIDC) : 
                   m_pCallback(pIDC),
                   /* ... */
{
  /* ... */
}

The following code from CApp::InitInstance shows how the CAppState object's methods become associated with the m_pCallback member of CDvdCore.

m_pDvdCore = new CDvdCore(m_hInstance, (IDvdCallback*)m_pAppState);
if (!m_pDvdCore)
  return false;

With this final step, the bridge between the monitoring thread and the main application thread is complete.

See Also

Architectural Overview of DVDSample | Callbacks | IDVDNavDataStatusSink | IDVDNavigatorSink | IConnectionPoint | IConnectionPointContainer | Examining the DVDSample Sample Application

 Last updated on Thursday, April 08, 2004

© 1992-2003 Microsoft Corporation. All rights reserved.