/******************************************************************************
*                                                                             *
*   Name:  MMSRV.C                                                            *
*                                                                             *
*   Copyright : COPYRIGHT IBM CORPORATION, 1993                               *
*               LICENSED MATERIAL - PROGRAM PROPERTY OF IBM                   *
*                                                                             *
*   Description: Multi media handling routines.                               *
*                                                                             *
*   Hardware Requirement: Audio I/O Device.                                   *
*                                                                             *
*   Software Requirement: IBM OS/2 V2.1, Pen for OS/2 V 1.0 and MMPM/2 V1.1   *
*                                                                             *
*   Subroutine Names and their function:                                      *
*                                                                             *
*      mmsrvSetVolume : Set volume of speaker phone                           *
*                                                                             *
*      mmsrvAcquire : Acquire device before play and recording                *
*                                                                             *
*      mmsrvRelease : Release device after recording and playing is done      *
*                                                                             *
*      mmsrvStop : Stop device when STOP button is clicked when recording     *
*                  and playing is done.                                       *
*                                                                             *
*      mmsrvClose : Close the device at end                                   *
*                                                                             *
*      mmsrvOpen : Open device at the beginning                               *
*                                                                             *
*      mmsrvPlay : Play device with recorded data (voice)                     *
*                                                                             *
*      mmsrvRecord : Record voice.                                            *
*                    The MM_MCIPOSITIONCHANGE message is sent for every one   *
*                    tenth second from the multi media to the Audio dialog    *
*                    window while recording and playing.                      *
*                                                                             *
*  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is                *
*      sample code created by IBM Corporation. This sample code is not        *
*      part of any standard or IBM product and is provided to you solely      *
*      for  the purpose of assisting you in the development of your           *
*      applications.  The code is provided "AS IS", without                   *
*      warranty of any kind.  IBM shall not be liable for any damages         *
*      arising out of your use of the sample code, even if they have been     *
*      advised of the possibility of such damages.                            *
*                                                                             *
******************************************************************************/

#define  INCL_DOS
#define  INCL_WIN
#define  INCL_GPI
#define  INCL_PM
#define  INCL_DOSFILEMGR

#include <os2.h>
//#include <stdlib.h>
//#include <stdio.h>

#define  INCL_MMIO
#define  INCL_OS2MM
#include <os2me.h>
#include "mmsrv.h"

/*****************************************************************************
*                                                                            *
*   Subroutine Name : ShowError                                              *
*                                                                            *
*   Function: Give the error message with return code in a message box.      *
*                                                                            *
*   Parameters:                                                              *
*                 PSZ   err:  error message string, INPUT                    *
*                 ULONG errid: error code,          INPUT                    *
*                                                                            *
*****************************************************************************/
VOID ShowError(PSZ  err, ULONG errid)
{
  char terr[100];

   sprintf(terr, "%s %d", err, errid);
   WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, terr, "Attention", 0, MB_OK);
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvSetVolume                                         *
*                                                                            *
*   Function: Set volume level when user adjust the volume level in          *
*             volume scroll bar.                                             *
*                                                                            *
*   Parameters:                                                              *
*                USHORT usVolume: volume level, INPUT                        *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_SET                                          *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvSetVolume( USHORT usVolume)
{
   ULONG                ulReturn = 0;  /* error value for mci returns   */
   MCI_WAVE_SET_PARMS   mspSet;        /* set values for volume, etc.   */

   usLevel = usVolume;
   if (usWaveId != 0)
   {
      /*******************************************************************
      *  To set the volume,  first, the MCI_SET_PARMS structure must be  *
      *  filled with the necessary values.  Then an MCI_SET command      *
      *  should be issued to the device to perform the volume change.    *
      *******************************************************************/
      memset(&mspSet, 0, sizeof(mspSet));
      mspSet.hwndCallback = (HWND) NULL;
      mspSet.ulAudio    = MCI_SET_AUDIO_ALL;    /* set all channels     */
      mspSet.ulLevel    = (ULONG) usVolume;     /* volume level desired */
      ulReturn = mciSendCommand((USHORT) usWaveId,
                                MCI_SET,
                                MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
                                (PVOID) &mspSet,
                                0);
      if (ulReturn)
         ShowError( "error while setting up the volume", ulReturn);
   }
   return ulReturn;
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvAcquire                                           *
*                                                                            *
*   Function: Acquire device before play and record.                         *
*                                                                            *
*   Parameters:  None.                                                       *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_ACQUIREDEVICE                                *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvAcquire(VOID)
{
   MCI_GENERIC_PARMS mciGenericParms;
   ULONG ulReturn;

   memset(&mciGenericParms, 0, sizeof(mciGenericParms));
   if (ulReturn = mciSendCommand((USHORT) usWaveId,
                                 MCI_ACQUIREDEVICE,
                                 MCI_WAIT | MCI_EXCLUSIVE_INSTANCE,
                                 (PVOID) &mciGenericParms,
                                 0L))
   {
      ShowError("error during acquiredevice ", ulReturn);
   }
   return(ulReturn);
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvRelease                                           *
*                                                                            *
*   Function: Release device after play or record is done.                   *
*                                                                            *
*   Parameters:  None.                                                       *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_RELEASEDEVICE                                *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvRelease(VOID)
{
   MCI_GENERIC_PARMS mciGenericParms;
   ULONG             ulReturn;

   memset(&mciGenericParms, 0, sizeof(mciGenericParms));
   if (ulReturn = mciSendCommand((USHORT) usWaveId,
                                 MCI_RELEASEDEVICE,
                                 MCI_WAIT,
                                 (PVOID) &mciGenericParms,
                                 0))
   {
      ShowError( "error occured in releasing the device ", ulReturn);
   }
   return(ulReturn);
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvStop                                              *
*                                                                            *
*   Function: Stop device  when the STOP button is clicked while recording   *
*             or playing.                                                    *
*                                                                            *
*   Parameters:  None.                                                       *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_STOP                                         *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvStop(VOID)
{
   ULONG             ulReturn = 0;
   MCI_GENERIC_PARMS mciGenericParms;

   memset(&mciGenericParms, 0, sizeof(mciGenericParms));
   if (ulReturn = mciSendCommand((USHORT) usWaveId,
                                 MCI_STOP,
                                 MCI_WAIT,
                                 (PVOID) &mciGenericParms,
                                 0))
   {
      ShowError( "error occured in stopping the device ", ulReturn);
   }
   return(ulReturn);
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvClose                                             *
*                                                                            *
*   Function: Close device when the Audio dialog window is closed.           *
*                                                                            *
*   Parameters:  None.                                                       *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_CLOSE                                        *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvClose(VOID)
{
   ULONG             ulReturn = 0;
   MCI_GENERIC_PARMS mciGenericParms;

   memset(&mciGenericParms, 0, sizeof(mciGenericParms));
   if(ulReturn = mciSendCommand((USHORT) usWaveId,
                                MCI_CLOSE,
                                MCI_WAIT,
                                (PVOID) &mciGenericParms,
                                0))
   {
      ShowError("error in closing the device ", ulReturn);
   }
   usWaveId = 0;
   usAmpId = 0;
   return (ulReturn);
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvOpen                                              *
*                                                                            *
*   Function: Open  device at the beginnning for setup.                      *
*                                                                            *
*   Parameters :  HWND hwnd of audio dialog window, INPUT                    *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_OPEN, MCI_SYSINFO, MCI_CLOSE, MCI_SET        *
*                           MCI_SET_POSITION_ADVICE, MCI_CONNECTOR,          *
*                           MCI_SET_CONNECTION                               *
*                                                                            *
*   Pseudo Code:  Give defaule system info.                                  *
*                 Setup parameters for device ordinal number.                *
*                 Specify device type.                                       *
*                 Setup parameters for audio data file.                      *
*                 Setup time format in milisecond.                           *
*                 Setup input source.                                        *
*                 Set the input level.                                       *
*****************************************************************************/
LONG APIENTRY mmsrvOpen(HWND hwnd)
{
  MCI_OPEN_PARMS       lpWaveOpen;        // Used for MCI_OPEN messages
  MCI_CONNECTOR_PARMS  mciConnectorParms; /* for MCI_CONNECTOR               */
  MCI_WAVE_SET_PARMS   mciWaveSetParms;   /* for MCI_SET, waveform devices   */
  MCI_GENERIC_PARMS    mciGenericParms;   /* for MCI_ACQUIRE                 */
  MCI_AMP_SET_PARMS    mciAmpSetParms;    /* for MCI_SET, amp/mix devices    */
  MCI_CONNECTION_PARMS mciConnectionParms;/* for MCI_CONNECTION              */
  MCI_SET_PARMS        mciSetParms;
  MCI_POSITION_PARMS   mciSetPosParms;   /* to get periodic messages to show time */
  ULONG                     ulReturn;

  MCI_SYSINFO_PARMS         mciSysinfoParms;
  MCI_SYSINFO_DEFAULTDEVICE mciSysinfoDefaultdevice;
  MCI_SYSINFO_QUERY_NAME    mciSysinfoQueryName;
  ULONG                     ulError;
  USHORT                    usDeviceTypeOpened; /* for device type opened    */

   memset( &mciSysinfoParms, 0, sizeof( mciSysinfoParms ) );
   memset( &mciSysinfoDefaultdevice, 0, sizeof(mciSysinfoDefaultdevice));

   /**************************************************************************
   *  Set up parameters to query the default device for                      *
   *  MCI_DEVTYPE_WAVEFORM_AUDIO device type. If no explicit default exists, *
   *  then the first device of the indicated type is implicitely the default.*
   *                                                                         *
   *  First, initialize MCI_SYSINFO_PARMS and MCI_SYSINFO_DEFAULTDEVICE      *
   *  structures with the pertinent information then issue MCI_SYSINFO       *
   *  command via mciSendCommand. The pSysInfoParm field points to the       *
   *  MCI_SYSINFO_DEFAULTDEVICE structure. The default device name will be   *
   *  returned in the szInstallName field.                                   *
   **************************************************************************/
   mciSysinfoParms.ulItem  = MCI_SYSINFO_QUERY_DEFAULT;
   mciSysinfoParms.pSysInfoParm  = &mciSysinfoDefaultdevice;
   mciSysinfoDefaultdevice.usDeviceType  = MCI_DEVTYPE_WAVEFORM_AUDIO;

   ulError = mciSendCommand( (USHORT) 0,
                             MCI_SYSINFO,
                             MCI_WAIT | MCI_SYSINFO_ITEM,
                             (PVOID) &mciSysinfoParms,
                             0);

   if (ulError == 0L)
   {
      memset( &mciSysinfoParms , 0, sizeof(MCI_SYSINFO_PARMS));
      memset( &mciSysinfoQueryName , 0, sizeof(MCI_SYSINFO_QUERY_NAME));

      /************************************************************************
      * Set up parameters to query the device ordinal value. This message     *
      * query the given device name which is in the szInstallName field of the*
      * MCI_SYSINFO_DEFAULTDEVICE structure and returns the ordinal value of  *
      * the first device of that type. The pSysInfoParm field points to the   *
      * MCI_SYSINFO_QUERY_NAME structure which has the default device name.   *
      ************************************************************************/
      mciSysinfoParms.ulItem  = MCI_SYSINFO_QUERY_NAMES;
      mciSysinfoParms.pSysInfoParm  = &mciSysinfoQueryName;
      memmove( &mciSysinfoQueryName.szInstallName,
               &mciSysinfoDefaultdevice.szInstallName,
               sizeof(mciSysinfoQueryName.szInstallName ) );

      ulError = mciSendCommand( (USHORT) 0,
                                MCI_SYSINFO,
                                MCI_WAIT | MCI_SYSINFO_ITEM,
                                (PVOID) &mciSysinfoParms,
                                0);
      if (ulError == 0L)
         /* Get the device type ordinal value for further use. */
         usDeviceTypeOpened = (USHORT)mciSysinfoQueryName.usDeviceOrd;
   }
   else
   {
      ShowError("error in opening device", ulError);
      return (ulError);
   }

   memset(&lpWaveOpen, 0, sizeof(lpWaveOpen));
   lpWaveOpen.hwndCallback = (ULONG) 0;

   lpWaveOpen.usDeviceID   = (USHORT)  NULL; /* this is returned   */

   /**********************************************************************
   * Specify the device type. The pszDeviceType is to be interpreted as  *
   * the low-order word is a standard device type, and the high-order    *
   * word is the ordinal index for the device. In other words we are     *
   * explecitely trying to open the default device on the system. This   *
   * gives the ability to load a non existing (untitled) audio file.     *
   **********************************************************************/
   lpWaveOpen.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,
                                              usDeviceTypeOpened);

   /* send and receive in the same buf   */
   lpWaveOpen.pszElementName = (PSZ) NULL;
   lpWaveOpen.pszAlias = (PSZ) NULL;

   ulReturn = mciSendCommand((USHORT) 0,
                             MCI_OPEN,
                             MCI_WAIT | MCI_OPEN_TYPE_ID |
                             MCI_OPEN_SHAREABLE | MCI_OPEN_ELEMENT,
                             (PVOID) &lpWaveOpen,
                             (USHORT) NULL);

   if (ulReturn != 0)
   {
      (void) ShowError("Error in Opening the device", ulReturn);
      mciSendCommand((USHORT) usWaveId,
                     MCI_CLOSE,
                     MCI_WAIT,
                     (PVOID) &mciGenericParms,
                     0);
      return  ulReturn;
   }

   /* stash the returned device ID  */
   usWaveId = lpWaveOpen.usDeviceID;

   /**************************************************************************/
   /* * Set up parameters for the audio data file (such as stereo/mono,      */
   /* sample * rate and sample size).                                        */
   /**************************************************************************/
   memset(&mciWaveSetParms, 0, sizeof(mciWaveSetParms));
   mciWaveSetParms.usChannels = (USHORT) MONO;             /* specify MONO/STEREO */
   mciWaveSetParms.ulSamplesPerSec = (ULONG) SAMPPERSEC;   /* used for waveform */
   mciWaveSetParms.usBitsPerSample = (USHORT) BITSPERSAMP; /* bits per sample   */
   ulReturn = mciSendCommand((USHORT) usWaveId,
     MCI_SET,
     MCI_WAIT | MCI_WAVE_SET_CHANNELS | MCI_WAVE_SET_SAMPLESPERSEC | MCI_WAVE_SET_BITSPERSAMPLE,
     (PVOID) &mciWaveSetParms,
     0);
   if (ulReturn)
   {
      ShowError("Error in setting up wave format ", ulReturn);
      return (ulReturn);
   }

   /************************************************************************/
   /*   Set up time format in miliseconds                                  */
   /************************************************************************/
   memset(&mciWaveSetParms, 0, sizeof(mciWaveSetParms));
   mciWaveSetParms.ulTimeFormat = MCI_FORMAT_MILLISECONDS;
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_SET,
                             MCI_WAIT | MCI_SET_TIME_FORMAT,
                             (PVOID) &mciWaveSetParms,
                             0);
   if (ulReturn)
   {
      ShowError("Error in setting up time format ", ulReturn);
      return (ulReturn);
   }

   memset(&mciSetPosParms, 0, sizeof(mciSetPosParms));
   mciSetPosParms.hwndCallback = hwnd;
   mciSetPosParms.ulUnits      = 100;
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_SET_POSITION_ADVISE,
                             MCI_WAIT | MCI_SET_POSITION_ADVISE_ON,
                             (PVOID) &mciSetPosParms,
                             0);
   if (ulReturn)
   {
      ShowError("error in setting the position setting", ulReturn);
      return (ulReturn);
   }

   /***********************************************************************/
   /* Set up input source - microphone.                                   */
   /***********************************************************************/
   memset(&mciConnectorParms, 0, sizeof(mciConnectorParms));
   mciConnectorParms.ulConnectorType = MCI_MICROPHONE_CONNECTOR; /* microphone */
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_CONNECTOR,
                             MCI_WAIT | MCI_CONNECTOR_TYPE | MCI_ENABLE_CONNECTOR,
                             (PVOID) &mciConnectorParms,
                             0);
   if (ulReturn)
   {
      ShowError("error in setting microphone as source", ulReturn);
      return (ulReturn);
   }

   memset(&mciConnectionParms, 0, sizeof(mciConnectionParms));
   mciConnectionParms.ulConnectorType = MCI_WAVE_STREAM_CONNECTOR;
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_CONNECTION,
                             MCI_WAIT | MCI_QUERY_CONNECTION | MCI_CONNECTOR_TYPE,
                             (PVOID) &mciConnectionParms,
                             0);
   if (ulReturn)
   {
      ShowError("error in getting amp id", ulReturn);
      return (ulReturn);
   }
   usAmpId = mciConnectionParms.usToDeviceID;

   /**********************************************************************/
   /* * Set the appropriate input level.                                 */
   /**********************************************************************/
   mciAmpSetParms.ulAudio = MCI_SET_AUDIO_ALL; /* all the channels.         */
   mciAmpSetParms.ulLevel = (ULONG) 100;       /* set audio level.          */
   ulReturn = mciSendCommand((USHORT) usAmpId,
                             MCI_SET,
                             MCI_WAIT | MCI_SET_AUDIO | MCI_AMP_SET_GAIN,
                             (PVOID) &mciAmpSetParms,
                             0);
   if (ulReturn)
   {
      ShowError("error in setting the gain level", ulReturn);
      return (ulReturn);
   }
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvPlay                                              *
*                                                                            *
*   Function: Play the recorded audio data.                                  *
*                                                                            *
*   Parameters :  HWND hwnd of audio dialog window, INPUT                    *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_PLAY                                         *
*                                                                            *
*****************************************************************************/
LONG APIENTRY mmsrvPlay(HWND hwnd)
{
   ULONG          ulReturn;
   MCI_PLAY_PARMS mciPlayParms;

   if ((ulReturn = mmsrvSetVolume(usLevel)) != 0)
      return ulReturn;
   memset(&mciPlayParms, 0, sizeof(mciPlayParms));
   mciPlayParms.hwndCallback = (HWND) hwnd;
   mciPlayParms.ulFrom = 0;
   if (ulReturn = mciSendCommand((USHORT) usWaveId,
                                 MCI_PLAY,
                                 MCI_NOTIFY | MCI_FROM,
                                 (PVOID) &mciPlayParms,
                                 0L))
   {
      ShowError("error during playback no ", ulReturn);
   }
   return  ulReturn;
}

/*****************************************************************************
*                                                                            *
*   Subroutine Name : mmsrvRecord                                            *
*                                                                            *
*   Function: Record the voice.                                              *
*                                                                            *
*   Parameters :  HWND hwnd of audio dialog window, INPUT                    *
*                                                                            *
*   MMPM/2 API: mciSendCommand                                               *
*                                                                            *
*   MMPM/s Message handled: MCI_SEEK, MCI_DELETE, MCI_RECORD                 *
*                                                                            *
*   Pseudo Code: Change the media position of device.                        *
*                Remove any remaining data from device.                      *
*                Start recording.                                            *
*****************************************************************************/
LONG APIENTRY mmsrvRecord(HWND hwnd)
{
  ULONG             ulReturn = 0;
  MCI_RECORD_PARMS  mciRecordParms;    /* for MCI_RECORD */
  MCI_GENERIC_PARMS mciGenericParms;
  MCI_AMP_SET_PARMS mciAmpSetParms;    /* for MCI_SET, amp/mix devices      */
  MCI_EDIT_PARMS    mciEditParms;
  MCI_SEEK_PARMS    mciWaveSeekParms;

   /**************************************************************************/
   /* * Set the Monitor on.                                                  */
   /**************************************************************************/
   memset(&mciWaveSeekParms, 0, sizeof(mciWaveSeekParms));
   mciWaveSeekParms.ulTo = 0L;
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_SEEK,
                             MCI_TO_START | MCI_WAIT,
                             (PVOID) &mciWaveSeekParms,
                             (USHORT) NULL);
   if(ulReturn)
   {
      ShowError("error in seeking ", ulReturn);
      return(ulReturn);
   }

   memset(&mciEditParms, 0, sizeof(mciEditParms));
   mciEditParms.hwndCallback = (ULONG) NULL;
   mciEditParms.ulFrom = 0L;
   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_DELETE,
                             MCI_WAIT,
                             (PVOID) &mciEditParms,
                             (USHORT) NULL);

   if(ulReturn)
   {
      ShowError("error occured in deleting old recording ", ulReturn);
      return(ulReturn);
   }

   /**************************************************************************/
   /* initialize MCI_RECORD_PARMS structure with the pertinent               */
   /* information then issue an MCI_RECORD command via mciSendCommand.       */
   /**************************************************************************/
   memset(&mciRecordParms, 0, sizeof(mciRecordParms));
   mciRecordParms.hwndCallback = hwnd;                 /* notify main window */
   mciRecordParms.ulFrom = 0;

   ulReturn = mciSendCommand((USHORT) usWaveId,
                             MCI_RECORD,
                             MCI_NOTIFY | MCI_FROM | MCI_RECORD_OVERWRITE,
                             (PVOID) &mciRecordParms,
                             0);
   if (ulReturn)
   {
      ShowError("error occured in recording ", ulReturn);
      memset(&mciGenericParms, 0, sizeof(mciGenericParms));
      mciSendCommand((USHORT) usWaveId,
                     MCI_STOP,
                     MCI_WAIT,
                     (PVOID) &mciGenericParms,
                     0);
   }
   return(ulReturn);
}
