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

  1. /********************* START OF SPECIFICATIONS *********************
  2. *
  3. * SUBROUTINE NAME: admccue.c
  4. *
  5. *
  6. *
  7. *              Copyright (c) IBM Corporation  1991, 1993
  8. *                        All Rights Reserved
  9. *
  10. * DESCRIPTIVE NAME: Audio MCD WaveAudio cueing + event file
  11. *
  12. * FUNCTION:Cue an Waveform Audio Element for input or output
  13. *          Set a cue point
  14. *
  15. * On an MCI_CUE, a streaming MCD should perform the following actions:
  16. *
  17. *  Check flags and validate pointers.
  18. *  Check to see if the stream is already in cue state.  If it is, then
  19. *   just return success.
  20. *  If the caller wants to cue for output, execute the following:
  21. *
  22. *  Stop any in process commands.
  23. *  If the stream is going in the wrong direction (i.e. record), destroy it.
  24. *  Create the stream if necessary.
  25. *  Preroll start the stream.
  26. *
  27. *  If the caller wants to cue for input, execute the following:
  28. *
  29. *  Stop any in process commands.
  30. *  If the stream is going in the wrong direction, destroy it.
  31. *  Create the stream if necessary.
  32. *  Preroll start the stream.
  33. *
  34. *
  35. * NOTES: Concepts illustrated in this source file.
  36. *         A. Default flags for MCI_CUE processing.
  37. *         B. When cueing is not necessary.
  38. *         C. When to destroy a stream before a cue.
  39. *         D. Why an MCI_SET before MCI_CUE requires stream
  40. *            creation.
  41. *         E. How to cue a stream for input or output.
  42. *         F. How to create a cue point.
  43. *         G. How/when to disable a cue point.
  44. *
  45. * ENTRY POINTS:
  46. *
  47. * INPUT:
  48. *
  49. *
  50. *
  51. * EXIT-NORMAL: Return Code 0.
  52. *
  53. * EXIT_ERROR:  Error Code.
  54. *
  55. * EFFECTS:
  56. *
  57. *********************** END OF SPECIFICATIONS **********************/
  58.  
  59. #define INCL_DOSSEMAPHORES
  60. #define INCL_DOSPROCESS
  61. #define INCL_ERRORS
  62.  
  63. #include <os2.h>                        // OS2 defines.
  64. #include <string.h>                     // String functions.
  65. #include <os2medef.h>                   // MME includes files.
  66. #include <audio.h>                      // Audio Device Defines.
  67. #include <ssm.h>                        // SSM spi includes.
  68. #include <meerror.h>                    // MM Error Messages.
  69. #include <mmioos2.h>                    // MMIO Include.
  70. #include <mcios2.h>                     // MM System Include.
  71. #include <mmdrvos2.h>                   // MCI Driver Include.
  72. #include <mcd.h>                        // AudioIFDriverInterface.
  73. #include <hhpheap.h>                    // Heap Manager Definitions
  74. #include <qos.h>
  75. #include <audiomcd.h>                   // Component Definitions
  76. #include "admcfunc.h"                   // Function Prototypes
  77.  
  78.  
  79.  
  80. /********************* START OF SPECIFICATIONS *********************
  81. *
  82. * SUBROUTINE NAME: MCICUE..C
  83. *
  84. * DESCRIPTIVE NAME: Cue Waveform Device.
  85. *
  86. * FUNCTION: Prepare a Waveform Device or an Device Element for Record/Playback.
  87. *           Applications will usually call this function in order to reduce
  88. *           the latency of an MCI_RECORD or MCI_PLAY
  89. *
  90. * NOTES: Cueing a Waveform Device translates to prerolling of streams
  91. *        at the SSM level.
  92. *        Preroll means source handler fills the buffers and is
  93. *        to roll. The Target handlers are not started, meaning buffers are
  94. *        are not consumed.
  95. *
  96. * ENTRY POINTS:
  97. *
  98. * INPUT: MCI_CUE message.
  99. *
  100. * EXIT-NORMAL: Return Code 0.
  101. *
  102. * EXIT_ERROR:  Error Code.
  103. *
  104. * EFFECTS:
  105. *
  106. * INTERNAL REFERENCES:
  107. *
  108. * EXTERNAL REFERENCES: AudioIFDriverEntry()       - AudioDevice MCD
  109. *
  110. *********************** END OF SPECIFICATIONS **********************/
  111. RC MCICue (FUNCTION_PARM_BLOCK *pFuncBlock)
  112. {
  113.   ULONG          ulrc;                 // Error Value
  114.   ULONG          ulParam1;             // Msg Flags
  115.  
  116.   BOOL           fCueInput = FALSE;    // Direction to cue
  117.   BOOL           fCueOutput = FALSE;   // "     "       "
  118.  
  119.   INSTANCE *     ulpInstance;          // Local Instance
  120.   ULONG          ulCueFlags;           // Mask For Incoming MCI Flags
  121.  
  122.   PMCI_GENERIC_PARMS pCueParms;     // Msg data ptr
  123.  
  124.   MCI_AMP_INSTANCE     BackupAmp;           // Hold old amp values
  125.  
  126.  
  127.  
  128.   /******************************
  129.   * Derefernce pointers.
  130.   ******************************/
  131.   ulParam1   =    pFuncBlock->ulParam1;
  132.   pCueParms = ( PMCI_GENERIC_PARMS ) pFuncBlock->ulParam2;
  133.   ulpInstance= (INSTANCE *) pFuncBlock->ulpInstance;
  134.  
  135.  
  136.   /*---------------------------------------------------------
  137.   * Make a copy of the amp/mixer instance in case any errors
  138.   * happened.
  139.   *---------------------------------------------------------*/
  140.  
  141.   memmove( &BackupAmp, &MIX, sizeof( MCI_AMP_INSTANCE ) );
  142.  
  143.  
  144.   /******************************
  145.   * Check for Invalid Flags
  146.   *******************************/
  147.   ulCueFlags = ulParam1;
  148.   ulCueFlags &= ~(MCI_NOTIFY     + MCI_WAIT +
  149.                   MCI_CUE_INPUT  + MCI_CUE_OUTPUT +
  150.                   MCI_WAVE_INPUT + MCI_WAVE_OUTPUT);
  151.  
  152.   /********************************************
  153.   * If the caller passed any flags other
  154.   * than the ones we masked out, return error
  155.   ********************************************/
  156.  
  157.   if (ulCueFlags > 0)
  158.       return ( MCIERR_INVALID_FLAG );
  159.  
  160.   /************************************************
  161.   * Cue point parms are not required, however, if
  162.   * they are there, ensure they are valid
  163.   ************************************************/
  164.   /*why do we check them then???????*/
  165.  
  166.   ulrc = CheckMem (((PVOID)pCueParms),
  167.                    sizeof (MCI_GENERIC_PARMS), PAG_READ);
  168.  
  169.   /******************************************
  170.   * Check for incompatible flags
  171.   *******************************************/
  172.   if (((ulParam1 & MCI_WAVE_INPUT)  || (ulParam1 & MCI_CUE_INPUT)) &&
  173.       ((ulParam1 & MCI_WAVE_OUTPUT) || (ulParam1 & MCI_CUE_OUTPUT)))
  174.  
  175.       return (MCIERR_FLAGS_NOT_COMPATIBLE );
  176.  
  177.   /****************************************
  178.   * If No Element return error
  179.   *****************************************/
  180.  
  181.   if ( ulpInstance->fFileExists == FALSE )
  182.      {
  183.      return (MCIERR_FILE_NOT_FOUND);
  184.      }
  185.  
  186.   /******************************************
  187.   * If we do not have the ability to write then
  188.   * cueing for input will be possible.
  189.   *******************************************/
  190.  
  191.   if ( ( (ulParam1 & MCI_WAVE_INPUT) || (ulParam1 & MCI_CUE_INPUT) ) &&
  192.        !ulpInstance->ulUsingTemp &&
  193.        !ulpInstance->usPlayLstStrm )
  194.     {
  195.     return ( MCIERR_UNSUPPORTED_FUNCTION );
  196.     }
  197.  
  198.   /******************************************
  199.   * Waveaudio defaults to cueing for output
  200.   * if no flags are passed.
  201.   *******************************************/
  202.  
  203.   if (!(ulParam1 & MCI_WAVE_INPUT || ulParam1 & MCI_WAVE_OUTPUT ||
  204.       ulParam1 & MCI_CUE_INPUT    || ulParam1 & MCI_CUE_OUTPUT))
  205.       {
  206.       ulParam1 &= MCI_WAVE_OUTPUT;
  207.  
  208.       }
  209.  
  210.   if ( ulParam1 & MCI_CUE_INPUT || ulParam1 & MCI_WAVE_INPUT )
  211.      {
  212.      fCueInput = TRUE;
  213.      }
  214.   else
  215.      {
  216.      fCueOutput = TRUE;
  217.      }
  218.  
  219.   /************************************
  220.   * If the stream is paused, there is no
  221.   * sense in cueing it since the buffers
  222.   * are full anyway
  223.   **************************************/
  224.  
  225.   if ( STRMSTATE == MCI_PAUSE  ||
  226.        STRMSTATE == STOP_PAUSED )
  227.  
  228.       {
  229.       /***********************************************
  230.       ** If the stream is going the right way
  231.       ** then we have the ability to avoid the cue
  232.       ** since the buffers have been filled up before
  233.       ** we did the pause
  234.       **********************************************/
  235.  
  236.       if ( AMPMIX.ulOperation == OPERATION_RECORD &&
  237.            fCueInput )
  238.          {
  239.          ulpInstance->ulCreateFlag = PREROLL_STATE;
  240.          STRMSTATE = CUERECD_STATE;
  241.          return ( MCIERR_SUCCESS );
  242.          }
  243.  
  244.       /*************************************************
  245.       * If the current stream is cued for playback and
  246.       * we have a cue_output request, our work is done
  247.       **************************************************/
  248.  
  249.       else if ( AMPMIX.ulOperation == OPERATION_PLAY &&
  250.                 fCueOutput )
  251.          {
  252.  
  253.          ulpInstance->ulCreateFlag = PREROLL_STATE;
  254.          STRMSTATE = CUEPLAY_STATE;
  255.          return ( MCIERR_SUCCESS );
  256.          }
  257.  
  258.       }   /* If the stream may be in cue state */
  259.  
  260.   /**********************************************
  261.   * Create and cue the playback stream A --> B
  262.   ***********************************************/
  263.  
  264.   if ( fCueOutput )
  265.      {
  266.       ulrc = CueSetup( pFuncBlock, MCI_PLAY );
  267.  
  268.       STRMSTATE = CUEPLAY_STATE;
  269.  
  270.      } /* default case is wave output */
  271.  
  272.   /********************************************
  273.   * If the caller requested a cue for input, then
  274.   * create and cue the record stream B --> A
  275.   *********************************************/
  276.  
  277.   else
  278.      {
  279.      ulrc = CueSetup( pFuncBlock, MCI_RECORD );
  280.  
  281.      STRMSTATE = CUERECD_STATE;
  282.  
  283.      }   /* Cue Input */
  284.  
  285.  
  286.   if ( ulrc )
  287.      {
  288.      /* Ensure that our instance remains the same as before the cue attempt */
  289.  
  290.      memmove( &MIX, &BackupAmp, sizeof ( MCI_AMP_INSTANCE ) );
  291.  
  292.      }
  293.  
  294.   return (ulrc);
  295. }
  296.  
  297.  
  298. /********************* START OF SPECIFICATIONS *********************
  299. *
  300. * SUBROUTINE NAME: CueSetup
  301. *
  302. * DESCRIPTIVE NAME: Creates a stream and cues it.
  303. *
  304. * FUNCTION: This function abort any in progress commands and
  305. *           cue a stream.
  306. *
  307. * NOTES:
  308. *
  309. * ENTRY POINTS:
  310. *
  311. * INPUT: INSTANCE ptr
  312. *
  313. * EXIT-NORMAL: Return Code 0.
  314. *
  315. * EXIT_ERROR:
  316. *
  317. * EFFECTS:
  318. *
  319. * INTERNAL REFERENCES: MCIERR ().
  320. *
  321. * EXTERNAL REFERENCES: spiCreateStream()
  322. *                      spiStartStream()
  323. *
  324. *********************** END OF SPECIFICATIONS **********************/
  325.  
  326. ULONG CueSetup( FUNCTION_PARM_BLOCK *pFuncBlock,
  327.                 ULONG               ulMCIOperation )
  328.  
  329. {
  330. ULONG        ulAbortNotify = FALSE;  // is there a command to abort?
  331. ULONG        ulAmpDestroy;
  332. ULONG        ulAmpOperation;
  333. ULONG        ulrc;
  334.  
  335. INSTANCE     *pInstance;
  336.  
  337.  
  338.    pInstance = (INSTANCE *) pFuncBlock->ulpInstance;
  339.  
  340.    if ( ulMCIOperation == MCI_RECORD )
  341.       {
  342.       ulAmpOperation = OPERATION_RECORD;
  343.       /* If the amp is in play mode, we must destroy the stream */
  344.       ulAmpDestroy   = OPERATION_PLAY;
  345.       }
  346.    else
  347.       {
  348.       ulAmpOperation = OPERATION_PLAY;
  349.       /* If the amp is in play mode, we must destroy the stream */
  350.       ulAmpDestroy   = OPERATION_RECORD;
  351.  
  352.       }
  353.  
  354.    /*****************************************
  355.    * To ensure proper syncronization, acquire
  356.    * the semaphore which is used to control
  357.    * who can check to see which processes are
  358.    * active. This function will also tell us
  359.    * if there is an operation to abort or
  360.    * supercede.
  361.    ******************************************/
  362.  
  363.    GetNotifyAbortAccess ( pInstance, &ulAbortNotify );
  364.  
  365.    /*******************************************
  366.    * If there is an operation active (i.e. a
  367.    * play, record or save) then post a message
  368.    * stating that the command has been
  369.    * aborted ( play or record) or
  370.    * wait for completion (save).
  371.    ********************************************/
  372.  
  373.    if ( ulAbortNotify )
  374.       {
  375.       ulrc = CueAbortInProgressNotify( pInstance, pFuncBlock, ulMCIOperation );
  376.       }
  377.  
  378.     /**********************************************
  379.     * If the card is in record mode, or a record
  380.     * stream is active, destroy the stream.
  381.     ***********************************************/
  382.  
  383.     if (  pInstance->AmpInstance.ulOperation == ulAmpDestroy )
  384.  
  385.          {
  386.          /******************************************
  387.          * Stop The Previous stream
  388.          *******************************************/
  389.          SpiStopStream ( pInstance->StreamInfo.hStream,
  390.                          SPI_STOP_DISCARD);
  391.  
  392.          /**************************************
  393.          * Destroy the previous stream
  394.          **************************************/
  395.          DestroyStream ( &pInstance->StreamInfo.hStream);
  396.  
  397.          /*******************************************
  398.          * Set Stream Creation flag to create state
  399.          ********************************************/
  400.          pInstance->ulCreateFlag = CREATE_STATE;
  401.  
  402.          }
  403.  
  404.  
  405.  
  406.    /***********************************************
  407.    * If a set was performed on an existing stream,
  408.    * destroy the stream and get new spcb keys
  409.    ***********************************************/
  410.  
  411.    DestroySetStream ( pInstance );
  412.  
  413.     /***********************************************
  414.     * Set the stream up and cue it for play back!
  415.     ***********************************************/
  416.  
  417.     ulrc = CueStream( pInstance, ulAmpOperation );
  418.  
  419.     return ( ulrc );
  420.  
  421. } /* CueSetup */
  422.  
  423.  
  424. /********************* START OF SPECIFICATIONS *********************
  425. *
  426. * SUBROUTINE NAME: CueStream
  427. *
  428. * DESCRIPTIVE NAME: Creates a stream and cues it.
  429. *
  430. * FUNCTION: This function will create and stream, and will
  431. *           preroll start for playback.  Since record buffers
  432. *           will be filled with garbage, it is pointless to
  433. *           preroll start it.
  434. *
  435. * NOTES:
  436. *
  437. * ENTRY POINTS:
  438. *
  439. * INPUT: INSTANCE ptr
  440. *
  441. * EXIT-NORMAL: Return Code 0.
  442. *
  443. * EXIT_ERROR:
  444. *
  445. * EFFECTS:
  446. *
  447. * INTERNAL REFERENCES: MCIERR ().
  448. *
  449. * EXTERNAL REFERENCES: spiCreateStream()
  450. *                      spiStartStream()
  451. *
  452. *********************** END OF SPECIFICATIONS **********************/
  453.  
  454. ULONG CueStream( INSTANCE *ulpInstance,
  455.                  ULONG    ulOperation )
  456.  
  457.  
  458. {
  459.  
  460.     ULONG    ulrc;               // return codes
  461.     ULONG    ulCount;            // Semaphore variable
  462.     BOOL     fInitNeeded = FALSE;// Must we initialize the card?
  463.  
  464.    /****************************************
  465.    * If no stream has been created, and the
  466.    * card has not changed modes, there is no
  467.    * need to reinit it!
  468.    *****************************************/
  469.  
  470.    if ( AMPMIX.ulOperation != ulOperation  ||
  471.         ulpInstance->StreamInfo.ulState == STREAM_SET_STATE )
  472.       {
  473.       fInitNeeded = TRUE;
  474.       }
  475.  
  476.  
  477.  
  478.     /*******************************
  479.     * Do stream set up work and then
  480.     * create the stream
  481.     *******************************/
  482.  
  483.     ulrc = PrepareAndCreateStream( ulpInstance, ulOperation, fInitNeeded  );
  484.  
  485.     if ( ulrc )
  486.        {
  487.        return ( ulrc );
  488.        }
  489.  
  490.  
  491.      /*******************************
  492.      * Preroll Start the stream.
  493.      *******************************/
  494.      DosResetEventSem (ulpInstance->hEventSem, &ulCount);
  495.  
  496.      /********************************************************
  497.      * We do not want to preroll start a record stream
  498.      * since the buffers willbe filled with bogus information
  499.      * so only fill the play stream with a preroll start.
  500.      *********************************************************/
  501.  
  502.      if ( ( STRMSTATE != CUEPLAY_STATE && ulOperation == OPERATION_PLAY ) )
  503.          {
  504.  
  505.          ulrc = SpiStartStream (ulpInstance->StreamInfo.hStream,
  506.                                 SPI_START_PREROLL);
  507.  
  508.          if (ulrc)
  509.             {
  510.             return ulrc;
  511.             }
  512.  
  513.          /*************************************
  514.          * Wait till you Recieve PREROLL Event
  515.          *************************************/
  516.  
  517.          DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  518.  
  519.          } /* Preroll Start */
  520.  
  521.      /*************************************
  522.      * Update state To preroll
  523.      **************************************/
  524.  
  525.      ulpInstance->ulCreateFlag = PREROLL_STATE;
  526.  
  527.      return ( ulrc );
  528.  
  529. } /* Cue Stream */
  530.  
  531.  
  532.  
  533. /********************* START OF SPECIFICATIONS *********************
  534. *
  535. * SUBROUTINE NAME: AbortInProgressNotify
  536. *
  537. * DESCRIPTIVE NAME: Stops a notify which was already in progress
  538. *
  539. * FUNCTION: Stops save, record and playback notifies
  540. *
  541. * NOTES:
  542. *
  543. * ENTRY POINTS:
  544. *
  545. * INPUT: INSTANCE ptr
  546. *
  547. * EXIT-NORMAL: Return Code 0.
  548. *
  549. * EXIT_ERROR:
  550. *
  551. * EFFECTS:
  552. *
  553. * INTERNAL REFERENCES: MCIERR ().
  554. *
  555. * EXTERNAL REFERENCES: spiStopStream()    - SSM Spi
  556. *
  557. *********************** END OF SPECIFICATIONS **********************/
  558.  
  559. ULONG CueAbortInProgressNotify( INSTANCE             *ulpInstance,
  560.                                 FUNCTION_PARM_BLOCK  *pFuncBlock,
  561.                                 ULONG                ulMessage )
  562.  
  563.  
  564. {
  565.   ULONG ulrc = MCIERR_SUCCESS;
  566.  
  567.   /*****************************************************
  568.   * If a stream is currently in use, destroy or stop it!
  569.   ******************************************************/
  570.  
  571.      if ( ulpInstance->usNotPendingMsg == MCI_SAVE )
  572.        {
  573.        /***********************************
  574.        * Can't interrupt a save because data
  575.        * can be lost--wait till completion
  576.        ************************************/
  577.  
  578.        DosWaitEventSem( ulpInstance->hThreadSem, (ULONG ) -1 );
  579.  
  580.        }
  581.      else
  582.        {
  583.        PostMDMMessage ( MCI_NOTIFY_ABORTED,
  584.                         ulpInstance->usNotPendingMsg,
  585.                         pFuncBlock );
  586.  
  587.       /* Stop the pending thread */
  588.  
  589.       ThreadedStop ( ulpInstance );
  590.  
  591.        /**********************************************************
  592.        * If we have a record stream and we are cueing for input
  593.        * or if we have a playback stream and are cueing for output
  594.        * then don't destroy the stream.  Just place it in a
  595.        * stopped state.
  596.        **********************************************************/
  597.  
  598.        if ( ulpInstance->usNotPendingMsg != ulMessage )
  599.           {
  600.           /**************************************
  601.           * Destroy the previous stream since it
  602.           * was going the wrong way.
  603.           ***************************************/
  604.  
  605.           DestroyStream ( &ulpInstance->StreamInfo.hStream);
  606.  
  607.           /***************************************
  608.           * Update the stream state so that following
  609.           * routines will be forced to create a new
  610.           * stream.
  611.           ****************************************/
  612.  
  613.           ulpInstance->ulCreateFlag = CREATE_STATE;
  614.  
  615.           } /* else this is a play stream */
  616.  
  617.         } /* notify pending was not a !save */
  618.  
  619.  
  620.    return ( ulrc );
  621.  
  622. } /* CueAbortInProgressNotify */
  623.  
  624.  
  625.  
  626. /********************* START OF SPECIFICATIONS *********************
  627. *
  628. * SUBROUTINE NAME: MCISCPT.C
  629. *
  630. * DESCRIPTIVE NAME: Set Cue Point Waveform Device.
  631. *
  632. * FUNCTION: Establish Cue points during playback on Waveform Device.
  633. *
  634. * NOTES:
  635. *
  636. * ENTRY POINTS:
  637. *     LINKAGE:   CALL FAR
  638. *
  639. * INPUT: MCI_SET_CUEPOINT message.
  640. *
  641. * EXIT-NORMAL: MCIERR_SUCCESS.
  642. *
  643. * EXIT_ERROR:  Error Code.
  644. *
  645. * EFFECTS:
  646. *
  647. * INTERNAL REFERENCES: MCIERR ().
  648. *
  649. * EXTERNAL REFERENCES: spiEnableEvent()    - SSM Spi
  650. *
  651. *********************** END OF SPECIFICATIONS **********************/
  652.  
  653.  
  654. RC MCISetCuePoint (FUNCTION_PARM_BLOCK *pFuncBlock)
  655. {
  656.   ULONG           ulrc;               // Propogated MME Error Code
  657.   ULONG           ulParam1;           // Incoming MCI Flag
  658.   ULONG           ulCuePointFlags;    // Mask For Incoming Flags
  659.   INSTANCE        *ulpInstance;       // Local Instance
  660.  
  661.   PID             pid;
  662.   TID             tid;
  663.  
  664.   HWND            hWnd;
  665.  
  666.   PMCI_CUEPOINT_PARMS pCueParms;    // Msg MCI Data Structure
  667.  
  668.   /****************************
  669.   * Dereference pointers
  670.   *****************************/
  671.  
  672.   ulParam1 = pFuncBlock->ulParam1;
  673.   pCueParms = ( PMCI_CUEPOINT_PARMS ) pFuncBlock->ulParam2;
  674.   ulpInstance= (INSTANCE *) pFuncBlock->ulpInstance;
  675.  
  676.   /**************************
  677.   * Mask out supported flags
  678.   **************************/
  679.   ulCuePointFlags = ulParam1;
  680.   ulCuePointFlags &= ~( MCI_WAIT            + MCI_NOTIFY +
  681.                    MCI_SET_CUEPOINT_ON + MCI_SET_CUEPOINT_OFF );
  682.  
  683.  
  684.   /* If the caller passed in an invalid flag return an error */
  685.  
  686.   if (ulCuePointFlags > 0 )
  687.       return ( MCIERR_INVALID_FLAG );
  688.  
  689.   /******************************************
  690.   * Check to see if CuePoint parms are good
  691.   ******************************************/
  692.  
  693.   ulrc = CheckMem (((PVOID) pCueParms ),
  694.                    sizeof (MCI_CUEPOINT_PARMS), PAG_READ);
  695.  
  696.   if (ulrc != MCIERR_SUCCESS)
  697.       return ( MCIERR_MISSING_PARAMETER );
  698.  
  699.   /**********************************************
  700.   * It is the MCD's responsibility to ensure that
  701.   * the callback handle that the caller passed in
  702.   * is valid--so ask PM if it is valid.
  703.   **********************************************/
  704.  
  705.   hWnd = pCueParms->hwndCallback;
  706.  
  707.  
  708.   if ( !WinQueryWindowProcess(hWnd, &pid, &tid) )
  709.       return (MCIERR_INVALID_CALLBACK_HANDLE);
  710.  
  711.   /************************************************
  712.   * Check for valid flags but invalid combination
  713.   *************************************************/
  714.  
  715.   if (ulParam1 & MCI_SET_CUEPOINT_ON && ulParam1 & MCI_SET_CUEPOINT_OFF)
  716.       return ( MCIERR_FLAGS_NOT_COMPATIBLE );
  717.  
  718.   /***************************************************
  719.   * The caller must either turn a cue point on or off
  720.   ****************************************************/
  721.  
  722.  
  723.   if (!(ulParam1 & MCI_SET_CUEPOINT_ON || ulParam1 & MCI_SET_CUEPOINT_OFF))
  724.        return ( MCIERR_MISSING_FLAG );
  725.  
  726.   /*****************************************
  727.   * No media element loaded--reject cuepoint
  728.   ******************************************/
  729.  
  730.   // make file exists to ulong--set to true/false.
  731.  
  732.   if ( ulpInstance->fFileExists == FALSE )
  733.      {
  734.      return (MCIERR_FILE_NOT_FOUND);
  735.      }
  736.  
  737.   /*************************
  738.   * Check for range errors
  739.   *************************/
  740.  
  741.   if (pCueParms->ulCuepoint <= 0)
  742.  
  743.       return (MCIERR_OUTOFRANGE);
  744.  
  745.   /**************************************
  746.   * Enable cuepoints if on flag is passed
  747.   **************************************/
  748.  
  749.   if (ulParam1 & MCI_SET_CUEPOINT_ON)
  750.      {
  751.      /**********************************************
  752.      * Enable CuePoints and add to linked list
  753.      **********************************************/
  754.  
  755.      ulrc = CuePointAdd( ulpInstance, pCueParms );
  756.  
  757.      } /* Set Cue Point On */
  758.  
  759.  
  760.   /*************************************
  761.   * Disable cuepoint if off flag is set
  762.   *************************************/
  763.  
  764.   if (ulParam1 & MCI_SET_CUEPOINT_OFF)
  765.      {
  766.      /**********************************************
  767.      * Disable CuePoints and remove from linked list
  768.      **********************************************/
  769.  
  770.      ulrc = CuePointDelete( ulpInstance, pCueParms );
  771.  
  772.      } /* CuePoint Off */
  773.  
  774.  
  775.   return ( ulrc );
  776.  
  777. } /* MCISetCuePoint */
  778.  
  779.  
  780.  
  781. /********************* START OF SPECIFICATIONS *********************
  782. *
  783. * SUBROUTINE NAME: CuePointAdd
  784. *
  785. * DESCRIPTIVE
  786. *
  787. * FUNCTION:  Adds cuepoint to linked list of cue points
  788. *
  789. * NOTES: This function illustrates how to extend an
  790. *        event control block to contain custom information.
  791. *        For example, each cue point EVCB can contain its
  792. *        own window callback handle.
  793. *
  794. * ENTRY POINTS:
  795. *     LINKAGE:   CALL FAR
  796. *
  797. * INPUT:
  798. *
  799. * EXIT-NORMAL: MCIERR_SUCCESS
  800. *
  801. * EXIT_ERROR:  Error Code.
  802. *
  803. * EFFECTS:
  804. *
  805. * INTERNAL REFERENCES: MCIERR ().
  806. *
  807. * EXTERNAL REFERENCES:
  808. *
  809. *********************** END OF SPECIFICATIONS **********************/
  810. RC CuePointAdd ( INSTANCE             *ulpInstance,
  811.                  PMCI_CUEPOINT_PARMS pCueParms )
  812.  
  813. {
  814.    MTIME_EVCB  *pTempMCuePtEVCB;   // temporary pointer to item in linked list
  815.  
  816.    ULONG       ulTempTime;         // time conversion variable
  817.    ULONG       ulFoundCuePoint=FALSE; // Find flag
  818.    ULONG       ulrc;
  819.  
  820.    extern HHUGEHEAP     heap;                // Global MCD Heap
  821.  
  822.    pTempMCuePtEVCB = CUEPOINT;
  823.  
  824.    /********************************************
  825.    * Check to see if the cue point is already in
  826.    * our linked list of cuepoints.  Continue
  827.    * checking while we have a list and we have
  828.    * not found the cuepoint.
  829.    *********************************************/
  830.  
  831.    while ( pTempMCuePtEVCB && !ulFoundCuePoint )
  832.       {
  833.  
  834.       /*****************************************************
  835.       * If the current node is the same as the cuepoint
  836.       * that the caller wants to set, then its a duplicate
  837.       *****************************************************/
  838.  
  839.       if (pTempMCuePtEVCB->mmCuePt == pCueParms->ulCuepoint)
  840.          {
  841.          ulFoundCuePoint = TRUE;
  842.          }
  843.  
  844.       /* Keep progressing through the list */
  845.  
  846.       pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  847.  
  848.       }
  849.  
  850.    /* If we found the cuepoint in the list--its a duplicate */
  851.  
  852.    if ( ulFoundCuePoint )
  853.       {
  854.       return MCIERR_DUPLICATE_CUEPOINT;
  855.       }
  856.  
  857.    AcquireProcSem ();
  858.  
  859.  
  860.    if ( !(pTempMCuePtEVCB = HhpAllocMem (heap, sizeof ( MTIME_EVCB ) ) ) )
  861.       {
  862.       return (MCIERR_OUT_OF_MEMORY);
  863.       }
  864.  
  865.    ReleaseProcSem ();
  866.  
  867.    /********************************************
  868.    * Fill In the window handle and device id
  869.    *********************************************/
  870.  
  871.  
  872.    pTempMCuePtEVCB->hwndCallback = pCueParms->hwndCallback;
  873.    pTempMCuePtEVCB->usDeviceID = ulpInstance->usWaveDeviceID;
  874.  
  875.    /********************************************
  876.    * Fill In Time event control block for a
  877.    * cue point ( all of these fields are REQUIRED)
  878.    * Note: We have altered the evcb to contain
  879.    * additional information (such as our callback
  880.    * userParm, instance etc.).  See audiomcd.h
  881.    * for an explanation of how this is done.
  882.    *********************************************/
  883.  
  884.    pTempMCuePtEVCB->evcb.ulType = EVENT_CUE_TIME;
  885.    pTempMCuePtEVCB->evcb.ulFlags = EVENT_SINGLE;
  886.    pTempMCuePtEVCB->evcb.hstream = ulpInstance->StreamInfo.hStream;
  887.  
  888.    /*********************************************
  889.    * Store the time at which the cue point
  890.    * is to be generated ( this must be in MMTIME
  891.    *********************************************/
  892.  
  893.    ulrc = ConvertToMM ( ulpInstance,
  894.                         &ulTempTime,
  895.                         pCueParms->ulCuepoint);
  896.  
  897.    pTempMCuePtEVCB->evcb.mmtimeStream = ulTempTime;
  898.  
  899.    /***************************************************
  900.    * Store the callback handle that the caller wishes
  901.    * the cuepoint notification to occur on.
  902.    * Remember each cuepoint can have its own callback.
  903.    ****************************************************/
  904.  
  905.    pTempMCuePtEVCB->mmCuePt = pCueParms->ulCuepoint;
  906.  
  907.    /*****************************************************
  908.    * Stick In INSTANCE Pointer in The Time EVCB, this will
  909.    * allow the event procedure to have access to our
  910.    * instance--it ordinarily would not have access to it.
  911.    * See comments in PlayEventProc and RecordEventProc.
  912.    ******************************************************/
  913.  
  914.    pTempMCuePtEVCB->ulpInstance = (ULONG) ulpInstance;
  915.  
  916.  
  917.    /*****************************************************
  918.    * Copy CuePoint User Parm into EVCB Structure
  919.    ******************************************************/
  920.    pTempMCuePtEVCB->usCueUsrParm =pCueParms->usUserParm;
  921.  
  922.    /*****************************************************
  923.    * Link this cue point into the list of cue points
  924.    ******************************************************/
  925.  
  926.    pTempMCuePtEVCB->pNextEVCB = CUEPOINT;
  927.    CUEPOINT = pTempMCuePtEVCB;
  928.  
  929.    /************************************************
  930.    * We can only enable events after a stream has
  931.    * been created--otherwise you will get errors.
  932.    * If we cannot enable the event right now, store
  933.    * this in a flag, and enable it before playback
  934.    * or record.
  935.    ************************************************/
  936.  
  937.    if (ulpInstance->ulCreateFlag == PREROLL_STATE)
  938.       {
  939.       ulrc = SpiEnableEvent( (PEVCB) pTempMCuePtEVCB,
  940.                              (PHEVENT) &pTempMCuePtEVCB->HCuePtHndl );
  941.  
  942.       ulpInstance->usCuePt = EVENT_ENABLED;
  943.       }
  944.    else
  945.       {
  946.       ulpInstance->usCuePt = TRUE;
  947.       }
  948.  
  949.    return ( ulrc );
  950.  
  951. } /* CuePointAdd */
  952.  
  953.  
  954.  
  955.  
  956. /********************* START OF SPECIFICATIONS *********************
  957. *
  958. * SUBROUTINE NAME: CuePointDelete
  959. *
  960. * DESCRIPTIVE
  961. *
  962. * FUNCTION:  Removes cuepoint from linked list of cue points
  963. *
  964. * NOTES:
  965. *
  966. * ENTRY POINTS:
  967. *
  968. * INPUT:
  969. *
  970. * EXIT-NORMAL: Return Code 0.
  971. *
  972. * EXIT_ERROR:  Error Code.
  973. *
  974. * EFFECTS:
  975. *
  976. * INTERNAL REFERENCES: MCIERR ().
  977. *
  978. * EXTERNAL REFERENCES:
  979. *
  980. *********************** END OF SPECIFICATIONS **********************/
  981. RC CuePointDelete ( INSTANCE             *ulpInstance,
  982.                     PMCI_CUEPOINT_PARMS pCueParms )
  983.  
  984. {
  985.    MTIME_EVCB  *pTempMCuePtEVCB;         // temporary pointer to item in linked list
  986.    MTIME_EVCB  *pPrevMCuePtEVCB;         // temporary pointer to item in linked list
  987.  
  988.    ULONG       ulFoundCuePoint = FALSE;  // Flag to indicate whether the cpt was found
  989.    ULONG       ulrc;
  990.  
  991.    extern HHUGEHEAP     heap;                // Global MCD Heap
  992.  
  993.   /* If we have never enabled a cuepoint, we can't delete it */
  994.  
  995.   if ( !CUEPOINT )
  996.      {
  997.      return ( MCIERR_INVALID_CUEPOINT );
  998.      }
  999.  
  1000.   pTempMCuePtEVCB = pPrevMCuePtEVCB = CUEPOINT;
  1001.  
  1002.   /********************************************
  1003.   * Check to see if the cue point is already in
  1004.   * our linked list of cuepoints.  Continue
  1005.   * checking while we have a list and we have
  1006.   * not found the cuepoint.
  1007.   *********************************************/
  1008.  
  1009.   while ( pTempMCuePtEVCB && !ulFoundCuePoint )
  1010.     {
  1011.     if ( pTempMCuePtEVCB->mmCuePt == pCueParms->ulCuepoint)
  1012.        {
  1013.  
  1014.        /********************************************
  1015.        * If we found a cuepoint and the stream is
  1016.        * active, remove the cuepoint.  Simply
  1017.        * deleting it from our linked list is not
  1018.        * enough since the cuepoint will continue
  1019.        * to be reported until it is removed.
  1020.        ********************************************/
  1021.  
  1022.        if ( ulpInstance->usCuePt == EVENT_ENABLED )
  1023.  
  1024.           {
  1025.           /***********************************************
  1026.           * Check Validity of hCuePointEvent
  1027.           **********************************************/
  1028.           ulrc = SpiDisableEvent ( pTempMCuePtEVCB->HCuePtHndl );
  1029.  
  1030.           } /* CreateFlag == PrerollState */
  1031.  
  1032.        ulFoundCuePoint = TRUE;
  1033.  
  1034.        /***********************************************
  1035.        * Ensure that the previous node points to the
  1036.        * next node.
  1037.        *********************************************/
  1038.  
  1039.        if ( pTempMCuePtEVCB != pPrevMCuePtEVCB )
  1040.           {
  1041.           pPrevMCuePtEVCB->pNextEVCB = pTempMCuePtEVCB->pNextEVCB;
  1042.           }
  1043.        else
  1044.           {
  1045.           /***********************************************
  1046.           * If we are deleting the first item in the list
  1047.           * ensure that we have a valid initial pointer
  1048.           **********************************************/
  1049.  
  1050.           CUEPOINT = pTempMCuePtEVCB->pNextEVCB;
  1051.           }
  1052.  
  1053.        /* Toast the node to delete */
  1054.  
  1055.        CleanUp( pTempMCuePtEVCB );
  1056.  
  1057.  
  1058.        } /* Found the CuePoint Block */
  1059.  
  1060.     /**********************************************
  1061.     * Else we didn't find the requested cue point
  1062.     * so advance a node
  1063.     **********************************************/
  1064.  
  1065.     else
  1066.        {
  1067.        if ( pTempMCuePtEVCB != pPrevMCuePtEVCB )
  1068.           {
  1069.           pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  1070.           pPrevMCuePtEVCB = pPrevMCuePtEVCB->pNextEVCB;
  1071.           }
  1072.        else
  1073.           {
  1074.           pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  1075.           }
  1076.  
  1077.        } /* else we haven't found the requested cue point */
  1078.  
  1079.     } /* endwhile */
  1080.  
  1081.     /* If we couldn't find the cuepoint--report the error */
  1082.  
  1083.     if ( ulFoundCuePoint == FALSE)
  1084.        {
  1085.        return ( MCIERR_INVALID_CUEPOINT );
  1086.        }
  1087.  
  1088.     return ( ulrc );
  1089.  
  1090. } /* CuePointDelete */
  1091.  
  1092.  
  1093.