//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odother
//
//   CLASSES: none
//
//   ORIGINS: 27
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//
// @(#) 1.1 nt/src/samples/cdplayer/cddevice.cpp, odcdplayerpart, od96nt, odnt9712d 8/22/96 15:35:31 [ 3/21/97 17:32:45 ]

/*-------------------------------------------------------------------+
|                            CDDevice.C                              |
| ================================================================== |
|                                                                    |
| Description:  CD Device implementation, uses Microsoft's Win32 MCI |
|               API set.                                             |
|                                                                    |
| Author:       David Kuettel, Summer 1996                           |
|                                                                    |
+-------------------------------------------------------------------*/
#ifndef IBMSample_CDDevice
#include "CDDevice.h"
#endif

extern "C" {
	#include <mmsystem.h>
	#include <stdio.h>
}

/*-------------------------------------------------------------------+
|                     CDDevice::CDDevice ()                          |
| ================================================================== |
|                                                                    |
| Function:    CDDevice default constructor                          |
|                                                                    |
+-------------------------------------------------------------------*/
CDDevice::CDDevice () : fWindowHandle (NULL)
{
}


/*-------------------------------------------------------------------+
|                    CDDevice::~CDDevice ()                          |
| ================================================================== |
|                                                                    |
| Function:    CDDevice destructor...                                |
|                                                                    |
+-------------------------------------------------------------------*/
CDDevice::~CDDevice ()
{
}


/*-------------------------------------------------------------------+
|                       CDDevice::SetNotification ()                 |
| ================================================================== |
|                                                                    |
| Function:    Saves the window handle that all command complete     |
|              notifications are sent too.                           |
|                                                                    |
+-------------------------------------------------------------------*/
void CDDevice::SetNotification (HWND windowHandle)
{
	this->fWindowHandle = windowHandle;
}


/*-------------------------------------------------------------------+
|                       CDControl::Open ()                           |
| ================================================================== |
|                                                                    |
| Function:    Open CD device, cache the device id and set the time  |
|              format.                                               |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Open ()
{
	MCI_OPEN_PARMS mciOpenParms;
	MCI_SET_PARMS  mciSetParms;
	DWORD result = S_OK;

	mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;

	if (result = mciSendCommand (
				NULL, 
				MCI_OPEN,
				MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,
				(DWORD) (LPVOID) &mciOpenParms)) {
		return result;
	}

	/*
	 *  The device was opened successfully; cache the device ID. 
	 */
	this->fDeviceID = mciOpenParms.wDeviceID;

	/*
	 *  Set the time format to track/minute/second/frame (TMSF). 
	 */
	mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;

	if (result = mciSendCommand (
				fDeviceID,
				MCI_SET,
				MCI_SET_TIME_FORMAT,
				(DWORD) (LPVOID) &mciSetParms)) {
		Close ();
		return result;
	}

	return result;
}


/*-------------------------------------------------------------------+
|                             Close ()                               |
| ================================================================== |
|                                                                    |
| Function:    Send the Close command                                |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Close ()
{
	return mciSendCommand (fDeviceID, MCI_CLOSE, 0, NULL);
}


/*-------------------------------------------------------------------+
|                           CDDevice::Play ()                        |
| ================================================================== |
|                                                                    |
| Function:    Send the Play command                                 |
|                                                                    |
| NOTE:        MCI_TO flag cannot be specified when playing the      |
|              last track.                                           |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Play (BYTE bTrack) 
{
	DWORD result = S_OK;

	MCI_PLAY_PARMS mciPlayParms;

	mciPlayParms.dwFrom = 0L;
	mciPlayParms.dwTo   = 0L;
	mciPlayParms.dwFrom = MCI_MAKE_TMSF(bTrack, 0, 0, 0);
	mciPlayParms.dwTo   = MCI_MAKE_TMSF(bTrack + 1, 0, 0, 0);
	mciPlayParms.dwCallback = (DWORD) fWindowHandle;

	DWORD flags = MCI_FROM | MCI_NOTIFY;

	/*
	 *  Only specify the MCI_TO flag if this is not the last track.
	 *  In which case dwTo defaults to end of CD...
	 */
	DWORD numTracks = NumTracks ();
	if (bTrack != numTracks) flags |= MCI_TO;

	if (result = mciSendCommand (fDeviceID, MCI_PLAY, flags,
				(DWORD) (LPVOID) &mciPlayParms))
	{
		Close ();
	}

	return result;
}


/*-------------------------------------------------------------------+
|                         CDDevice::Pause ()                         |
| ================================================================== |
|                                                                    |
| Function:    Send the Pause command                                |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Pause ()
{
	return mciSendCommand (fDeviceID, MCI_PAUSE, 0, NULL);
}


/*-------------------------------------------------------------------+
|                         CDDevice::Resume ()                        |
| ================================================================== |
|                                                                    |
| Function:    Send the Resume command                               |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Resume ()
{
	return mciSendCommand (fDeviceID, MCI_RESUME, 0, NULL);
}


/*-------------------------------------------------------------------+
|                         CDDevice::Stop ()                          |
| ================================================================== |
|                                                                    |
| Function:    Send the Stop command                                 |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Stop ()
{
	return mciSendCommand (fDeviceID, MCI_STOP, 0, NULL);
}


/*-------------------------------------------------------------------+
|                       CDDevice::OpenDoor ()                        |
| ================================================================== |
|                                                                    |
| Function:    Open the CD door (eject the CD).                      |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::OpenDoor ()
{
	return mciSendCommand (fDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, NULL);
}


/*-------------------------------------------------------------------+
|                       CDDevice::CloseDoor ()                       |
| ================================================================== |
|                                                                    |
| Function:    Close the CD door.                                    |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::CloseDoor ()
{
	return mciSendCommand (fDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, NULL);
}


/*-------------------------------------------------------------------+
|                       CDDevice::GetID ()                           |
| ================================================================== |
|                                                                    |
| Function:    Returns a unique string for each CDROM.  Used as an   |
|              index to retrieve the Album information from the      |
|              registry.                                             |
|                                                                    |
| Algorithm:   Generates somewhat unique string by converting length |
|              of cd (in seconds) into a string.  Should use the     |
|              UPC code, but either my test CD did not have a UPC    |
|              code, or I have a bug in my code...                   |
|                                                                    |
|              MCI_INFO_MEDIA_UPC:                                   |
|                  o  Produces the Universal Product Code (UPC)      |
|                     that is encoded on an audio CD.  The UPC       |
|                     is a string of digits.  It might not be        |
|                     available for all CDs.                         |
|                                                                    |
|              MCI_INFO_MEDIA_IDENTITY:                              |
|                  o  Produces a unique identifier for the audio     |
|                     CD currently loaded in the player being        |
|                     queried.  This flag returns a string of 16     |
|                     hexidecimal digits.                            |
|                                                                    |
| Returns:     The unique string.                                    |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::GetID (LPSTR& id)
{
	static char deviceIdentString [100];
	HRESULT result;

#if MEDIA_UPC_WORKS

	MCI_INFO_PARMS mciInfoParms;

	mciInfoParms.lpstrReturn = deviceIdentString;
	mciInfoParms.dwRetSize = 100;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_INFO,
			// MCI_INFO_MEDIA_IDENTITY,
			MCI_INFO_MEDIA_UPC,
			(DWORD) (LPVOID) &mciInfoParms))
	{
		Close ();
		return result;
	}

#else
	MCI_STATUS_PARMS mciStatusParms;

	DWORD trackLength;

	mciStatusParms.dwItem = MCI_STATUS_LENGTH;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	trackLength = mciStatusParms.dwReturn;
	sprintf (deviceIdentString, "{%08x}", trackLength);

#endif
	id = deviceIdentString;

	return result;
}


/*-------------------------------------------------------------------+
|                       CDDevice::Status ()                          |
| ================================================================== |
|                                                                    |
| Function:    Obtains the device state.                             |
|                                                                    |
| Returns:     S_OK if successful or an error otherwise.             |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Status (DWORD& mode)
{
	MCI_STATUS_PARMS mciStatusParms;
	HRESULT result;

	mciStatusParms.dwItem = MCI_STATUS_MODE;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	mode = mciStatusParms.dwReturn;

	return result;
}


/*-------------------------------------------------------------------+
|                    CDDevice::IsMediaPresent ()                     |
| ================================================================== |
|                                                                    |
| Function:    Determines if the CD is loaded in the caddy.          |
|                                                                    |
| Returns:     TRUE:  Media present                                  |
|              FALSE: Media NOT present (or) error occurred.         |
|                                                                    |
+-------------------------------------------------------------------*/
BOOL CDDevice::IsMediaPresent ()
{
	BOOL status;
	HRESULT result;

	MCI_STATUS_PARMS mciStatusParms;

	mciStatusParms.dwItem = MCI_STATUS_MEDIA_PRESENT;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	status = mciStatusParms.dwReturn;

	return status;
}


/*-------------------------------------------------------------------+
|                      CDDevice::NumTracks ()                        |
| ================================================================== |
|                                                                    |
| Function:    Determine the number of tracks on the CD.             |
|                                                                    |
| Returns:     The number of tracks on the CD.                       |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::NumTracks ()
{
	DWORD numTracks;
	HRESULT result;

	MCI_STATUS_PARMS mciStatusParms;

	mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	numTracks = mciStatusParms.dwReturn;

	return numTracks;
}

/*-------------------------------------------------------------------+
|                       CDDevice::Track ()                           |
| ================================================================== |
|                                                                    |
| Function:    ...                                                   |
|                                                                    |
| Algorithm:   ...                                                   |
|                                                                    |
| Parameters:  ...                                                   |
|                                                                    |
| Returns:     ...                                                   |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::Track (DWORD& track)
{
	MCI_STATUS_PARMS mciStatusParms;
	HRESULT result;

	// mciPlayParms.dwCallBack = 0;
	// mciPlayParms.dwTrack    = 0;
	// mciPlayParms.dwReturn   = 0;

	mciStatusParms.dwItem = MCI_STATUS_POSITION;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	track = mciStatusParms.dwReturn;

	return result;
}


/*-------------------------------------------------------------------+
|                       CDDevice::TrackLength ()                     |
| ================================================================== |
|                                                                    |
| Function:    ...                                                   |
|                                                                    |
| Algorithm:   ...                                                   |
|                                                                    |
| Parameters:  ...                                                   |
|                                                                    |
| Returns:     ...                                                   |
|                                                                    |
+-------------------------------------------------------------------*/
DWORD CDDevice::TrackLength (BYTE track, DWORD& trackLength)
{
	MCI_STATUS_PARMS mciStatusParms;
	HRESULT result;

	// mciStatusParms.dwCallBack = 0;
	mciStatusParms.dwTrack    = track;
	// mciStatusParms.dwReturn   = 0;
	mciStatusParms.dwItem = MCI_STATUS_LENGTH;

	if (result = mciSendCommand (
			fDeviceID, 
			MCI_STATUS,
			MCI_STATUS_ITEM | MCI_TRACK,
			(DWORD) (LPVOID) &mciStatusParms))
	{
		Close ();
		return result;
	}

	trackLength = mciStatusParms.dwReturn;

	return result;
}
