home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cset21v6.zip / MMPM2TK / TK / ADMCT / ADMCRECD.C < prev    next >
C/C++ Source or Header  |  1993-04-12  |  51KB  |  1,523 lines

  1. /********************* START OF SPECIFICATIONS *********************
  2. *
  3. * SUBROUTINE NAME: MCIRECD.C
  4. *
  5. *
  6. *
  7. *              Copyright (c) IBM Corporation  1991, 1993
  8. *                        All Rights Reserved
  9. *
  10. * DESCRIPTIVE NAME: Audio MCD WaveAudio Recording Source.
  11. *
  12. * FUNCTION: Record into  Waveform Audio Element.
  13. *
  14. *  On MCI_RECORD, a streaming MCD should perform the following commands:
  15. *
  16. *  Always check flags and validate memory first.  This way if the flags
  17. *   are invalid, the previous command will not be interrupted.
  18. *  If there is a command active on another thread (i.e. and play, record
  19. *   or save), then either abort (play or save) or superced (record) by
  20. *   stopping the stream and sending a message to the caller.
  21. *  If the stream is going the wrong way (e.g. it is setup for playback)
  22. *   then destroy the stream.
  23. *  If no stream has been created, then create one.  If the stream handler
  24. *   needs to associate a data object, do it here.
  25. *  If we destroyed a play back stream before creating the record stream,
  26. *   seek to the same position in the record stream where the play back stream
  27. *   was.
  28. *  Enable any events (such as cuepoints or position advises).
  29. *  Setup MMIO networking hooks.
  30. *  Start stream.
  31. *  Wait for a streaming event.
  32. *  Stop the stream if necessary.
  33. *  If MCI_NOTIFY was sent used, inform the caller of command completion.
  34. *
  35. * NOTES: This source file illustrates the following concepts:
  36. *         A. Aborting or superceding a previous command
  37. *         B. Transitioning from a play stream->record stream
  38. *            so that the caller at the MCI Layer is unaware of the
  39. *            change.
  40. *         C. Processing a stream which was altered by the MCI_SET
  41. *            command.
  42. *         D. Proper creation of a stream.
  43. *         E. Processing the MCI_FROM/MCI_TO flags in a streaming
  44. *            environment.
  45. *         F. Enable both cuepoints and position advises.
  46. *         G. Processing record insert.
  47. *         H. Determing when the creation of a thread is necessary
  48. *            for an MCI_NOTIFY
  49. *         I. How to use MMIO networking features (via MMIOM_BEGINSTREAM).
  50. *         J. Proper handling of a record event procedure.
  51. *         K. Proper termination of a record thread.
  52. *         L. Communicating with MMIO for retrieving/seting file header.
  53. *         M. Communicating with MMIO to process recording/inserting.
  54. *
  55. *
  56. * ENTRY POINTS:
  57. *
  58. * INPUT: MCI_Record message.
  59. *        MCI_FROM Flag
  60. *        MCI_TO   Flag
  61. *        MCI_RECORD_OVERWRITE   Flag
  62. *        MCI_RECORD_INSERT      Flag
  63. *
  64. * EXIT-NORMAL: Return Code 0.
  65. *
  66. * EXIT_ERROR:  Error Code.
  67. *
  68. * EFFECTS:
  69. *           The Original Element may be modified.
  70. *           All Recording is lost if MCI_SAVE message is not specified.
  71. *
  72. *
  73. * INTERNAL REFERENCES:   CreateNAssocStream ().
  74. *                        DestroyStream ().
  75. *                        AssocMemPlayToAudioStream ().
  76. *                        CreateToEvent().
  77. *                        ConvertTimeUnits ().
  78. *                        StartRecord().
  79. *                        ReEventProc().
  80. *                        SetAudioDevice().
  81. *                        SetWaveDeviceDefaults().
  82. *                        OpenFile().
  83. *                        CheckMem ().
  84. *
  85. * EXTERNAL REFERENCES:   DosResetEventSem ()        - OS/2 API
  86. *                        DosPostEventSem  ()        - OS/2 API
  87. *                        DosCreateThread ()         - OS/2 API
  88. *                        SpiEnableEvent ()          - MME API
  89. *                        SpiStopStream ()           - MME API
  90. *                        SpiCreateStream ()         - MME API
  91. *                        SpiAssociate()             - MME API
  92. *                        SpiSeekStream ()           - MME API
  93. *                        mdmDriverNotify ()         - MME API
  94. *                        mmioSetHeader ()           - MME API
  95. *
  96. *********************** END OF SPECIFICATIONS **********************/
  97. #define INCL_BASE
  98. #define INCL_DOSMODULEMGR
  99. #define INCL_DOSSEMAPHORES
  100.  
  101. #include <os2.h>
  102. #include <string.h>
  103. #include <os2medef.h>                   // MME includes files.
  104. #include <audio.h>                      // Audio Device defines
  105. #include <ssm.h>                        // SSM spi includes.
  106. #include <meerror.h>                    // MM Error Messages.
  107. #include <mmioos2.h>                    // MMIO Include.
  108. #include <mcios2.h>                     // MM System Include.
  109. #include <mmdrvos2.h>                     // Mci Driver Include.
  110. #include <mcd.h>                        // VSDIDriverInterface.
  111. #include <hhpheap.h>                    // Heap Manager Definitions
  112. #include <qos.h>
  113. #include <audiomcd.h>                   // Component Definitions.
  114. #include "admcfunc.h"                   // Function Prototypes
  115.  
  116.  
  117. /********************* START OF SPECIFICATIONS *********************
  118. *
  119. * SUBROUTINE NAME: MCIRECD.C
  120. *
  121. * DESCRIPTIVE NAME: Waveform Record Routine.
  122. *
  123. * FUNCTION: Record into an Waveform File.
  124. *
  125. * NOTES:  hStream[2] = B --> A = Record stream.
  126. *
  127. * ENTRY POINTS:
  128. *     LINKAGE:   CALL FAR
  129. *
  130. * INPUT: MCI_PLAY message.
  131. *
  132. * EXIT-NORMAL: Return Code 0.
  133. *
  134. * EXIT_ERROR:  Error Code.
  135. *
  136. * EFFECTS:
  137. *
  138. * INTERNAL REFERENCES:  CreateNAssocStream ().
  139. *                       ().
  140. *                       OpenFile ().
  141. *                       SetAudioDevice ().
  142. *                       SetWaveDeviceDefaults ().
  143. *                       AssocMemPlayToAudioStream ().
  144. *
  145. * EXTERNAL REFERENCES:  SpiStartStream ()    - SSM  Spi
  146. *                       SpiStopStream  ()    - SSM  Spi
  147. *
  148. *********************** END OF SPECIFICATIONS **********************/
  149. RC MCIRecd (FUNCTION_PARM_BLOCK *pFuncBlock)
  150.  
  151. {
  152.   ULONG      ulrc;               // Propogated Error Code
  153.   ULONG      ulParam1;           // Incoming MCI Flags
  154.   ULONG      ulCnt;              // Sem Posting Count
  155.  
  156.   ULONG      ulAbortNotify = FALSE;
  157.  
  158.  
  159.   INSTANCE   *ulpInstance;       // Local Instance
  160.  
  161.   BOOL       fInitNeeded;        // Must the card be reinited
  162.   BOOL       fSeekNeeded = FALSE;// is a seek needed after a create
  163.  
  164.   MCI_AMP_INSTANCE     BackupAmp;           // Hold old amp values
  165.  
  166.   LONG       rc;                 // thread it return
  167.  
  168.   /********************************
  169.   * derefernce pointers
  170.   *********************************/
  171.   ulpInstance = (INSTANCE *)pFuncBlock->ulpInstance;
  172.   ulParam1 = pFuncBlock->ulParam1;
  173.  
  174.  
  175.   /*---------------------------------------------------------
  176.   * Make a copy of the amp/mixer instance in case any errors
  177.   * happened.
  178.   *---------------------------------------------------------*/
  179.  
  180.   memmove( &BackupAmp, &MIX, sizeof( MCI_AMP_INSTANCE ) );
  181.  
  182.  
  183.  
  184.   /*************************************************
  185.   * Check to ensure that all of the flags are valid
  186.   * memory is properly allocated and that the
  187.   * requested action is possible (i.e. the from
  188.   * position < to position, etc.)
  189.   **************************************************/
  190.  
  191.   ulrc = CheckRecordFlags ( pFuncBlock );
  192.  
  193.   /*******************************************
  194.   * If there are any errors, we must release
  195.   * the access semaphore which will allow
  196.   * other commands to process.  If we do not
  197.   * release this semaphore, the next command
  198.   * (i.e. MCI_PLAY, MCI_SET etc., will be
  199.   * blocked waiting for it to be posted.
  200.   *******************************************/
  201.  
  202.   if (ulrc)
  203.      {
  204.      return (ulrc);
  205.      }
  206.  
  207.   /****************************************
  208.   * If no stream has been created, and the
  209.   * card has not changed modes, there is no
  210.   * need to reinit it!
  211.   *****************************************/
  212.  
  213.   if ( AMPMIX.ulOperation == OPERATION_PLAY  ||
  214.        ulpInstance->StreamInfo.ulState == STREAM_SET_STATE )
  215.      {
  216.      fInitNeeded = TRUE;
  217.      }
  218.  
  219.    /***********************************************
  220.    * If all of the parameters are valid so far, then
  221.    * obtain semaphore which allows us to abort or
  222.    * supercede in progress commands.
  223.    ************************************************/
  224.  
  225.    GetNotifyAbortAccess ( ulpInstance, &ulAbortNotify );
  226.  
  227.   /*******************************************
  228.   * If there is an operation active (i.e. a
  229.   * play, record or save) then post a message
  230.   * stating that the command has been
  231.   * aborted (play), superceded (record) or
  232.   * wait for completion (save).
  233.   ********************************************/
  234.  
  235.    if ( ulAbortNotify == TRUE)
  236.       {
  237.       ulrc = AbortInProgressNotify( ulpInstance, pFuncBlock, ulParam1, MCI_RECORD );
  238.       }
  239.  
  240.  
  241.  
  242.  
  243.   /**********************************************************************
  244.   * Destroy the stream. If a play preceded, the direction of the stream is
  245.   * reversed. The previous stream gets destroyed.
  246.   **********************************************************************/
  247.  
  248.   if (AMPMIX.ulOperation == OPERATION_PLAY)
  249.       {
  250.        /***********************************************
  251.        * Since we are destroying an existing stream
  252.        * retrieve the current stream position.  When
  253.        * the record stream is created, we will
  254.        * seek to this point.  Do this so that the
  255.        * caller at the MCI Layer is ignorant of the
  256.        * streaming operations.
  257.        ***********************************************/
  258.  
  259.  
  260.       GetOldStreamPosition( ulpInstance);
  261.       DestroyStream ( &ulpInstance->StreamInfo.hStream);
  262.       ulpInstance->ulCreateFlag = CREATE_STATE;
  263.       if ( ulpInstance->ulOldStreamPos > 0 )
  264.          {
  265.          fSeekNeeded = TRUE;
  266.          }
  267.       }      /* Transition from PLAY State */
  268.  
  269.    /***********************************************
  270.    * If a set was performed on an existing stream,
  271.    * destroy the stream and get new spcb keys.  You
  272.    * MUST recreate the stream after and MCI_SET has
  273.    * been done since there is no way to communicate
  274.    * to the stream handler the change in data rates
  275.    * other than at spiCreate time.
  276.    ***********************************************/
  277.  
  278.    DestroySetStream ( ulpInstance );
  279.  
  280.   /*********************************************************************
  281.   * Create The Recording stream. This normally goes from audio stream
  282.   * handler to the file system stream handler. Based on the associate
  283.   * flag we can change the recording destination to File system or
  284.   * memory (in case of playlist)
  285.   *********************************************************************/
  286.  
  287.   if (ulpInstance->ulCreateFlag != PREROLL_STATE)
  288.  
  289.      {
  290.      /*******************************
  291.      * Do stream set up work and then
  292.      * create the stream
  293.      *******************************/
  294.  
  295.      ulrc = PrepareAndCreateStream( ulpInstance, OPERATION_RECORD, fInitNeeded );
  296.  
  297.      if ( ulrc )
  298.         {
  299.         /* Ensure that our instance remains the same as before the load attempt */
  300.    
  301.         memmove( &MIX, &BackupAmp, sizeof ( MCI_AMP_INSTANCE ) );
  302.  
  303.         return ( ulrc );
  304.         }
  305.  
  306.  
  307.      /***************************************************************
  308.      * Set the stream up with the same position advises and cuepoints
  309.      * as the previous stream had (if there any).
  310.      ***************************************************************/
  311.  
  312.      ulrc = RememberStreamState( ulpInstance, ulParam1, fSeekNeeded );
  313.  
  314.      if ( ulrc )
  315.         {
  316.         return ( ulrc );
  317.         }
  318.      }  /* Create Flag != Preroll State */
  319.  
  320.   /**********************
  321.   * Update State Flags
  322.   ***********************/
  323.   ulpInstance->ulCreateFlag = PREROLL_STATE;
  324.  
  325.   /*************************************************
  326.   * Playlist currently do not support io procs, thus
  327.   * they currently do not support MMIO calls.
  328.   * Therefore, if we are currently using a playlist
  329.   * then we cannot work with the audio header in the
  330.   * file.
  331.   **************************************************/
  332.  
  333. //  if (ulpInstance->usPlayLstStrm != TRUE)
  334. //      {
  335. //
  336. //      /******************************************************************
  337. //      * Before we start to record, set the header of the file via MMIO.
  338. //      * This will allow applications which opened the file via OPEN_MMIO
  339. //      * to allways have a correct view of what is in the file.
  340. //      ******************************************************************/
  341. //
  342. //      ulrc = SetAudioHeader (ulpInstance);
  343. //
  344. //      } /* Non PlayList */
  345.  
  346.  
  347.    /******************************************************************
  348.    * Place the stream in the correct position if MCI_FROM is specified
  349.    * and set the correct stopping point if MCI_TO is specfied
  350.    ******************************************************************/
  351.  
  352.    ulrc = ProcessFromToFlags( pFuncBlock, ulpInstance, MCI_RECORD, ulParam1 );
  353.  
  354.    if ( ulrc )
  355.       {
  356.       return ( ulrc );
  357.       }
  358.  
  359.  
  360.   /***********************************************
  361.   * If the caller requests that we record insert,
  362.   * then let the IO Procedure know that we want
  363.   * the record to be done via insert until we
  364.   * turn this flag off (at the end of StartRecord)
  365.   ************************************************/
  366.  
  367.   if (ulParam1 & MCI_RECORD_INSERT)
  368.      {
  369.      /* Not all IO Procs can insert, check capabilities first */
  370.  
  371.       if ( ulpInstance->ulCapabilities & CAN_INSERT )
  372.          {
  373.          /* Request record insert from mmio io proc */
  374.  
  375.          ulrc = mmioSendMessage( ulpInstance->hmmio,
  376.                                  MMIOM_BEGININSERT,
  377.                                  0,
  378.                                  0);
  379.          if (ulrc)
  380.             {
  381.             /* If an error, get a little more info via mmioGetLastError */
  382.  
  383.             ulrc = mmioGetLastError( ulpInstance->hmmio );
  384.  
  385.             return (ulrc);
  386.             }
  387.  
  388.            /* Set flag indicating that record insert is active */
  389.  
  390.            ulpInstance->fRecdInsert = TRUE;
  391.  
  392.          } /* Current IO Proc can insert */
  393.       else
  394.          {
  395.  
  396.          return ( MCIERR_UNSUPPORTED_FLAG );
  397.  
  398.          } /* Current IO Proc cannot insert */
  399.  
  400.      } /* Record Insert flag sent */
  401.  
  402.   else if ( !ulpInstance->usPlayLstStrm )
  403.  
  404.      {
  405.      ulrc = mmioSendMessage( ulpInstance->hmmio,
  406.                              MMIOM_BEGINGROUP,
  407.                              0,
  408.                              0);
  409.      if (ulrc)
  410.         {
  411.         ulrc = mmioGetLastError( ulpInstance->hmmio );
  412.  
  413.         return (ulrc);
  414.         }
  415.  
  416.  
  417.      } /* NORMAL RECORD */
  418.  
  419.  
  420.   /***********************************************
  421.   * Ensure that our avg. bytes per sec is accurate
  422.   * since a best fit could have changed the field
  423.   * on the fly.
  424.   ***********************************************/
  425.  
  426. //  ulpInstance->ulAverageBytesPerSec = WAVEHDR.usChannels * WAVEHDR.ulSamplesPerSec * ( WAVEHDR.usBitsPerSample / 8 );
  427.   ulpInstance->ulAverageBytesPerSec = AMPMIX.lSRate * ( AMPMIX.lBitsPerSRate / 8 ) * AMPMIX.sChannels;
  428.  
  429.  
  430.   /****************************************
  431.   * See if the network can support the
  432.   * the file we are about to start streaming.
  433.   *
  434.   * ALL streaming MCD's should take advantage
  435.   * of this MMIO api.
  436.   *****************************************/
  437.  
  438.   ulrc = BeginQualityofService( ulpInstance, STREAM_WRITE );
  439.  
  440.   /*-----------------------------------------
  441.   * If there is not a network io proc, we will
  442.   * receive unsupported message.  In this case
  443.   * we will ignore the error.
  444.   *
  445.   * If there is a network io proc we may have
  446.   * to examine the error a little more carefully
  447.   *--------------------------------------------*/
  448.  
  449.   if ( ulrc && ulrc != MMIOERR_UNSUPPORTED_MESSAGE )
  450.      {
  451.      /*--------------------------------------------
  452.      * At open time, we retrieved a variable called
  453.      * MSV_SYSQOSERRORFLAG which indicates if the
  454.      * user wants to be notified if the streaming
  455.      * operation will not be possible. It can
  456.      * have the following values:
  457.      *
  458.      * A. ERROR_REPORT (report all errors).
  459.      * B. ERROR_IGNORE (ignore all errors).
  460.      *---------------------------------------------*/
  461.  
  462.      if ( ulpInstance->lQOSReporting == ERROR_REPORT )
  463.         {
  464.         /* Tell the caller of the network bandwidth problem */
  465.  
  466.         return ( ulrc );
  467.         }
  468.      } /* If there was a problem setting up network support */
  469.  
  470.  
  471.   /************************************
  472.   * Enable Position Advise if Needed
  473.   *************************************/
  474.  
  475.  
  476.   ulrc = EnableEvents( ulpInstance );
  477.  
  478.  
  479.  
  480.   if (!ulrc)
  481.        /************************************************
  482.        ** To determine whether or not an operation must be
  483.        ** done on a thread, use the following criteria:
  484.        **
  485.        **   A. Will the operation take a long time.
  486.        **   B. Is there any way to make it appear as if
  487.        **      a thread was active.
  488.        **
  489.        ** We could do an spiStart, receive the event
  490.        ** in our event proc and clean up on the SSM
  491.        ** thread.  However, this thread will be a HIGH
  492.        ** PRIORITY thread and we have too much processing
  493.        ** to do.  Therefore, there is no way to fake it.
  494.        ** Thus we must create a record thread if the notify
  495.        ** flag is sent
  496.        ************************************************/
  497.  
  498.       if (ulParam1 & MCI_NOTIFY)
  499.          {
  500.          ulpInstance->usNotifyPending = TRUE;
  501.          ulpInstance->usNotPendingMsg = MCI_RECORD;
  502.  
  503.          DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
  504.  
  505.           /****************************************************
  506.           * This thread is kicked off by the MCD mainly
  507.           * to start the stream. When it is safe to continue
  508.           * the play thread will post the thread semaphore and
  509.           * this thread can continue.
  510.           ****************************************************/
  511.  
  512.           rc = _beginthread ( (PFNTHREAD) StartRecord,
  513.                                  0,
  514.                                  NOTIFY_THREAD_STACKSIZE,
  515.                                  (ULONG) pFuncBlock );
  516.  
  517.          /*************************************************
  518.          * Wait for the record thread to indicate that it
  519.          * is safe to continue.
  520.          **************************************************/
  521.  
  522.            if ( rc != -1 )
  523.               {
  524.               DosWaitEventSem (ulpInstance->hThreadSem, -1);
  525.               }
  526.            else
  527.               {
  528.               /****************************************
  529.               * Tell the network that we are done
  530.               * streaming since an error occurred
  531.               *****************************************/
  532.  
  533.               EndQualityofService( ulpInstance );
  534.  
  535.               ulrc = MCIERR_OUT_OF_MEMORY;
  536.               }
  537.  
  538.  
  539.          if ( rc > 0 )
  540.             {
  541.             DosWaitEventSem (ulpInstance->hThreadSem, -1);
  542.             }
  543.          }
  544.  
  545.       else
  546.          {
  547.          ulpInstance->usWaitPending = TRUE;
  548.          ulpInstance->usWaitMsg= MCI_RECORD;
  549.  
  550.          /************************************************
  551.          * Start record.  This function will kick
  552.          * off the record, get an event (i.e. stream
  553.          * complete, stopped etc.) and report the return
  554.          * code.  We will return this return code to the
  555.          * caller.
  556.          ************************************************/
  557.  
  558.  
  559.          ulrc = StartRecord (pFuncBlock);
  560.  
  561.          } /* MCI_WAIT flag was used */
  562.  
  563.   /**********************************
  564.   * Release data Access Semaphore
  565.   ***********************************/
  566.  
  567.    DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
  568.  
  569.   return (ulrc);
  570. }
  571.  
  572.  
  573.  
  574. /********************* START OF SPECIFICATIONS *********************
  575. *
  576. * SUBROUTINE NAME: EventProc.
  577. *
  578. * DESCRIPTIVE NAME: SSM Event Handler
  579. *
  580. * FUNCTION:  Handle Streaming Event Notifications from SSM.
  581. *
  582. * NOTES: This routine is presumed to receive all types of event
  583. *        notifications from the SSM. The types include Implicit
  584. *        events, Cue point notifications in terms of both time
  585. *        and data. In response to Cue point notifications an
  586. *        MCI_CUEPOINT message is returned to MDM via mdmDriverNotify ()
  587. *
  588. * ENTRY POINTS:
  589. *
  590. * INPUT:
  591. *
  592. * EXIT-NORMAL: Return Code 0.
  593. *
  594. * EXIT_ERROR:  Error Code and flError flag is set.
  595. *
  596. * EFFECTS:
  597. *
  598. * INTERNAL REFERENCES:
  599. *
  600. * EXTERNAL REFERENCES: mdmDriverNotify ()  - MDM   API
  601. *
  602. *********************** END OF SPECIFICATIONS **********************/
  603. RC APIENTRY RecordEventRoutine ( MEVCB  *pevcb)
  604. {
  605.   MTIME_EVCB        *pMTimeEVCB;    // Modified EVCB
  606.   INSTANCE          *ulpInstance;   // Instance Ptr
  607.  
  608.   /***********************************************************
  609.   * EventProc receives asynchronous SSM event notifications
  610.   * When the event is received, the event semaphore is posted
  611.   * which will wake up the MCD thread(s) blocked on this
  612.   * semaphore.
  613.   * The semaphore is not posted for time events like
  614.   * cuepoint (TIME) and media position changes since they do
  615.   * not alter the state of the stream.
  616.   ************************************************************/
  617.  
  618.  
  619.   switch (pevcb->evcb.ulType)
  620.   {
  621.   case EVENT_IMPLICIT_TYPE:
  622.  
  623.        /* Retrieve our instance from the EVCB */
  624.  
  625.        ulpInstance = (INSTANCE *)pevcb->ulpInstance;
  626.  
  627.        switch (pevcb->evcb.ulSubType)
  628.        {
  629.        case EVENT_ERROR:
  630.             ulpInstance->StreamEvent = EVENT_ERROR;
  631.  
  632.             /****************************************
  633.             * Check for playlist specific error first
  634.             *****************************************/
  635.  
  636.             /**************************************
  637.             * End of PlayList event is received
  638.             * as an implicit error event. It
  639.             * is treated as a normal EOS
  640.             ***************************************/
  641.             if (ulpInstance->usPlayLstStrm == TRUE)
  642.                 if (pevcb->evcb.ulStatus == ERROR_END_OF_PLAYLIST)
  643.                     ulpInstance->StreamInfo.Evcb.evcb.ulStatus = MMIOERR_CANNOTWRITE;
  644.  
  645.             DosPostEventSem (ulpInstance->hEventSem);
  646.            break;
  647.  
  648.        case EVENT_STREAM_STOPPED:
  649.             /****************************************
  650.             * Event Stream Stopped. Release the
  651.             * Blocked thread
  652.             *****************************************/
  653.             ulpInstance->StreamEvent = EVENT_STREAM_STOPPED;
  654.             DosPostEventSem (ulpInstance->hEventSem);
  655.            break;
  656.  
  657.        case EVENT_SYNC_PREROLLED:
  658.             /******************************************
  659.             * This event is received in reponse to a
  660.             * preroll start. A Preroll start is done
  661.             * on an MCI_CUE message.
  662.             *******************************************/
  663.             ulpInstance->StreamEvent = EVENT_SYNC_PREROLLED;
  664.             DosPostEventSem (ulpInstance->hEventSem);
  665.            break;
  666.  
  667.        case EVENT_PLAYLISTMESSAGE:
  668.             /******************************************
  669.             * We can receive this event if a playlist
  670.             * parser hits the MESSAGE COMMAND.
  671.             * NOTE: The MCD should return this message
  672.             * with the callback handle specified on the
  673.             * open.  This could be the source of much
  674.             * grief if you return on the wrong handle.
  675.             ******************************************/
  676.  
  677.             mdmDriverNotify ( ulpInstance->usWaveDeviceID,
  678.                               ulpInstance->hwndOpenCallBack,
  679.                               MM_MCIPLAYLISTMESSAGE,
  680.                               (USHORT) MAKEULONG(pevcb->evcb.ulStatus,
  681.                                                  ulpInstance->usWaveDeviceID),
  682.                               (ULONG)pevcb->evcb.unused1);
  683.  
  684.  
  685.            break;
  686. // why don't we support playlist cuepoints on record--investigate
  687.  
  688.        } /* SubType case of Implicit Events */
  689.       break;
  690.  
  691.   case EVENT_CUE_TIME_PAUSE:
  692.        /***************************************************
  693.        * This event will arrive if we recorded to a certain
  694.        * position in the stream.  Let the play thread know
  695.        * that we have reached the desired point.
  696.        ****************************************************/
  697.  
  698.       pMTimeEVCB = (MTIME_EVCB *)pevcb;
  699.       ulpInstance = (INSTANCE *)pMTimeEVCB->ulpInstance;
  700.       ulpInstance->StreamEvent = EVENT_CUE_TIME_PAUSE;
  701.  
  702.       DosPostEventSem (ulpInstance->hEventSem);
  703.       break;
  704.   case EVENT_CUE_TIME:
  705.  
  706.        /*************************************************
  707.        * Single Events are Treated as Time Cue Points
  708.        * Note: the caller is required to have a callback
  709.        * specifically for this purpose which we stored in
  710.        * our Time Event Control Block (EVCB).  See the
  711.        * ADMCCUE.C file for more information on how to
  712.        * manipulate your own EVCB and why you would want to
  713.        **************************************************/
  714.  
  715.        pMTimeEVCB = (MTIME_EVCB *)pevcb;
  716.        ulpInstance = (INSTANCE *)pMTimeEVCB->ulpInstance;
  717.  
  718.       if ( pMTimeEVCB->evcb.ulFlags == EVENT_SINGLE )
  719.          {
  720.          mdmDriverNotify ( ulpInstance->usWaveDeviceID,
  721.                            pMTimeEVCB->hwndCallback,
  722.                            MM_MCICUEPOINT,
  723.                            (USHORT) pMTimeEVCB->usCueUsrParm,
  724.                            (ULONG) pMTimeEVCB->evcb.mmtimeStream);
  725.          }
  726.  
  727.        /************************************************
  728.        * Recurring events equate to position advise events
  729.        * or media changed events.
  730.        *
  731.        * Note: the caller is required to have a callback
  732.        * specifically for this purpose which we stored in
  733.        * our Time Event Control Block (EVCB).  See the
  734.        * ADMCCUE.C file for more information on how to
  735.        * manipulate your own EVCB and why you would want to
  736.        **************************************************/
  737.  
  738.       if ( pMTimeEVCB->evcb.ulFlags == EVENT_RECURRING )
  739.          {
  740.          mdmDriverNotify ( ulpInstance->usWaveDeviceID,
  741.                            ulpInstance->StreamInfo.PosAdvEvcb.hwndCallback,
  742.                            MM_MCIPOSITIONCHANGE,
  743.                            (USHORT) ulpInstance->usPosUserParm,
  744.                            (ULONG)  pMTimeEVCB->evcb.mmtimeStream);
  745.          }
  746.  
  747.  
  748.       break;
  749.  
  750.   default:
  751.       break;
  752.  
  753.   }  /* All Events case */
  754.  
  755.   return (MCIERR_SUCCESS);
  756.  
  757. }              /* of Event Handler */
  758.  
  759.  
  760.  
  761.  
  762.  
  763. /********************* START OF SPECIFICATIONS *******************************
  764. *
  765. * SUBROUTINE NAME: StartRecord.
  766. *
  767. * DESCRIPTIVE NAME:StartRecording
  768. *
  769. * FUNCTION: SpiStartStream().
  770. *
  771. *
  772. * ENTRY POINTS:
  773. *
  774. * NOTES: This routine is called using caller' thread (MCI_WAIT)
  775. *        or a separate thread spawned by MCD on MCI Notify.  Once the stream
  776. *        is started, the event procedure above is called by SSM on a
  777. *        high priority thread.  The event procedure will post a semaphore
  778. *        awaking this function.
  779. *
  780. *        When a streaming operation is interuptted (usually by a stop)
  781. *        the interuptting thread waits for the MCDs thread to complete
  782. *        its remaing tasks. This wait is controlled via the instance based
  783. *        thread semaphore.
  784. *
  785. *        Further, on a notify the Record Notify command does not return
  786. *        until the newly created thread is ready to block itself. This
  787. *        ensures that any other MCI messages are free to be processed
  788. *        following the MCI_RECORD message operate on a running stream.
  789. *        This also means there is minimum latency between the return of the
  790. *        Record command to the application and start of audible sound.
  791. *
  792. * INPUT:
  793. *
  794. * EXIT-NORMAL: Return Code 0.
  795. *
  796. * EXIT_ERROR:  Error Code.
  797. *
  798. * EFFECTS:
  799. *
  800. * INTERNAL REFERENCES: None
  801. *
  802. * EXTERNAL REFERENCES: None
  803. *
  804. *********************** END OF SPECIFICATIONS *******************************/
  805. RC StartRecord (FUNCTION_PARM_BLOCK *pFuncBlockCopy )
  806. {
  807.   ULONG         ulrc;
  808.   ULONG         ulCnt;
  809.   ULONG         ulParam1;
  810.   ULONG         ulErr;
  811.   ULONG         ulRecdToNotify;
  812.   INSTANCE      *ulpInstance;
  813.  
  814.   FUNCTION_PARM_BLOCK  FuncBlock;
  815.  
  816.   BOOL          fPostMessage;      // should we inform the caller?
  817.  
  818.   memmove( &FuncBlock, pFuncBlockCopy, sizeof( FUNCTION_PARM_BLOCK ) );
  819.  
  820.    ulErr = MCI_NOTIFY_SUCCESSFUL;
  821.    ulpInstance = (INSTANCE *) FuncBlock.ulpInstance;
  822.    ulParam1 = FuncBlock.ulParam1;
  823.    fPostMessage = TRUE;
  824.  
  825.  
  826.   /**************************************
  827.   * Reset the event semaphore used by the
  828.   * RecordEventProc.  See comments below.
  829.   ****************************************/
  830.  
  831.    DosResetEventSem (ulpInstance->hEventSem, &ulCnt);
  832.  
  833.    /* Update state to reflect the flact we are playing */
  834.  
  835.    ulpInstance->StreamInfo.ulState = MCI_RECORD;
  836.  
  837.  
  838.   /****************************************
  839.   * Set a flag so we can sense when someone
  840.   * issues an aborted or superceded request
  841.   *****************************************/
  842.  
  843.   ulpInstance->ulNotifyAborted = FALSE;
  844.  
  845.  
  846.  
  847.    /***********************
  848.    * Start the stream
  849.    ************************/
  850.    ulrc = SpiStartStream (ulpInstance->StreamInfo.hStream, SPI_START_STREAM);
  851.  
  852.   /*****************************************
  853.   * If this is a notify thread, let the
  854.   * caller know it is ok to continue
  855.   *****************************************/
  856.  
  857.   if (ulParam1 & MCI_NOTIFY)
  858.      {
  859.      FuncBlock.pInstance->usUserParm = FuncBlock.usUserParm;
  860.      DosPostEventSem (ulpInstance->hThreadSem);
  861.      }
  862.  
  863.   /***********************************************
  864.   * It is VERY important to check the error code
  865.   * from the SpiStartStream before waiting on an
  866.   * event from it.  If an error is returned and
  867.   * we wait on an event from the event proc, we
  868.   * will hang since an event will never come.
  869.   ***********************************************/
  870.  
  871.    if ( !ulrc )
  872.       {
  873.       /**********************************************
  874.       * Block this thread until an event happens in
  875.       * the stream.  When it does, the PlayEventProc
  876.       * will signal us via this semaphore.
  877.       **********************************************/
  878.  
  879.       DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  880.  
  881.       /*******************************************************
  882.       * Acquire semaphore which will prevent any thread from
  883.       * aborting us.  Once we have this semaphore, enter a
  884.       * critical section, update some key instance variables
  885.       * and get out quickly.
  886.       *******************************************************/
  887.  
  888.       DosRequestMutexSem( ulpInstance->hmtxNotifyAccess, -1 );
  889.     
  890.       /**********************************************
  891.       * Let any other thread know that there no
  892.       * longer is a command active which can be
  893.       * aborted.  We are in the clean up stage now
  894.       * and once we exit the critical section, other
  895.       * commands can safely operate.
  896.       ***********************************************/
  897.     
  898.       if (ulpInstance->usNotifyPending == TRUE)
  899.           ulpInstance->usNotifyPending =FALSE;
  900.     
  901.       /**************************************
  902.       * Ensure that if we are being aborted
  903.       * by another thread, and we received
  904.       * an event that we ignore the event
  905.       * and let the other process post the
  906.       * notify
  907.       **************************************/
  908.     
  909.       if (ulpInstance->ulNotifyAborted == TRUE)
  910.          {
  911.          fPostMessage = FALSE;
  912.          }
  913.  
  914.       /************************************************
  915.       * We have set up the event proc to give us the
  916.       * more detailed error in ulStatus if an EVENT
  917.       * ERROR is returned.
  918.       *************************************************/
  919.  
  920.       else if (ulpInstance->StreamEvent == EVENT_ERROR)
  921.         {
  922.         ulErr = ulpInstance->StreamInfo.Evcb.evcb.ulStatus;
  923.  
  924.         if (ulErr == MMIOERR_CANNOTWRITE)
  925.            {
  926.            ulErr = MCIERR_TARGET_DEVICE_FULL;
  927.            }
  928.  
  929.         /***************************************************
  930.         * Just because we have received an event error, it
  931.         * does not mean that the stream is stopped.  If we
  932.         * tried to seek in the current stream state, BAD
  933.         * things will happen so stop the stream.
  934.         ***************************************************/
  935.  
  936.         DosResetEventSem (ulpInstance->hEventSem, &ulCnt);
  937.  
  938.         /* An error happened, therefore do a discard--we're toast anyway */
  939.  
  940.         ulrc = SpiStopStream (ulpInstance->StreamInfo.hStream, SPI_STOP_DISCARD );
  941.  
  942.         if (!ulrc)
  943.            {
  944.            DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  945.            }
  946.  
  947.          } /* if an event error happened */
  948.  
  949.       /************************************************
  950.       * Store the fact that we were doing a record to
  951.       * a certain point in the stream.  Other threads
  952.       * may overwrite this variable so keep its value
  953.       * while we are in the critical section.
  954.       ************************************************/
  955.  
  956.       if (ulpInstance->fToEvent == TRUE)
  957.          {
  958.          ulpInstance->fToEvent = FALSE;
  959.         
  960.          /*************************************************
  961.          * NOTE: it is very important that we disable this
  962.          * event since following commands could receive a
  963.          * bogus cuepoint when the stream by the to point.
  964.          **************************************************/
  965.         
  966.          ulrc = SpiDisableEvent(ulpInstance->StreamInfo.hPlayToEvent);
  967.         
  968.          DosResetEventSem (ulpInstance->hEventSem, &ulCnt);
  969.         
  970.          ulrc = SpiStopStream (ulpInstance->StreamInfo.hStream, SPI_STOP_FLUSH );
  971.         
  972.          if (!ulrc)
  973.             {
  974.             DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  975.             }
  976.         
  977.          } /* Were we recording to a certain point */
  978.  
  979.  
  980.       } /* if no error on starting a record */
  981.    else  /* an error occurred on starting the stream */
  982.       {
  983.       /**********************************
  984.       * Disable Notify Pending Flag
  985.       ***********************************/
  986.  
  987.       if (ulpInstance->usNotifyPending == TRUE)
  988.         ulpInstance->usNotifyPending =FALSE;
  989.  
  990.       /* Let the caller know things went VERY badly */
  991.  
  992.       if ( ulParam1 & MCI_NOTIFY )
  993.          {
  994.          PostMDMMessage (ulrc, MCI_RECORD, &FuncBlock);
  995.          }
  996.  
  997.       return ( ulrc );
  998.       }
  999.  
  1000.   /******************************************************
  1001.   * Fix for MMPM/2 AVC--they do repeated open\closes and after
  1002.   * approximately 80 closes, due to some OS/2 scheduling
  1003.   * quirk, close would free the instance before the thread
  1004.   * finished processing.  Therefore, require close to
  1005.   * acquire the exclusive semaphore before freeing
  1006.   * instance.
  1007.   ********************************************************/
  1008.  
  1009.   DosRequestMutexSem( ulpInstance->hmtxCloseAccess, -1 );
  1010.  
  1011.  
  1012.    /* Ensure the file contains the information we just recorded */
  1013.  
  1014.    ulrc = UpdateFileHeader( ulpInstance );
  1015.  
  1016.    if ( ulrc )
  1017.       {
  1018.       /*************************************************
  1019.       * If an error previously occurred, we do not want
  1020.       * to overwrite this error.
  1021.       **************************************************/
  1022.  
  1023.       ulErr = ulrc;
  1024.       }
  1025.  
  1026.  
  1027.   /********************************************
  1028.   * After a record, we always do a full-fledged
  1029.   * stop, so update the stream state.
  1030.   *********************************************/
  1031.   ulpInstance->StreamInfo.ulState = MCI_STOP;
  1032.  
  1033.  
  1034.   /****************************************
  1035.   * Tell the network that we are done
  1036.   * streaming.
  1037.   *****************************************/
  1038.  
  1039.   EndQualityofService( ulpInstance );
  1040.  
  1041.  
  1042.   /*------------------------------------------
  1043.   * Records can be un-done.  Update this fact
  1044.   * in our undo/redo level storage.
  1045.   *------------------------------------------*/
  1046.   AddNode( ulpInstance, 1 );
  1047.   ulpInstance->ulNumUndo++;
  1048.  
  1049.  
  1050.   /****************************************
  1051.   * Post The Notification only after
  1052.   * File is saved in case of To
  1053.   *****************************************/
  1054.  
  1055.   if (ulpInstance->usWaitPending == TRUE)
  1056.      {
  1057.      ulpInstance->usWaitPending = FALSE;
  1058.      DosReleaseMutexSem( ulpInstance->hmtxNotifyAccess );
  1059.      DosReleaseMutexSem( ulpInstance->hmtxCloseAccess );
  1060.  
  1061.      return (ulErr);
  1062.      }
  1063.  
  1064.  
  1065.    /****************************************************
  1066.    * Inform the caller of the state of the stream. The
  1067.    * only scenario where we do not do this is when
  1068.    * another command (such as MCI_STOP ) aborts the
  1069.    * record ( in which case it is responsible for
  1070.    * posting the message itself.
  1071.    *****************************************************/
  1072.  
  1073.     if ( fPostMessage )
  1074.          {
  1075.          /*******************************************
  1076.          * Post The Notification Message for Record
  1077.          ********************************************/
  1078.          PostMDMMessage (ulErr, MCI_RECORD, &FuncBlock);
  1079.          }
  1080.  
  1081.  
  1082.  
  1083.    /**************************************************
  1084.    * Post The Semaphore to clear any Blocked threads
  1085.    **************************************************/
  1086.    DosPostEventSem (ulpInstance->hThreadSem);
  1087.  
  1088.    /***************************************
  1089.    * Allow other threads in the process to
  1090.    * continue and release exlcusive notify
  1091.    * semaphore.
  1092.    ***************************************/
  1093.  
  1094.    DosReleaseMutexSem( ulpInstance->hmtxNotifyAccess );
  1095.  
  1096.    DosReleaseMutexSem( ulpInstance->hmtxCloseAccess );
  1097.  
  1098.    return ( MCIERR_SUCCESS );
  1099.  
  1100. } /* StartRecord */
  1101.  
  1102. /********************* START OF SPECIFICATIONS *******************************
  1103. *
  1104. * SUBROUTINE NAME: UpdateFileHeader.
  1105. *
  1106. * DESCRIPTIVE NAME:
  1107. *
  1108. * FUNCTION: Updates the file header after a record
  1109. *
  1110. *
  1111. * ENTRY POINTS:
  1112. *
  1113. * NOTES: This function is responsible for terminating the logical
  1114. *        record action and updating the file header.
  1115. *
  1116. * INPUT:
  1117. *
  1118. * EXIT-NORMAL: Return Code 0.
  1119. *
  1120. * EXIT_ERROR:  Error Code.
  1121. *
  1122. * EFFECTS:
  1123. *
  1124. * INTERNAL REFERENCES: None
  1125. *
  1126. * EXTERNAL REFERENCES: None
  1127. *
  1128. *********************** END OF SPECIFICATIONS *******************************/
  1129.  
  1130.  
  1131.  
  1132. ULONG UpdateFileHeader ( INSTANCE    *ulpInstance )
  1133.  
  1134. {
  1135. ULONG ulrc;
  1136. LONG  lBytesRead;
  1137.  
  1138.    /***************************************************
  1139.    * Unlike playback, record modifies the length of the
  1140.    * file and the data in it, therefore we MUST update
  1141.    * let the io proc know that the opeartion is done.
  1142.    *
  1143.    * Note: This does not apply to playlist since it
  1144.    * operates on buffers rather than files and mmio
  1145.    * operations are not allowed on playlists.
  1146.    ****************************************************/
  1147.  
  1148.    if ( ulpInstance->usPlayLstStrm != TRUE )
  1149.       {
  1150.       /************************************************
  1151.       * If the RECORD_INSERT flag was used, tell the
  1152.       * io proc we are done inserting
  1153.       ************************************************/
  1154.       if ( ulpInstance->fRecdInsert )
  1155.         {
  1156.  
  1157.         ulrc = mmioSendMessage( ulpInstance->hmmio,
  1158.                                 MMIOM_ENDINSERT,
  1159.                                 0,
  1160.                                 0);
  1161.  
  1162.         if (ulrc)
  1163.           {
  1164.           return ( mmioGetLastError( ulpInstance->hmmio ) );
  1165.           }
  1166.  
  1167.         /***************************************
  1168.         * Ensure that it no other record inserts
  1169.         * will be done unless specified
  1170.         ****************************************/
  1171.  
  1172.         ulpInstance->fRecdInsert = FALSE;
  1173.  
  1174.         }
  1175.       else
  1176.  
  1177.       /************************************************
  1178.       * Tell the io proc that the logical record is
  1179.       * complete.  This will allow the record to be
  1180.       * undone or redone.
  1181.       ***********************************************/
  1182.  
  1183.         {
  1184.         ulrc = mmioSendMessage( ulpInstance->hmmio,
  1185.                                 MMIOM_ENDGROUP,
  1186.                                 0,
  1187.                                 0);
  1188.  
  1189.         if (ulrc)
  1190.           {
  1191.           return ( mmioGetLastError( ulpInstance->hmmio ) );
  1192.           }
  1193.  
  1194.         }  /* else we are not inserting */
  1195.  
  1196.  
  1197.       /***************************************************
  1198.       * Unlike playback, record modifies the length of the
  1199.       * file and the data in it, therefore we MUST update
  1200.       * the header.
  1201.       ****************************************************/
  1202.  
  1203.       if ( ulrc = SetAudioHeader( ulpInstance ) )
  1204.          {
  1205.          return ( ulrc );
  1206.          }
  1207.  
  1208.  
  1209.       /***********************************************
  1210.       * The io proc will update the size of the file
  1211.       * after we do a setheader, so do a getheader to
  1212.       * figure out what the new size of the file is
  1213.       ************************************************/
  1214.       ulrc = mmioGetHeader ( ulpInstance->hmmio,
  1215.                              (PVOID) &(ulpInstance->mmAudioHeader),
  1216.                              sizeof( MMAUDIOHEADER ),
  1217.                              &lBytesRead,
  1218.                              (ULONG) NULL,
  1219.                              (ULONG) NULL );
  1220.  
  1221.       if (ulrc != MMIO_SUCCESS )
  1222.          {
  1223.          return ( mmioGetLastError( ulpInstance->hmmio ) );
  1224.          }
  1225.  
  1226.       /* update our header size */
  1227.  
  1228.       ulpInstance->ulDataSize = XWAVHDR.ulAudioLengthInBytes;
  1229.  
  1230.       } /* update header if !playlist stream */
  1231.  
  1232.     return ( MCIERR_SUCCESS );
  1233.  
  1234. } /* UpdateFileHeader */
  1235.  
  1236.  
  1237.  
  1238. /********************* START OF SPECIFICATIONS *******************************
  1239. *
  1240. * SUBROUTINE NAME: CheckRecordFlags
  1241. *
  1242. * DESCRIPTIVE NAME: Process Error Conditions for  Record
  1243. *
  1244. * FUNCTION: Report Errors, Do PreProcessing for MCI Record
  1245. *
  1246. *
  1247. * ENTRY POINTS:
  1248. *
  1249. * NOTE: All MCI Functions should check to ensure that the flags are
  1250. *       valid before interrupting a previous operation.  This means
  1251. *       that if the caller supplied bad flags while a play was
  1252. *       operating, the play would not be interrupted.
  1253. *
  1254. * EXIT-NORMAL: MCIERR_SUCCESS.
  1255. *
  1256. * EXIT_ERROR:  Error Code.
  1257. *
  1258. * EFFECTS:
  1259. *
  1260. * INTERNAL REFERENCES: WaveIOPROC.
  1261. *
  1262. * EXTERNAL REFERENCES: DosQueryProcAddr - OS/2 API.
  1263. *
  1264. *********************** END OF SPECIFICATIONS *******************************/
  1265.  
  1266. RC CheckRecordFlags( FUNCTION_PARM_BLOCK *pFuncBlock )
  1267.  
  1268. {
  1269.  
  1270.   ULONG                ulrc;                  // RC
  1271.   ULONG                ulParam1;              // Incoming MCI Flags
  1272.  
  1273.   INSTANCE             *ulpInstance;          // Local Instance
  1274.  
  1275.   ULONG                ulRecordFlags;         // Mask for MCI Record
  1276.   ULONG                ulMMFileLength;        // Length of the File in MMTIME
  1277.   ULONG                ulTemp1;               // Scratch For Time Conversion
  1278.   ULONG                ulTempTO = 0;          // Scratch for Play Till
  1279.   ULONG                ulFromPosition = 0;    // holds where we will play from
  1280.  
  1281.   PMCI_RECORD_PARMS   pRecordParms;         // caller data struct
  1282.  
  1283.  
  1284.  
  1285.   /* Intialize local variables */
  1286.  
  1287.   ulParam1 = pFuncBlock->ulParam1;
  1288.   ulpInstance = (INSTANCE *)pFuncBlock->ulpInstance;
  1289.  
  1290.  
  1291.  
  1292.   ulRecordFlags = pFuncBlock->ulParam1;
  1293.  
  1294.   /****************************************
  1295.   * Mask out the flags we know about
  1296.   ****************************************/
  1297.  
  1298.   ulRecordFlags &= ~(MCI_FROM + MCI_TO + MCI_RECORD_INSERT +
  1299.                      MCI_RECORD_OVERWRITE + MCI_WAIT + MCI_NOTIFY);
  1300.  
  1301.   /* Return an error if there are any excess flags */
  1302.  
  1303.   if (ulRecordFlags > 0)
  1304.       return ( MCIERR_INVALID_FLAG );
  1305.  
  1306.   /***********************************************
  1307.   * Check for incompatible flags.
  1308.   ************************************************/
  1309.  
  1310.   if( (pFuncBlock->ulParam1 & MCI_RECORD_INSERT) &&
  1311.        (pFuncBlock->ulParam1 & MCI_RECORD_OVERWRITE))
  1312.  
  1313.         return ( MCIERR_FLAGS_NOT_COMPATIBLE );
  1314.  
  1315.   /************************************************
  1316.   * If neither overwrite or insert is specified,
  1317.   * then we will default to overwrite.
  1318.   * NOTE: this is in contrast to what the docs say
  1319.   * invesitigate.
  1320.   ************************************************/
  1321.  
  1322.   if (!(pFuncBlock->ulParam1 & MCI_RECORD_INSERT))
  1323.       pFuncBlock->ulParam1 |= MCI_RECORD_OVERWRITE;
  1324.  
  1325.   /***********************************************
  1326.   * If no element has been loaded, return an
  1327.   * error.
  1328.   ***********************************************/
  1329.  
  1330.   if ( !ulpInstance->fFileExists )
  1331.       return ( MCIERR_FILE_NOT_FOUND );
  1332.  
  1333.   /* The caller is required to pass record parms--ensure they are valid */
  1334.  
  1335.   pRecordParms= ( PMCI_RECORD_PARMS )pFuncBlock->ulParam2;
  1336.  
  1337.   ulrc = CheckMem ( (PVOID) pRecordParms,
  1338.                     sizeof (MCI_RECORD_PARMS), PAG_READ);
  1339.  
  1340.  
  1341.   if (ulrc != MCIERR_SUCCESS)
  1342.      {
  1343.      return MCIERR_MISSING_PARAMETER;
  1344.      }
  1345.  
  1346.   /******************************************
  1347.   * If the io proc that we are currently
  1348.   * using does not support writing, return
  1349.   * an error (OpenFile shows how to determine
  1350.   * these capabilities).
  1351.   *******************************************/
  1352.  
  1353.   if ( ( !( ulpInstance->ulCapabilities & CAN_RECORD )  &&
  1354.          !ulpInstance->usPlayLstStrm ) || 
  1355.          !AMPMIX.ulCanRecord )
  1356.      {
  1357.      return ( MCIERR_UNSUPPORTED_FUNCTION );
  1358.      }
  1359.  
  1360.   if ( ulpInstance->usPlayLstStrm )
  1361.      {
  1362.      return ( MCIERR_SUCCESS );
  1363.      }
  1364.  
  1365.  
  1366.   ConvertTimeUnits ( ulpInstance,
  1367.                      &ulMMFileLength,
  1368.                      FILE_LENGTH);
  1369.  
  1370.   ulTemp1 = ulMMFileLength;
  1371.  
  1372.   /* what is this statement for? */
  1373.  
  1374.   ConvertToMM( ulpInstance, &ulMMFileLength, ulMMFileLength );
  1375.  
  1376.  
  1377.    /***********************************************
  1378.    * Unlike play processing, checking to see if
  1379.    * MCI_FROM on a record is valid is easy,
  1380.    * one just has to check to see if the FROM is
  1381.    * a valid position in the file.
  1382.    ***********************************************/
  1383.  
  1384.    if (ulParam1 & MCI_FROM)
  1385.       {
  1386.       /*********************************************
  1387.       * We cannot start recording from a position
  1388.       * which is greater than the length of the
  1389.       * file.
  1390.       *********************************************/
  1391.       // add code to avoid playlist problems.
  1392.  
  1393.       if ( pRecordParms->ulFrom > ulTemp1 )
  1394.         {
  1395.         return ( MCIERR_OUTOFRANGE );
  1396.         }
  1397.  
  1398.       /***********************************************
  1399.       * The record will start from the from position
  1400.       * If MCI_FROM is not specified, then the routines
  1401.       * below will assume the current file position for
  1402.       * the from.  Either way, convert the from position
  1403.       * to MM time and store it.
  1404.       ************************************************/
  1405.  
  1406.       ulrc = ConvertToMM ( ulpInstance,
  1407.                            (ULONG*) &ulFromPosition,
  1408.                            pRecordParms->ulFrom );
  1409.  
  1410.       }  /* Record From */
  1411.  
  1412.    /*****************************************************
  1413.    * If the MCI_TO flag is specified on a record, then
  1414.    * the following checks are required to ensure that
  1415.    * the to position is valid.
  1416.    *
  1417.    * A. The to position must be greater than 0.
  1418.    * B. If the from flag is specified, the to position
  1419.    *    must be greater than the from position.
  1420.    * C. If a stream has been created, then
  1421.    *    I. Ensure that the to position is not less than
  1422.    *       our current stream position.
  1423.    ******************************************************/
  1424.  
  1425.    if (ulParam1 & MCI_TO)
  1426.       {
  1427.       /* The to position must be greater than 0 */
  1428.  
  1429.       if ( pRecordParms->ulTo <= 0 )
  1430.         {
  1431.         return ( MCIERR_OUTOFRANGE );
  1432.         }
  1433.  
  1434.       if ( ulParam1 & MCI_FROM )
  1435.         {
  1436.  
  1437.         /* Recording behind the from position is illegal */
  1438.  
  1439.         if ( pRecordParms->ulTo <= pRecordParms->ulFrom )
  1440.            {
  1441.            return ( MCIERR_OUTOFRANGE );
  1442.            }
  1443.  
  1444.         } /* if the from flag specified */
  1445.  
  1446.       /* Check to see if a stream has been created */
  1447.  
  1448.       if ( ulpInstance->ulCreateFlag == PREROLL_STATE )
  1449.          {
  1450.  
  1451.          /**********************************************
  1452.          * Get the current stream time, it will be used
  1453.          * for range checking below.
  1454.          ***********************************************/
  1455.  
  1456.          ulrc = SpiGetTime( ulpInstance->StreamInfo.hStream,
  1457.                             ( PMMTIME ) &( ulpInstance->StreamInfo.mmStreamTime ) );
  1458.  
  1459.          if ( ulrc )
  1460.             {
  1461.             return ( ulrc );
  1462.             }
  1463.  
  1464.          /* Since the stream time is in mm time, convert the to point to MM time */
  1465.  
  1466.          ConvertToMM ( ulpInstance,
  1467.                        (ULONG*) &ulTempTO,
  1468.                        pRecordParms->ulTo );
  1469.  
  1470.          /*********************************************************
  1471.          * The documentation states that the record will start from
  1472.          * either the current position or the from point.
  1473.          * If the from flag was not passed in, then set the
  1474.          * from position to be equivalent to our current position
  1475.          * for simplicity purposes.
  1476.          * Note: ulFromPosition was filled in the from processing
  1477.          ********************************************************/
  1478.  
  1479.          if ( ulFromPosition == 0 &&
  1480.               !(ulParam1 & MCI_FROM ) )
  1481.             {
  1482.             ulFromPosition = ( ULONG ) ulpInstance->StreamInfo.mmStreamTime;
  1483.             }
  1484.  
  1485.          if ( ulTempTO <= ulpInstance->StreamInfo.mmStreamTime &&
  1486.               ulTempTO <= ulFromPosition         )
  1487.             {
  1488.  
  1489.             /********************************************************
  1490.             * it is possible that we had rounding problems so ensure
  1491.             * that user did indeed pass in an illegal value
  1492.             ********************************************************/
  1493.             if ( ( ulParam1 & MCI_FROM ) &&
  1494.                  !(pRecordParms->ulTo <= pRecordParms->ulFrom ) )
  1495.                {
  1496.  
  1497.                }
  1498.             else
  1499.                {
  1500.                return ( MCIERR_OUTOFRANGE );
  1501.                }
  1502.             }
  1503.  
  1504.          } /* if stream has been created */
  1505.  
  1506.       } /* MCI_TO was specified */
  1507.  
  1508.    /*******************************************************
  1509.    * Playlists to not support the record insert message to
  1510.    * io procs--so don't do it.
  1511.    *******************************************************/
  1512.  
  1513.    if (pFuncBlock->ulParam1 & MCI_RECORD_INSERT)
  1514.       {
  1515.       ulpInstance->fRecdInsert = TRUE;
  1516.       }   /* Insert Specified */
  1517.  
  1518.   return (MCIERR_SUCCESS);
  1519.  
  1520. } /* Check Record Flags */
  1521.  
  1522.  
  1523.