home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / runnable / mmos2 / mmtoolkt / samples / admct / admcrecd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  35.5 KB  |  1,098 lines

  1. /*static char *SCCSID = "@(#)admcrecd.c    13.17 92/04/29";*/
  2. /********************* START OF SPECIFICATIONS *********************
  3. *
  4. * SUBROUTINE NAME: MCIRECD.C
  5. *
  6. * DESCRIPTIVE NAME: Audio MCD WaveAudio Recording Function.
  7. *
  8. * FUNCTION:Record into  Waveform Audio Element.
  9. *
  10. * NOTES:
  11. *
  12. * ENTRY POINTS:
  13. *     LINKAGE:   CALL FAR
  14. *
  15. * INPUT: MCI_Record message.
  16. *        MCI_FROM Flag
  17. *        MCI_TO   Flag
  18. *        MCI_RECORD_OVERWRITE   Flag
  19. *        MCI_RECORD_INSERT      Flag
  20. *
  21. * EXIT-NORMAL: Return Code 0.
  22. *
  23. * EXIT_ERROR:  Error Code.
  24. *
  25. * EFFECTS:
  26. *           The Original Element may be modified.
  27. *           All Recording is lost if MCI_SAVE message is not specified.
  28. *
  29. *
  30. * INTERNAL REFERENCES:   CreateNAssocStream ().
  31. *                        DestroyStream ().
  32. *                        AssocMemPlayToAudioStream ().
  33. *                        DoTillEvent().
  34. *                        ConvertTimeUnits ().
  35. *                        StartRecord().
  36. *                        ReEventProc().
  37. *                        SetAudioDevice().
  38. *                        InitAudioDevice().
  39. *                        SetWaveDeviceDefaults().
  40. *                        OpenFile().
  41. *                        CheckMem ().
  42. *
  43. * EXTERNAL REFERENCES:   DosResetEventSem ()        - OS/2 API
  44. *                        DosPostEventSem  ()        - OS/2 API
  45. *                        DosCreateThread ()         - OS/2 API
  46. *                        SpiEnableEvent ()          - MME API
  47. *                        SpiStopStream ()           - MME API
  48. *                        SpiCreateStream ()         - MME API
  49. *                        SpiAssociate()             - MME API
  50. *                        SpiSeekStream ()           - MME API
  51. *                        mdmDriverNotify ()         - MME API
  52. *                        mmioSetHeader ()           - MME API
  53. *
  54. *********************** END OF SPECIFICATIONS **********************/
  55. #define INCL_BASE
  56. #define INCL_DOSMODULEMGR
  57. #define INCL_DOSSEMAPHORES
  58.  
  59. #include <os2.h>
  60. #include <string.h>
  61. #include <os2medef.h>                   // MME includes files.
  62. #include <audio.h>                      // Audio Device defines
  63. #include <ssm.h>                        // SSM spi includes.
  64. #include <meerror.h>                    // MM Error Messages.
  65. #include <mmsystem.h>                   // MM System Include.
  66. #include <mcidrv.h>                     // Mci Driver Include.
  67. #include <mmio.h>                       // MMIO Include.
  68. #include <mcd.h>                        // VSDIDriverInterface.
  69. #include <hhpheap.h>                    // Heap Manager Definitions
  70. #include <audiomcd.h>                   // Component Definitions.
  71. #include "admcfunc.h"                   // Function Prototypes
  72.  
  73. /********************* START OF SPECIFICATIONS *********************
  74. *
  75. * SUBROUTINE NAME: MCIRECD.C
  76. *
  77. * DESCRIPTIVE NAME: Waveform Record Routine.
  78. *
  79. * FUNCTION: Record into an Waveform File.
  80. *
  81. * NOTES:  hStream[2] = B --> A = Record stream.
  82. *
  83. * ENTRY POINTS:
  84. *     LINKAGE:   CALL FAR
  85. *
  86. * INPUT: MCI_PLAY message.
  87. *
  88. * EXIT-NORMAL: Return Code 0.
  89. *
  90. * EXIT_ERROR:  Error Code.
  91. *
  92. * EFFECTS:
  93. *
  94. * INTERNAL REFERENCES:  CreateNAssocStream ().
  95. *                       ().
  96. *                       DoTillEvent ().
  97. *                       OpenFile ().
  98. *                       SetAudioDevice ().
  99. *                       SetWaveDeviceDefaults ().
  100. *                       AssocMemPlayToAudioStream ().
  101. *
  102. * EXTERNAL REFERENCES:  SpiStartStream ()    - SSM  Spi
  103. *                       SpiStopStream  ()    - SSM  Spi
  104. *
  105. *********************** END OF SPECIFICATIONS **********************/
  106. RC MCIRecd (FUNCTION_PARM_BLOCK *pFuncBlock)
  107.  
  108. {
  109.   ULONG                   ulrc;               // Propogated Error Code
  110.   INSTANCE                *ulpInstance;       // Local Instance
  111.   ULONG                   ulParam1;           // Incoming MCI Flags
  112.   USHORT                  usEvcbIndex;        // EVCB Loop Index
  113.   USHORT                  ulAssocFlag;        // Stream Handler Type
  114.   DWORD                   dwSetAll;           // Set all Wave Extens
  115.   DWORD                   dwTempTO;           // Length of Element
  116.   ULONG                    lCnt;               // Sem Posting Count
  117.   DWORD                   dwSpiSeekFlags;     // Stream Seek Flags
  118.   DWORD                   dwTemp1;            // Time format conversion
  119.   DWORD                   dwTemp2;            // Time Format conversion
  120.   DWORD                   dwMMFileLength;     // Media Element Length
  121.   MCI_WAVE_SET_PARMS      lpSetParms;         // MCI Wave Set Parms
  122.   LPMCI_RECORD_PARMS      lpRecordParms;      // MCI Record Parms
  123.  
  124.  
  125.   /**********************************
  126.   * Intialize Flags and other vars
  127.   ***********************************/
  128.   ulrc = MCIERR_SUCCESS;
  129.   usEvcbIndex = 0;
  130.   ulAssocFlag = 0;
  131.   dwSetAll = MCI_WAVE_SET_BITSPERSAMPLE| MCI_WAVE_SET_FORMATTAG|
  132.              MCI_WAVE_SET_CHANNELS| MCI_WAVE_SET_SAMPLESPERSEC;
  133.  
  134.   dwSpiSeekFlags = SPI_SEEK_ABSOLUTE;
  135.   /********************************
  136.   * derefernce pointers
  137.   *********************************/
  138.   ulpInstance= (INSTANCE *)pFuncBlock->ulpInstance;
  139.   ulParam1 = pFuncBlock->ulParam1;
  140.  
  141.   /**********************************************************************
  142.   * Destroy The stream if a play preceded the direction of the stream is
  143.     reversed. The previous stream gets destroyed.
  144.   **********************************************************************/
  145.   if (AMPMIX.ulOperation == OPERATION_PLAY)
  146.       {
  147.  
  148.       if ( ulpInstance->StreamEvent == EVENT_EOS ||
  149.            STRMSTATE == MCI_STOP                 ||
  150.            STRMSTATE == CUEPLAY_STATE            ||
  151.            STRMSTATE == MCI_SEEK                 ||
  152.            STRMSTATE == STOP_PAUSED )
  153.          {
  154.          if ( !ulpInstance->ulOldStreamPos  )
  155.             {
  156.             ulrc = SpiGetTime( STREAM.hStream,
  157.                                ( PMMTIME ) &ulpInstance->ulOldStreamPos );
  158.  
  159.             // if an error occurred, then don't remember our position in the stream
  160.  
  161.             if ( ulrc )
  162.                {
  163.                ulpInstance->ulOldStreamPos = 0;
  164.                }
  165.             }
  166.  
  167.          DestroyStream (STREAM.hStream);
  168.  
  169.          }   /* EOS and hanging around */
  170.  
  171.          ulpInstance->ulCreateFlag = CREATE_STATE;
  172.  
  173.       }      /* Transition from PLAY State */
  174.  
  175.  
  176.    /***********************************************
  177.    * If a set was performed on an existing stream,
  178.    * destroy the stream and get new spcb keys
  179.    ***********************************************/
  180.    if ( STRMSTATE == STREAM_SET_STATE )
  181.       {
  182.       DestroyStream (STREAM.hStream);
  183.  
  184.       ulpInstance->ulCreateFlag = CREATE_STATE;
  185.  
  186.       }
  187.  
  188.   /*********************************************************************
  189.   * Create The Recording stream. This normally goes from audio stream
  190.   * handler to the file system stream handler. Based on the associate
  191.   * flag we can change the recording destination to File system or
  192.   * memory (in case of playlist)
  193.   *********************************************************************/
  194.   if (ulpInstance->ulCreateFlag != PREROLL_STATE) {
  195.  
  196.        if (ulpInstance->usPlayLstStrm == TRUE) {
  197.             ulAssocFlag = (ULONG)NULL;
  198.        }
  199.        else
  200.             ulAssocFlag = RECORD_STREAM;
  201.  
  202.       // get new spcb key
  203.  
  204.       ulrc = InitAudioDevice (ulpInstance, OPERATION_RECORD);
  205.  
  206.       if (ulrc)
  207.          {
  208.          return ( ulrc );
  209.          }
  210.       AMPMIX.ulOperation = OPERATION_RECORD;
  211.  
  212.       VSDInstToWaveSetParms (&lpSetParms,ulpInstance);
  213.  
  214.  
  215.       if (!ulrc)
  216.          ulrc = SetAudioDevice ( ulpInstance,
  217.                                  (LPMCI_WAVE_SET_PARMS)&lpSetParms,
  218.                                  dwSetAll);
  219.  
  220.       if ( ulrc )
  221.         {
  222.         return ( ulrc );
  223.         }
  224.  
  225.        /*************************************************
  226.        * If the init caused a new global sys file, use it
  227.        *************************************************/
  228.  
  229.        STREAM.AudioDCB.ulSysFileNum = AMPMIX.ulGlobalFile;
  230.  
  231.        /*************************************************
  232.        * Create a Stream with B = Src & A = Tgt
  233.        **************************************************/
  234.        ulrc = CreateNAssocStream (STREAM.hidBSource,
  235.                                   STREAM.hidATarget,
  236.                                   &(STREAM.hStream),
  237.                                   (INSTANCE *) ulpInstance,
  238.                                   (ULONG) ulAssocFlag,
  239.                                   (PEVFN)ReEventProc);
  240.        if (ulrc)
  241.            return (MCIERR_DRIVER_INTERNAL);
  242.  
  243.        /*****************************************************
  244.        * In Case of PlayList Do the Associate Seperately
  245.        ******************************************************/
  246.        if (ulAssocFlag == (ULONG)NULL)
  247.            ulrc = AssocMemPlayToAudioStrm (ulpInstance,
  248.                                            RECORD_STREAM);
  249.  
  250.  
  251.        if (ulpInstance->usPosAdvise == EVENT_ENABLED)
  252.            ulpInstance->usPosAdvise = TRUE;
  253.  
  254.        if (ulpInstance->usCuePt == EVENT_ENABLED)
  255.            ulpInstance->usCuePt = TRUE;
  256.  
  257.            /**********************
  258.            * Update State Flags
  259.            ***********************/
  260.        ulpInstance->ulCreateFlag = PREROLL_STATE;
  261.  
  262.        // If we previously destroyed a stream, seek to the position where we were
  263.        // else just seek to 0
  264.  
  265.        if ( !(ulParam1 & MCI_FROM ) )
  266.           {
  267.           ulrc = SpiSeekStream ( STREAM.hStream,
  268.                                  SPI_SEEK_ABSOLUTE,
  269.                                 ulpInstance->ulOldStreamPos );
  270.           if (ulrc)
  271.             {
  272.             return (ulrc);
  273.             }
  274.           }
  275.  
  276.        ulpInstance->ulOldStreamPos = 0;
  277.  
  278.        /************************************
  279.        * place the stream in a stopped state
  280.        * since no activity has occurred
  281.        *************************************/
  282.  
  283.        STRMSTATE = MCI_STOP;
  284.  
  285.   }  /* Create Flag != Preroll State */
  286.  
  287.   if (ulpInstance->usPlayLstStrm != TRUE) {
  288.  
  289.       /******************************************************************
  290.       * Fill in Wave Format. Do the Set header call here. At this point
  291.       * Recording of data commences at whatever audio device attributes
  292.       * that are currently set. This needs to be written in the wave
  293.       * header format chunk.
  294.       ******************************************************************/
  295.  
  296.       ulrc = SetAudioHeader (ulpInstance);
  297.  
  298.       ulrc = SetAmpDefaults (ulpInstance);
  299.  
  300.  
  301.       ulrc = InitAudioDevice (ulpInstance, OPERATION_RECORD);
  302.       if ( ulrc )
  303.          {
  304.          return ulrc;
  305.          }
  306.  
  307.   } /* Non PlayList */
  308.  
  309.  
  310.    ConvertTimeUnits (ulpInstance, (DWORD*)& (dwMMFileLength),
  311.                      FILE_LENGTH);
  312.  
  313.   dwTemp1 = dwMMFileLength;
  314.  
  315.   /****************************************
  316.   * From Flag For Record is not Supported
  317.   *****************************************/
  318.  
  319.   if (ulParam1 & MCI_FROM) {
  320.  
  321.  
  322.       lpRecordParms= (LPMCI_RECORD_PARMS )pFuncBlock->ulParam2;
  323.  
  324.       if (STRMSTATE != MCI_STOP )
  325.          {
  326.          /**************************************
  327.          * Reset Internal Semaphores Used
  328.          ****************************************/
  329.          DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  330.  
  331.          /**************************************
  332.          * Stop The Stream (Discard buffers)
  333.          **************************************/
  334.          ulrc = SpiStopStream (STREAM.hStream, SPI_STOP_DISCARD);
  335.  
  336.          if (!ulrc)
  337.            {
  338.            /*****************************************
  339.            * Wait for the stream to be stopped
  340.            *****************************************/
  341.  
  342.            DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  343.            }
  344.          }
  345.  
  346.      if ( lpRecordParms->dwFrom > dwTemp1 )
  347.        {
  348.        return MCIERR_OUTOFRANGE;
  349.        }
  350.  
  351.      ulrc = ConvertToMM (ulpInstance, &(dwTemp2),
  352.                          (DWORD)lpRecordParms->dwFrom);
  353.  
  354.        if (lpRecordParms->dwFrom > dwTemp1 )
  355.           return MCIERR_OUTOFRANGE;
  356.  
  357.        /******************************
  358.        * Do the Seek Thing
  359.        ******************************/
  360.  
  361.        if (!ulrc)
  362.          {
  363.          ulrc = SpiSeekStream (STREAM.hStream,
  364.                                dwSpiSeekFlags,
  365.                                (DWORD)( dwTemp2 + ulpInstance->ulSyncOffset));
  366.          }
  367.  
  368.     } /* Record From */
  369.   /**************************************************/
  370.   // From Flag For Record is Supported
  371.   /**************************************************/
  372.   if (ulParam1 & MCI_TO) {
  373.  
  374.       if (!ulrc)
  375.           {
  376.           lpRecordParms= (LPMCI_RECORD_PARMS )pFuncBlock->ulParam2;
  377.  
  378.           ulrc = ConvertToMM (ulpInstance, (DWORD*)&(dwTempTO),
  379.                                   (DWORD)(lpRecordParms->dwTo ));
  380.  
  381.           ulrc = CheckMem ((PVOID)pFuncBlock->ulParam2,
  382.                            sizeof (MCI_RECORD_PARMS), PAG_READ);
  383.  
  384.           if (ulrc != MCIERR_SUCCESS)
  385.               return MCIERR_MISSING_PARAMETER;
  386.  
  387.           if (!ulrc)
  388.               ulrc = DoTillEvent (ulpInstance, dwTempTO);
  389.  
  390.           ulpInstance->PlayTo = TRUE;
  391.           }
  392.   }   /* To Flag */
  393.  
  394.  
  395.   if (STRMSTATE == MCI_SEEK)
  396.       ulrc = SpiSeekStream (STREAM.hStream,
  397.                             SPI_SEEK_ABSOLUTE,
  398.                             STREAM.mmStreamTime);
  399.   /************************************
  400.   * Stick In Instance PTR in EVCB
  401.   *************************************/
  402.   STREAM.Evcb.ulpInstance = (ULONG)ulpInstance;
  403.  
  404.   /************************************
  405.   * Enable Position Advise if Needed
  406.   *************************************/
  407.   if (ulpInstance->usPosAdvise == TRUE) {
  408.  
  409.       /*******************************************
  410.       * Correct The hStream Value
  411.       *******************************************/
  412.       STREAM.PosAdvEvcb.evcb.hstream = STREAM.hStream;
  413.  
  414.       /***********************************************
  415.        * Stick In INSTANCE Pointer in The Time EVCB
  416.       ************************************************/
  417.       STREAM.PosAdvEvcb.ulpInstance = (ULONG)ulpInstance;
  418.  
  419.  
  420.       STREAM.PosAdvEvcb.evcb.mmtimeStream = STREAM.PosAdvEvcb.mmCuePt;
  421.       /************************************************
  422.       * Send The Event down to Audio Stream Handler
  423.       *************************************************/
  424.       ulrc = SpiEnableEvent((PEVCB) &(STREAM.PosAdvEvcb),
  425.                             (PHEVENT) &(STREAM.hPosEvent));
  426.  
  427.       ulpInstance->usPosAdvise = EVENT_ENABLED;
  428.  
  429.   } /* Enable Position Advise */
  430.  
  431.   /*****************************
  432.   * Enable Cue points if any
  433.   ******************************/
  434.   if (ulpInstance->usCuePt == TRUE) {
  435.       /******************************
  436.       * Correct The hStream Value
  437.       *******************************/
  438.       for (usEvcbIndex = 0; usEvcbIndex < CUEPTINDX; usEvcbIndex ++) {
  439.            CUEPTEVCB[usEvcbIndex].evcb.hstream = STREAM.hStream;
  440.  
  441.            /*************************************************
  442.            * Stick In INSTANCE Pointer in The Time EVCB
  443.            **************************************************/
  444.            CUEPTEVCB[usEvcbIndex].ulpInstance = (ULONG)ulpInstance;
  445.  
  446.            ulrc = SpiEnableEvent((PEVCB) &(STREAM.MCuePtEvcb[usEvcbIndex]),
  447.                                 (PHEVENT) &(STREAM.HCuePtHndl[usEvcbIndex]));
  448.       } /* For loop */
  449.  
  450.       ulpInstance->usCuePt = EVENT_ENABLED; // Reset The Flag
  451.   }  /* Enable Cue Point */
  452.  
  453.   /****************************************
  454.   * Send Insert Down To The Wave IO Proc
  455.   *****************************************/
  456.  
  457.   if (ulParam1 & MCI_RECORD_INSERT)
  458.      {
  459.       if ( ulpInstance->ulCanInsert)
  460.          {
  461.          ulrc = mmioSendMessage( ulpInstance->hmmio,
  462.                                  MMIOM_BEGININSERT,
  463.                                  0,
  464.                                  0);
  465.          if (ulrc)
  466.             {
  467.             ulrc = mmioGetLastError( ulpInstance->hmmio );
  468.  
  469.             return (ulrc);
  470.             }
  471.  
  472.            ulpInstance->usRecdInsert = TRUE;
  473.          }
  474.       else
  475.          {
  476.          return MCIERR_UNSUPPORTED_FLAG;
  477.          }
  478.      } /* Record Insert */
  479.  
  480.   if (!ulrc)
  481.       if (ulParam1 & MCI_NOTIFY) {
  482.           ulpInstance->usNotifyPending = TRUE;
  483.           ulpInstance->usNotPendingMsg = MCI_RECORD;
  484.  
  485.          /****************************************************
  486.          * This thread is kicked off by the MCD mainly
  487.          * to start the stream. Minimum processing should
  488.          * be done on the SSMs eventThread . The eventProc
  489.          * signalls This thread via semaphores and
  490.          * acts accordingly
  491.          ****************************************************/
  492.          DosResetEventSem (ulpInstance->hThreadSem, &lCnt);
  493.  
  494.          ulrc= DosCreateThread ((PTID)&(pFuncBlock->pInstance->RecdThreadID),
  495.                                  (PFNTHREAD)StartRecord,
  496.                                  (ULONG) pFuncBlock,
  497.                                  (ULONG) 0L,
  498.                                  (ULONG)NOTIFY_THREAD_STACKSIZE);
  499.  
  500.          /*************************************************
  501.          * Wait for the Record thread to do the start.
  502.          **************************************************/
  503.  
  504.          if (!ulrc)
  505.              DosWaitEventSem (ulpInstance->hThreadSem, -1);
  506.       }
  507.  
  508.       else
  509.       {
  510.           ulpInstance->usWaitPending = TRUE;
  511.           ulpInstance->usWaitMsg= MCI_RECORD;
  512.           ulrc = StartRecord (pFuncBlock);
  513.       }
  514.  
  515.   /**********************************
  516.   * Release data Access Semaphore
  517.   ***********************************/
  518.   MCD_ExitCrit (ulpInstance);
  519.  
  520.   return (ULONG)(ulrc);
  521. }
  522.  
  523.  
  524.  
  525. /********************* START OF SPECIFICATIONS *********************
  526. *
  527. * SUBROUTINE NAME: EventProc.
  528. *
  529. * DESCRIPTIVE NAME: SSM Event Handler
  530. *
  531. * FUNCTION:  Handle Streaming Event Notifications from SSM.
  532. *
  533. * NOTES: This routine is presumed to receive all types of event
  534. *        notifications from the SSM. The types include Implicit
  535. *        events, Cue point notifications in terms of both time
  536. *        and data. In response to Cue point notifications an
  537. *        MCI_CUEPOINT message is returned to MDM via mdmDriverNotify ()
  538. *
  539. * ENTRY POINTS:
  540. *     LINKAGE:   CALL FAR
  541. *
  542. * INPUT:
  543. *
  544. * EXIT-NORMAL: Return Code 0.
  545. *
  546. * EXIT_ERROR:  Error Code and flError flag is set.
  547. *
  548. * EFFECTS:
  549. *
  550. * INTERNAL REFERENCES:
  551. *
  552. * EXTERNAL REFERENCES: mdmDriverNotify ()  - MDM   API
  553. *
  554. *********************** END OF SPECIFICATIONS **********************/
  555. RC APIENTRY ReEventProc ( MEVCB *lpevcb)
  556. {
  557.   MTIME_EVCB        *pMTimeEVCB;      // Modified EVCB
  558.   ULONG              ulrc;            // RC
  559.   INSTANCE           * ulpInstance;   // Instance Ptr
  560.   HWND               hWnd;            // Call Back Handle
  561.  
  562.   ulrc = MCIERR_SUCCESS;
  563.  
  564.   /***********************************************************
  565.   * EventProc receives asynchronous SSM event notifications
  566.   * These events are signalled to the MCDs thread which
  567.   * blocks itself. The posting of the semaphore in response
  568.   * to implicit events releases the blocked thread which
  569.   * is waiting on the instance based event semaphore.
  570.   * The semaphore is not posted for time events like
  571.   * cuepoint (TIME) and media position changes.
  572.   **********************************************************/
  573.  
  574.   switch (lpevcb->evcb.ulType)
  575.   {
  576.   case EVENT_IMPLICIT_TYPE:
  577.        ulpInstance = (INSTANCE *)lpevcb->ulpInstance;
  578.        hWnd = (HWND)ulpInstance->dwCallback;
  579.  
  580.        switch (lpevcb->evcb.ulSubType)
  581.        {
  582.        case EVENT_EOS:
  583.             ulpInstance->StreamEvent = EVENT_EOS;
  584.             DosPostEventSem (ulpInstance->hEventSem);
  585.            break;
  586.  
  587.        case EVENT_ERROR:
  588.             ulpInstance->StreamEvent = EVENT_ERROR;
  589.             /**************************************
  590.             * End of PlayList event is received
  591.             * as an implicit error event. It
  592.             * is treated as a normal EOS
  593.             ***************************************/
  594.             if (ulpInstance->usPlayLstStrm == TRUE)
  595.                 if (lpevcb->evcb.ulStatus == ERROR_END_OF_PLAYLIST)
  596.                     ulpInstance->StreamEvent = EVENT_EOS;
  597.  
  598.             DosPostEventSem (ulpInstance->hEventSem);
  599.            break;
  600.  
  601.        case EVENT_STREAM_STOPPED:
  602.             /****************************************
  603.             * Event Stream Stopped. Release the
  604.             * Blocked thread
  605.             *****************************************/
  606.             ulpInstance->StreamEvent = EVENT_STREAM_STOPPED;
  607.             ulpInstance->usFileExists = TRUE;
  608.             DosPostEventSem (ulpInstance->hEventSem);
  609.            break;
  610.  
  611.        case EVENT_SYNC_PREROLLED:
  612.             /******************************************
  613.             * This event is received in reponse to a
  614.             * preroll start. A Preroll start is done
  615.             * on an MCI_CUE message.
  616.             *******************************************/
  617.             ulpInstance->StreamEvent = EVENT_SYNC_PREROLLED;
  618.             DosPostEventSem (ulpInstance->hEventSem);
  619.            break;
  620.  
  621.        case EVENT_PLAYLISTMESSAGE:
  622.             mdmDriverNotify ((WORD)ulpInstance->wWaveDeviceID,
  623.                              (HWND)hWnd,
  624.                              MM_MCIPLAYLISTMESSAGE,
  625.                              (WORD) MAKEULONG(lpevcb->evcb.ulStatus,
  626.                                               ulpInstance->wWaveDeviceID),
  627.                              (DWORD)lpevcb->evcb.unused1);
  628.  
  629.            break;
  630.  
  631.  
  632.        } /* SubType case of Implicit Events */
  633.       break;
  634.  
  635.   case EVENT_CUE_DATA:
  636.       break;
  637.  
  638.   case EVENT_CUE_TIME_PAUSE:
  639.       /***************************************************
  640.       * This event will arrive if we recorded to a certain
  641.       * position in the stream
  642.       ****************************************************/
  643.       pMTimeEVCB = (MTIME_EVCB *)lpevcb;
  644.       ulpInstance = (INSTANCE *)pMTimeEVCB->ulpInstance;
  645.       ulpInstance->StreamEvent = EVENT_CUE_TIME_PAUSE;
  646.  
  647.       DosPostEventSem (ulpInstance->hEventSem);
  648.       break;
  649.   case EVENT_CUE_TIME:
  650.  
  651.        pMTimeEVCB = (MTIME_EVCB *)lpevcb;
  652.        ulpInstance = (INSTANCE *)pMTimeEVCB->ulpInstance;
  653.  
  654.       /***************************************************
  655.       * Single Time Events are Treated as Time Cue Points
  656.       ****************************************************/
  657.       if ( pMTimeEVCB->evcb.ulFlags == EVENT_SINGLE )
  658.          {
  659.          mdmDriverNotify ((WORD)ulpInstance->wWaveDeviceID,
  660.                           (HWND)pMTimeEVCB->dwCallback,
  661.                           MM_MCICUEPOINT,
  662.                           (WORD)pMTimeEVCB->usCueUsrParm,
  663.                           (DWORD)pMTimeEVCB->evcb.mmtimeStream);
  664.          }
  665.  
  666.       /***********************************************
  667.       * Recurring Events are Media Position Changes
  668.       ************************************************/
  669.       if ( pMTimeEVCB->evcb.ulFlags == EVENT_RECURRING )
  670.          {
  671.          mdmDriverNotify ( ulpInstance->wWaveDeviceID,
  672.                            (HWND)POSEVCB.dwCallback,
  673.                            MM_MCIPOSITIONCHANGE,
  674.                            (WORD)ulpInstance->usPosUserParm,
  675.                            (DWORD)pMTimeEVCB->evcb.mmtimeStream);
  676.          }
  677.  
  678.  
  679.       break;
  680.  
  681.   default:
  682.       break;
  683.  
  684.   }          /* All Events case */
  685.  
  686.   return (ULONG)(MCIERR_SUCCESS);
  687.  
  688. }              /* of Event Handler */
  689.  
  690.  
  691.  
  692.  
  693.  
  694. /********************* START OF SPECIFICATIONS *******************************
  695. *
  696. * SUBROUTINE NAME: StartRecord.
  697. *
  698. * DESCRIPTIVE NAME:StartRecording
  699. *
  700. * FUNCTION: SpiStartStream().
  701. *
  702. *
  703. * NOTES: This routine is called using app's wait thread (Wait Case)
  704. *        or a separate thread spawned by MCD on MCI Notify. SSMs
  705. *        asynch Events Signal The MCDs Thread, which acts as needed.
  706. * ENTRY POINTS:
  707. *     LINKAGE:   CALL FAR
  708. *
  709. * INPUT:
  710. *
  711. * EXIT-NORMAL: Return Code 0.
  712. *
  713. * EXIT_ERROR:  Error Code.
  714. *
  715. * EFFECTS:
  716. *
  717. * INTERNAL REFERENCES: None
  718. *
  719. * EXTERNAL REFERENCES: None
  720. *
  721. *********************** END OF SPECIFICATIONS *******************************/
  722. RC StartRecord (FUNCTION_PARM_BLOCK *pFuncBlock)
  723. {
  724.   ULONG         ulrc;
  725.   ULONG         lCnt;
  726.   ULONG         ulParam1;
  727.   ULONG         ulErr;
  728.   ULONG         ulSpiFlags;
  729.   LONG          lBogus;             // Temporary Stuff
  730.   LONG          lBytesRead;
  731.   USHORT        usRecdToNotify;
  732.   INSTANCE      * ulpInstance;
  733.   ULONG         ulHoldEvent;
  734.  
  735.    ulrc = ulErr = MCIERR_SUCCESS;
  736.    usRecdToNotify = FALSE;
  737.    ulpInstance = (INSTANCE *) pFuncBlock->ulpInstance;
  738.    ulParam1 = pFuncBlock->ulParam1;
  739.  
  740.  
  741.    /***********************************
  742.    * Reset and Wait on Sem
  743.    ************************************/
  744.    DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  745.  
  746.    /************************
  747.    * update state
  748.    *************************/
  749.  
  750.    STRMSTATE = MCI_RECORD;
  751.    /**************************
  752.    * Element Exists is set
  753.    ***************************/
  754.    ulpInstance->usFileExists = TRUE;
  755.  
  756.   /*****************************
  757.   * no one has issued an aborted
  758.   * or superceded
  759.   *****************************/
  760.   ulpInstance->ulNotifyAborted = FALSE;
  761.  
  762.  
  763.    /***********************
  764.    * Start the stream
  765.    ************************/
  766.    ulrc = SpiStartStream (STREAM.hStream, SPI_START_STREAM);
  767.  
  768.    /*****************************************
  769.     * Post The Thread Sem To release Notify
  770.     * Thread Blocked on this sem.
  771.    /***************************************/
  772.    if (ulParam1 & MCI_NOTIFY)
  773.        DosPostEventSem (ulpInstance->hThreadSem);
  774.  
  775.  
  776.    if ( !ulrc )
  777.       {
  778.       /*******************************************
  779.       *  Block this Thread For asynchronous
  780.       *  Events. (Event Proc Releases this block)
  781.       *******************************************/
  782.       DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  783.  
  784.       /*******************************************************
  785.       * Disable Thread Switching. The indefinite blockage of
  786.       * this thread is carried out by waiting on the event
  787.       * semaphore. The blocked thread will continue to run
  788.       * from this point (DosEnterCritSec()) once the event
  789.       * semaphore is posted asynchronously in response to
  790.       * a streaming event.
  791.       *******************************************************/
  792.       DosRequestMutexSem( ulpInstance->hmtxNotifyAccess, -1 );
  793.       DosEnterCritSec();
  794.  
  795.       if (ulpInstance->StreamEvent == EVENT_EOS) {
  796.         ulrc = MCI_NOTIFY_ABORTED;
  797.         ulpInstance->usRecdOK = TRUE;
  798.       }
  799.       else
  800.        if (ulpInstance->StreamEvent == EVENT_ERROR)
  801.            ulErr = STREAM.Evcb.evcb.ulStatus;
  802.  
  803.       /**********************************
  804.       * Disable Notify Pending Flag
  805.       ***********************************/
  806.  
  807.       if (ulpInstance->usNotifyPending == TRUE)
  808.         ulpInstance->usNotifyPending =FALSE;
  809.  
  810.       /*****************************
  811.       * Ensure that if we are being aborted
  812.       * by another thread, and we received
  813.       * an event that we ignore the event
  814.       * and let the other process post the
  815.       * notify
  816.       ******************************/
  817.       if (ulpInstance->ulNotifyAborted == TRUE)
  818.          {
  819.          ulpInstance->StreamEvent = EVENT_STREAM_STOPPED;
  820.          }
  821.  
  822.       /************************************
  823.       * Disable Record To Flag
  824.       ************************************/
  825.       if (ulpInstance->PlayTo == TRUE)
  826.         {
  827.  
  828.         ulpInstance->PlayTo = FALSE;
  829.         usRecdToNotify = TRUE;       // To Event Occurred
  830.         if ( !ulErr )
  831.            {
  832.            ulErr = MCI_NOTIFY_SUCCESSFUL;
  833.            }
  834.  
  835.         }
  836.  
  837.       /*******************************
  838.       * Resume Normal Tasking
  839.       *******************************/
  840.       DosExitCritSec();
  841.       DosReleaseMutexSem( ulpInstance->hmtxNotifyAccess );
  842.  
  843.       } /* if no error on a record */
  844.    else
  845.       {
  846.       /**********************************
  847.       * Disable Notify Pending Flag
  848.       ***********************************/
  849.  
  850.       if (ulpInstance->usNotifyPending == TRUE)
  851.         ulpInstance->usNotifyPending =FALSE;
  852.  
  853.       if ( ulParam1 & MCI_NOTIFY )
  854.          {
  855.          PostMDMMessage (ulrc, MCI_RECORD, pFuncBlock);
  856.          }
  857.  
  858.       return ulrc;
  859.       }
  860.  
  861.    /********************************
  862.    * Disable Position Advise
  863.    *********************************/
  864.    if (ulpInstance->usPosAdvise == TRUE)
  865.        ulrc = SpiDisableEvent(STREAM.hPosEvent);
  866.  
  867.  
  868.  
  869.    /************************************
  870.    * Flush stop The stream before the insert
  871.    * to prevent errors below
  872.    ************************************/
  873.    if (usRecdToNotify == TRUE)
  874.       {
  875.       DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  876.       /************************************
  877.       * Store the event since the stop will
  878.       * override it
  879.       ************************************/
  880.  
  881.       ulHoldEvent = ulpInstance->StreamEvent;
  882.  
  883.  
  884.       /*******************************************************
  885.       * If we are in a playlist and we get the end of playlist
  886.       * error (similar to EOS), do a stop discard to stop
  887.       * the audio stream handler
  888.       *******************************************************/
  889.  
  890.       if ( ( ulpInstance->usPlayLstStrm == TRUE &&
  891.            ulHoldEvent == EVENT_EOS ) ||
  892.            ( ulHoldEvent == EVENT_ERROR ) ||
  893.            ( ulHoldEvent == EVENT_STREAM_STOPPED ) )
  894.          {
  895.          ulSpiFlags = SPI_STOP_DISCARD;
  896.          }
  897.       else
  898.          {
  899.          ulSpiFlags = SPI_STOP_FLUSH;
  900.          }
  901.       ulrc = SpiStopStream (STREAM.hStream, ulSpiFlags );
  902.  
  903.       if (!ulrc)
  904.          {
  905.          DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  906.          }
  907.       ulrc = MCIERR_SUCCESS;
  908.  
  909.       } /* flush stop the stream */
  910.  
  911.  
  912.    // if we received an event error, stop the stream just in case
  913.  
  914.    if ( ulpInstance->StreamEvent == EVENT_ERROR )
  915.       {
  916.       /***********************************
  917.       * Reset and Wait on Sem
  918.       ************************************/
  919.       DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  920.  
  921.       ulHoldEvent = ulpInstance->StreamEvent;
  922.       ulrc = SpiStopStream (STREAM.hStream, SPI_STOP_DISCARD );
  923.  
  924.       if (!ulrc)
  925.          {
  926.          DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  927.          }
  928.       ulrc = MCIERR_SUCCESS;
  929.       ulpInstance->StreamEvent = ulHoldEvent;
  930.  
  931.       }
  932.  
  933.    if ( ulpInstance->usPlayLstStrm != TRUE )
  934.       {
  935.       if ( ulpInstance->usRecdInsert )
  936.         {
  937.  
  938.         ulrc = mmioSendMessage( ulpInstance->hmmio,
  939.                                 MMIOM_ENDINSERT,
  940.                                 0,
  941.                                 0);
  942.  
  943.         if (ulrc)
  944.           {
  945.           ulErr = MCIERR_DRIVER_INTERNAL;
  946.           }
  947.  
  948.         /***************************************
  949.         * Ensure that it no other record inserts
  950.         * will be done unless specified
  951.         ****************************************/
  952.  
  953.         ulpInstance->usRecdInsert = FALSE;
  954.  
  955.         }
  956.       }
  957.  
  958.    /**************************************
  959.    * Propogate Disk Full Error
  960.    ***************************************/
  961.    if (ulErr == MMIOERR_CANNOTWRITE)
  962.       {
  963.       ulErr = MCIERR_TARGET_DEVICE_FULL;
  964.       }
  965.  
  966.    if ( ulpInstance->usPlayLstStrm != TRUE )
  967.       {
  968.       /***********************************
  969.       * Set information for the header
  970.       ************************************/
  971.       WAVEHDR.usFormatTag = AMPMIX.sMode;
  972.       WAVEHDR.usChannels = AMPMIX.sChannels;
  973.       WAVEHDR.ulSamplesPerSec = AMPMIX.lSRate;
  974.       XWAVHDR.ulAudioLengthInMS = 0;
  975.       WAVEHDR.usBitsPerSample = ( USHORT ) AMPMIX.lBitsPerSRate;
  976.       WAVEHDR.usBlockAlign = ( USHORT ) AMPMIX.ulBlockAlignment;
  977.  
  978.       /*************************************************
  979.       * Tell the current IO Proc to clean up the header
  980.       **************************************************/
  981.       ulrc = mmioSetHeader( ulpInstance->hmmio,
  982.                             &ulpInstance->mmAudioHeader,
  983.                             sizeof( MMAUDIOHEADER ),
  984.                             &lBogus,
  985.                             0,
  986.                             0 );
  987.  
  988.       if (ulrc)
  989.          ulErr = (MCIERR_DRIVER_INTERNAL);
  990.  
  991.       /***********************************************
  992.       * Figure out what the new size of the file is
  993.       ************************************************/
  994.       ulrc = mmioGetHeader ( ulpInstance->hmmio,
  995.                              (PVOID) &(ulpInstance->mmAudioHeader),
  996.                              sizeof( MMAUDIOHEADER ),
  997.                              &lBytesRead,
  998.                              (ULONG)NULL,
  999.                              (ULONG)NULL );
  1000.  
  1001.       if (ulrc != MMIO_SUCCESS )
  1002.          ulErr = MCIERR_DRIVER_INTERNAL;
  1003.  
  1004.       // update our header size
  1005.  
  1006.       ulpInstance->mmckinfo.ckSize = XWAVHDR.ulAudioLengthInBytes;
  1007.  
  1008.       } /* update header if !playlist stream */
  1009.  
  1010.  
  1011.  
  1012.    /*****************************************
  1013.    * Handle posting of notifies for record to
  1014.    *****************************************/
  1015.  
  1016.    if (usRecdToNotify == TRUE)
  1017.       {
  1018.       /************************************
  1019.       * If an error occured, the stop will
  1020.       * override  the value we had previously
  1021.       * so restore it
  1022.       ************************************/
  1023.       ulpInstance->StreamEvent = ulHoldEvent;
  1024.  
  1025.       /************************************
  1026.       * We only want to post success if the
  1027.       * stream hit the cue time pause
  1028.       ************************************/
  1029.       if (ulParam1 & MCI_NOTIFY && ulHoldEvent == EVENT_CUE_TIME_PAUSE )
  1030.            {
  1031.            PostMDMMessage (ulErr, MCI_RECORD, pFuncBlock);
  1032.            }
  1033.  
  1034.       if (ulParam1 & MCI_NOTIFY && ulHoldEvent == EVENT_EOS )
  1035.            {
  1036.            PostMDMMessage ( MCIERR_TARGET_DEVICE_FULL, MCI_RECORD, pFuncBlock);
  1037.  
  1038.            // Ensure that the normal notify won't process the message
  1039.            ulpInstance->StreamEvent = EVENT_STREAM_STOPPED;
  1040.  
  1041.            }
  1042.  
  1043.  
  1044.       ulrc = SpiDisableEvent(STREAM.hPlayToEvent);
  1045.  
  1046.       } /* Record Till XX with Notify On */
  1047.  
  1048.     /*****************************************/
  1049.     // Post The Notification only after
  1050.     // File is saved in case of To
  1051.     /*****************************************/
  1052.     if (ulpInstance->usWaitPending == TRUE) {
  1053.         ulpInstance->usWaitPending = FALSE;
  1054.         STRMSTATE = MCI_STOP;
  1055.         return (ulErr);
  1056.     }
  1057.  
  1058.     /***********************************/
  1059.     // Normal Notifies
  1060.     /***********************************/
  1061.     if (ulParam1 & MCI_NOTIFY) {
  1062.         ulpInstance->usNotifyPending =FALSE;
  1063.         if ((ulpInstance->StreamEvent == EVENT_EOS) ||
  1064.            (ulpInstance->StreamEvent == EVENT_ERROR))
  1065.            {
  1066.            /*******************************************
  1067.            * Post The Notification Message for Record
  1068.            ********************************************/
  1069.            PostMDMMessage (ulErr, MCI_RECORD, pFuncBlock);
  1070.            }
  1071.  
  1072.          /********************************************
  1073.          * Update Internal States to stop
  1074.          *********************************************/
  1075.          STRMSTATE = MCI_STOP;
  1076.  
  1077.     }   /* Notify is On */
  1078.  
  1079.  
  1080.     /**************************************************
  1081.     * Post The Semaphore to clear any Blocked threads
  1082.     **************************************************/
  1083.     DosPostEventSem (ulpInstance->hThreadSem);
  1084.  
  1085.     /**********************************************
  1086.     * Post Any Other Error Notifications if Notify
  1087.     **********************************************/
  1088.     if (ulParam1 & MCI_NOTIFY) {
  1089.  
  1090.        /********************************
  1091.        * Release Thread Block Memory
  1092.        *********************************/
  1093.        ulrc = CleanUp ((PVOID)pFuncBlock);
  1094.     }
  1095.  
  1096.     return (ulErr);
  1097. }
  1098.