home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / VSCPPv8.zip / VACPP / IBMCPP / samples / TOOLKIT / MM / ADMCT / ADMCCUE.C < prev    next >
C/C++ Source or Header  |  1994-11-17  |  33KB  |  1,117 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 <ssm.h>                        // SSM spi includes.
  67. #include <meerror.h>                    // MM Error Messages.
  68. #include <mmioos2.h>                    // MMIO Include.
  69. #include <mcios2.h>                     // MM System Include.
  70. #include <mmdrvos2.h>                   // MCI Driver Include.
  71. #include <mcd.h>                        // AudioIFDriverInterface.
  72. #include <hhpheap.h>                    // Heap Manager Definitions
  73. #include <qos.h>
  74. #include <audiomcd.h>                   // Component Definitions
  75. #include "admcfunc.h"                   // Function Prototypes
  76. #include <checkmem.h>
  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 ( ulpInstance->ulOperation == MCIDRV_INPUT &&
  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 ( ulpInstance->ulOperation == MCIDRV_OUTPUT &&
  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 = MCIDRV_INPUT;
  343.       /* If the amp is in play mode, we must destroy the stream */
  344.       ulAmpDestroy   = MCIDRV_OUTPUT;
  345.       pInstance->ulCodecDescription = MAKE_TARGET | TARGET_CODEC;
  346.       }
  347.    else
  348.       {
  349.       ulAmpOperation = MCIDRV_OUTPUT;
  350.       /* If the amp is in play mode, we must destroy the stream */
  351.       ulAmpDestroy   = MCIDRV_INPUT;
  352.       pInstance->ulCodecDescription = MAKE_SOURCE | SOURCE_CODEC;
  353.  
  354.       }
  355.  
  356.    /*****************************************
  357.    * To ensure proper syncronization, acquire
  358.    * the semaphore which is used to control
  359.    * who can check to see which processes are
  360.    * active. This function will also tell us
  361.    * if there is an operation to abort or
  362.    * supercede.
  363.    ******************************************/
  364.  
  365.    GetNotifyAbortAccess ( pInstance, &ulAbortNotify );
  366.  
  367.    /*******************************************
  368.    * If there is an operation active (i.e. a
  369.    * play, record or save) then post a message
  370.    * stating that the command has been
  371.    * aborted ( play or record) or
  372.    * wait for completion (save).
  373.    ********************************************/
  374.  
  375.    if ( ulAbortNotify )
  376.       {
  377.       ulrc = CueAbortInProgressNotify( pInstance, pFuncBlock, ulMCIOperation );
  378.       }
  379.  
  380.     /**********************************************
  381.     * If the card is in record mode, or a record
  382.     * stream is active, destroy the stream.
  383.     ***********************************************/
  384.  
  385.     if (  pInstance->ulOperation == ulAmpDestroy )
  386.  
  387.          {
  388. // CONNECTOR FEATURE
  389.          StopStream2( pInstance, MCIDRV_DISCARD_STREAM_NETWORK );
  390.  
  391.          /******************************************
  392.          * Stop The Previous stream
  393.          *******************************************/
  394. //         SpiStopStream ( pInstance->StreamInfo.hStream,
  395. //                         SPI_STOP_DISCARD);
  396.  
  397.          /**************************************
  398.          * Destroy the previous stream
  399.          **************************************/
  400. #ifndef CONNECTION
  401.          DestroyStream ( pInstance);
  402. #endif
  403. // CONNECTOR FEATURE
  404.          /*******************************************
  405.          * Set Stream Creation flag to create state
  406.          ********************************************/
  407.          pInstance->ulCreateFlag = CREATE_STATE;
  408.  
  409. #ifndef CONNECTION
  410.          if ( pInstance->ulRealTimeTranslation ==MMIO_REALTIME )
  411.             {
  412.             DataTranslation( pInstance );
  413.             }
  414. #endif
  415.  
  416.          }
  417.  
  418.  
  419.  
  420.    /***********************************************
  421.    * If a set was performed on an existing stream,
  422.    * destroy the stream and get new spcb keys
  423.    ***********************************************/
  424.  
  425.    DestroySetStream ( pInstance );
  426.  
  427.     /***********************************************
  428.     * Set the stream up and cue it for play back!
  429.     ***********************************************/
  430.  
  431.     ulrc = CueStream( pInstance, ulAmpOperation );
  432.  
  433.     return ( ulrc );
  434.  
  435. } /* CueSetup */
  436.  
  437.  
  438. /********************* START OF SPECIFICATIONS *********************
  439. *
  440. * SUBROUTINE NAME: CueStream
  441. *
  442. * DESCRIPTIVE NAME: Creates a stream and cues it.
  443. *
  444. * FUNCTION: This function will create and stream, and will
  445. *           preroll start for playback.  Since record buffers
  446. *           will be filled with garbage, it is pointless to
  447. *           preroll start it.
  448. *
  449. * NOTES:
  450. *
  451. * ENTRY POINTS:
  452. *
  453. * INPUT: INSTANCE ptr
  454. *
  455. * EXIT-NORMAL: Return Code 0.
  456. *
  457. * EXIT_ERROR:
  458. *
  459. * EFFECTS:
  460. *
  461. * INTERNAL REFERENCES: MCIERR ().
  462. *
  463. * EXTERNAL REFERENCES: spiCreateStream()
  464. *                      spiStartStream()
  465. *
  466. *********************** END OF SPECIFICATIONS **********************/
  467.  
  468. ULONG CueStream( INSTANCE *ulpInstance,
  469.                  ULONG    ulOperation )
  470.  
  471.  
  472. {
  473.  
  474.     ULONG    ulrc;               // return codes
  475.     ULONG    ulCount;            // Semaphore variable
  476.     BOOL     fInitNeeded = FALSE;// Must we initialize the card?
  477.  
  478.    /****************************************
  479.    * If no stream has been created, and the
  480.    * card has not changed modes, there is no
  481.    * need to reinit it!
  482.    *****************************************/
  483.  
  484.    if ( ulpInstance->ulOperation != ulOperation  ||
  485.         ulpInstance->StreamInfo.ulState == STREAM_SET_STATE )
  486.       {
  487.       fInitNeeded = TRUE;
  488.       }
  489.  
  490.  
  491.  
  492.     /*******************************
  493.     * Do stream set up work and then
  494.     * create the stream
  495.     *******************************/
  496.  
  497.     ulrc = PrepareAndCreateStream( ulpInstance, ulOperation, fInitNeeded  );
  498.  
  499.     if ( ulrc )
  500.        {
  501.        return ( ulrc );
  502.        }
  503.  
  504.  
  505.      /*******************************
  506.      * Preroll Start the stream.
  507.      *******************************/
  508.      DosResetEventSem (ulpInstance->hEventSem, &ulCount);
  509.  
  510.      /********************************************************
  511.      * We do not want to preroll start a record stream
  512.      * since the buffers willbe filled with bogus information
  513.      * so only fill the play stream with a preroll start.
  514.      *********************************************************/
  515.  
  516.      if ( ( STRMSTATE != CUEPLAY_STATE && ulOperation == MCIDRV_OUTPUT) )
  517.          {
  518. // CONNECTOR FEATURE
  519. // is it possible to get here and need to test cueplay?????
  520. //
  521.            BeginQualityofService( ulpInstance, STREAM_READ );
  522.  
  523.            ulrc = StartStream( ulpInstance, MCIDRV_CUE_PLAYBACK );
  524. //         ulrc = SpiStartStream (ulpInstance->StreamInfo.hStream,
  525. //                                SPI_START_PREROLL);
  526.  
  527. // CONNECTOR FEATURE
  528.          if (ulrc)
  529.             {
  530.             return ulrc;
  531.             }
  532.  
  533.          /*************************************
  534.          * Wait till you Recieve PREROLL Event
  535.          *************************************/
  536.  
  537.          DosWaitEventSem (ulpInstance->hEventSem, (ULONG) -1);
  538.          EndQualityofService( ulpInstance );
  539.  
  540.          } /* Preroll Start */
  541.  
  542.      /*************************************
  543.      * Update state To preroll
  544.      **************************************/
  545.  
  546.      ulpInstance->ulCreateFlag = PREROLL_STATE;
  547.  
  548.      return ( ulrc );
  549.  
  550. } /* Cue Stream */
  551.  
  552.  
  553.  
  554. /********************* START OF SPECIFICATIONS *********************
  555. *
  556. * SUBROUTINE NAME: AbortInProgressNotify
  557. *
  558. * DESCRIPTIVE NAME: Stops a notify which was already in progress
  559. *
  560. * FUNCTION: Stops save, record and playback notifies
  561. *
  562. * NOTES:
  563. *
  564. * ENTRY POINTS:
  565. *
  566. * INPUT: INSTANCE ptr
  567. *
  568. * EXIT-NORMAL: Return Code 0.
  569. *
  570. * EXIT_ERROR:
  571. *
  572. * EFFECTS:
  573. *
  574. * INTERNAL REFERENCES: MCIERR ().
  575. *
  576. * EXTERNAL REFERENCES: spiStopStream()    - SSM Spi
  577. *
  578. *********************** END OF SPECIFICATIONS **********************/
  579.  
  580. ULONG CueAbortInProgressNotify( INSTANCE             *ulpInstance,
  581.                                 FUNCTION_PARM_BLOCK  *pFuncBlock,
  582.                                 ULONG                ulMessage )
  583.  
  584.  
  585. {
  586.   ULONG ulrc = MCIERR_SUCCESS;
  587.  
  588.   /*****************************************************
  589.   * If a stream is currently in use, destroy or stop it!
  590.   ******************************************************/
  591.  
  592.      if ( ulpInstance->usNotPendingMsg == MCI_SAVE )
  593.        {
  594.        /***********************************
  595.        * Can't interrupt a save because data
  596.        * can be lost--wait till completion
  597.        ************************************/
  598.  
  599.        DosWaitEventSem( ulpInstance->hThreadSem, (ULONG ) -1 );
  600.  
  601.        }
  602.      else
  603.        {
  604.        PostMDMMessage ( MCI_NOTIFY_ABORTED,
  605.                         ulpInstance->usNotPendingMsg,
  606.                         pFuncBlock );
  607.  
  608.       /* Stop the pending thread */
  609.  
  610.       ThreadedStop ( ulpInstance );
  611.  
  612.        /**********************************************************
  613.        * If we have a record stream and we are cueing for input
  614.        * or if we have a playback stream and are cueing for output
  615.        * then don't destroy the stream.  Just place it in a
  616.        * stopped state.
  617.        **********************************************************/
  618.  
  619.        if ( ulpInstance->usNotPendingMsg != ulMessage )
  620.           {
  621. // CONNECTOR FEATURE--destroys are no longer needed.
  622.           /**************************************
  623.           * Destroy the previous stream since it
  624.           * was going the wrong way.
  625.           ***************************************/
  626. #ifndef CONNECTION
  627.         DestroyStream ( ulpInstance);
  628. #endif
  629. // CONNECTOR FEATURE
  630.  
  631.           /***************************************
  632.           * Update the stream state so that following
  633.           * routines will be forced to create a new
  634.           * stream.
  635.           ****************************************/
  636.  
  637.           ulpInstance->ulCreateFlag = CREATE_STATE;
  638.  
  639.           } /* else this is a play stream */
  640.  
  641.         } /* notify pending was not a !save */
  642.  
  643.  
  644.    return ( ulrc );
  645.  
  646. } /* CueAbortInProgressNotify */
  647.  
  648.  
  649.  
  650. /********************* START OF SPECIFICATIONS *********************
  651. *
  652. * SUBROUTINE NAME: MCISCPT.C
  653. *
  654. * DESCRIPTIVE NAME: Set Cue Point Waveform Device.
  655. *
  656. * FUNCTION: Establish Cue points during playback on Waveform Device.
  657. *
  658. * NOTES:
  659. *
  660. * ENTRY POINTS:
  661. *     LINKAGE:   CALL FAR
  662. *
  663. * INPUT: MCI_SET_CUEPOINT message.
  664. *
  665. * EXIT-NORMAL: MCIERR_SUCCESS.
  666. *
  667. * EXIT_ERROR:  Error Code.
  668. *
  669. * EFFECTS:
  670. *
  671. * INTERNAL REFERENCES: MCIERR ().
  672. *
  673. * EXTERNAL REFERENCES: spiEnableEvent()    - SSM Spi
  674. *
  675. *********************** END OF SPECIFICATIONS **********************/
  676.  
  677.  
  678. RC MCISetCuePoint (FUNCTION_PARM_BLOCK *pFuncBlock)
  679. {
  680.   ULONG           ulrc;               // Propogated MME Error Code
  681.   ULONG           ulParam1;           // Incoming MCI Flag
  682.   ULONG           ulCuePointFlags;    // Mask For Incoming Flags
  683.   INSTANCE        *ulpInstance;       // Local Instance
  684.  
  685.   PID             pid;
  686.   TID             tid;
  687.  
  688.   HWND            hWnd;
  689.  
  690.   PMCI_CUEPOINT_PARMS pCueParms;    // Msg MCI Data Structure
  691.  
  692.   /****************************
  693.   * Dereference pointers
  694.   *****************************/
  695.  
  696.   ulParam1 = pFuncBlock->ulParam1;
  697.   pCueParms = ( PMCI_CUEPOINT_PARMS ) pFuncBlock->ulParam2;
  698.   ulpInstance= (INSTANCE *) pFuncBlock->ulpInstance;
  699.  
  700.   /**************************
  701.   * Mask out supported flags
  702.   **************************/
  703.   ulCuePointFlags = ulParam1;
  704.   ulCuePointFlags &= ~( MCI_WAIT            + MCI_NOTIFY +
  705.                    MCI_SET_CUEPOINT_ON + MCI_SET_CUEPOINT_OFF );
  706.  
  707.  
  708.   /* If the caller passed in an invalid flag return an error */
  709.  
  710.   if (ulCuePointFlags > 0 )
  711.       return ( MCIERR_INVALID_FLAG );
  712.  
  713.   /******************************************
  714.   * Check to see if CuePoint parms are good
  715.   ******************************************/
  716.  
  717.   ulrc = CheckMem (((PVOID) pCueParms ),
  718.                    sizeof (MCI_CUEPOINT_PARMS), PAG_READ);
  719.  
  720.   if (ulrc != MCIERR_SUCCESS)
  721.       return ( MCIERR_MISSING_PARAMETER );
  722.  
  723.   /**********************************************
  724.   * It is the MCD's responsibility to ensure that
  725.   * the callback handle that the caller passed in
  726.   * is valid--so ask PM if it is valid.
  727.   **********************************************/
  728.  
  729.   hWnd = pCueParms->hwndCallback;
  730.  
  731.  
  732.   if ( !WinQueryWindowProcess(hWnd, &pid, &tid) )
  733.       return (MCIERR_INVALID_CALLBACK_HANDLE);
  734.  
  735.   /************************************************
  736.   * Check for valid flags but invalid combination
  737.   *************************************************/
  738.  
  739.   if (ulParam1 & MCI_SET_CUEPOINT_ON && ulParam1 & MCI_SET_CUEPOINT_OFF)
  740.       return ( MCIERR_FLAGS_NOT_COMPATIBLE );
  741.  
  742.   /***************************************************
  743.   * The caller must either turn a cue point on or off
  744.   ****************************************************/
  745.  
  746.  
  747.   if (!(ulParam1 & MCI_SET_CUEPOINT_ON || ulParam1 & MCI_SET_CUEPOINT_OFF))
  748.        return ( MCIERR_MISSING_FLAG );
  749.  
  750.   /*****************************************
  751.   * No media element loaded--reject cuepoint
  752.   ******************************************/
  753.  
  754.   // make file exists to ulong--set to true/false.
  755.  
  756.   if ( ulpInstance->fFileExists == FALSE )
  757.      {
  758.      return (MCIERR_FILE_NOT_FOUND);
  759.      }
  760.  
  761.   /*************************
  762.   * Check for range errors
  763.   *************************/
  764.  
  765.   if (pCueParms->ulCuepoint <= 0)
  766.  
  767.       return (MCIERR_OUTOFRANGE);
  768.  
  769.   /**************************************
  770.   * Enable cuepoints if on flag is passed
  771.   **************************************/
  772.  
  773.   if (ulParam1 & MCI_SET_CUEPOINT_ON)
  774.      {
  775.      /**********************************************
  776.      * Enable CuePoints and add to linked list
  777.      **********************************************/
  778.  
  779.      ulrc = CuePointAdd( ulpInstance, pCueParms );
  780.  
  781.      } /* Set Cue Point On */
  782.  
  783.  
  784.   /*************************************
  785.   * Disable cuepoint if off flag is set
  786.   *************************************/
  787.  
  788.   if (ulParam1 & MCI_SET_CUEPOINT_OFF)
  789.      {
  790.      /**********************************************
  791.      * Disable CuePoints and remove from linked list
  792.      **********************************************/
  793.  
  794.      ulrc = CuePointDelete( ulpInstance, pCueParms );
  795.  
  796.      } /* CuePoint Off */
  797.  
  798.  
  799.   return ( ulrc );
  800.  
  801. } /* MCISetCuePoint */
  802.  
  803.  
  804.  
  805. /********************* START OF SPECIFICATIONS *********************
  806. *
  807. * SUBROUTINE NAME: CuePointAdd
  808. *
  809. * DESCRIPTIVE
  810. *
  811. * FUNCTION:  Adds cuepoint to linked list of cue points
  812. *
  813. * NOTES: This function illustrates how to extend an
  814. *        event control block to contain custom information.
  815. *        For example, each cue point EVCB can contain its
  816. *        own window callback handle.
  817. *
  818. * ENTRY POINTS:
  819. *     LINKAGE:   CALL FAR
  820. *
  821. * INPUT:
  822. *
  823. * EXIT-NORMAL: MCIERR_SUCCESS
  824. *
  825. * EXIT_ERROR:  Error Code.
  826. *
  827. * EFFECTS:
  828. *
  829. * INTERNAL REFERENCES: MCIERR ().
  830. *
  831. * EXTERNAL REFERENCES:
  832. *
  833. *********************** END OF SPECIFICATIONS **********************/
  834. RC CuePointAdd ( INSTANCE             *ulpInstance,
  835.                  PMCI_CUEPOINT_PARMS pCueParms )
  836.  
  837. {
  838.    MTIME_EVCB  *pTempMCuePtEVCB;   // temporary pointer to item in linked list
  839.  
  840.    ULONG       ulTempTime;         // time conversion variable
  841.    ULONG       ulFoundCuePoint=FALSE; // Find flag
  842.    ULONG       ulrc;
  843.  
  844.    extern HHUGEHEAP     heap;                // Global MCD Heap
  845.  
  846.    pTempMCuePtEVCB = CUEPOINT;
  847.  
  848.    /********************************************
  849.    * Check to see if the cue point is already in
  850.    * our linked list of cuepoints.  Continue
  851.    * checking while we have a list and we have
  852.    * not found the cuepoint.
  853.    *********************************************/
  854.  
  855.    while ( pTempMCuePtEVCB && !ulFoundCuePoint )
  856.       {
  857.  
  858.       /*****************************************************
  859.       * If the current node is the same as the cuepoint
  860.       * that the caller wants to set, then its a duplicate
  861.       *****************************************************/
  862.  
  863.       if (pTempMCuePtEVCB->mmCuePt == pCueParms->ulCuepoint)
  864.          {
  865.          ulFoundCuePoint = TRUE;
  866.          }
  867.  
  868.       /* Keep progressing through the list */
  869.  
  870.       pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  871.  
  872.       }
  873.  
  874.    /* If we found the cuepoint in the list--its a duplicate */
  875.  
  876.    if ( ulFoundCuePoint )
  877.       {
  878.       return MCIERR_DUPLICATE_CUEPOINT;
  879.       }
  880.  
  881.    AcquireProcSem ();
  882.  
  883.  
  884.    if ( !(pTempMCuePtEVCB = HhpAllocMem (heap, sizeof ( MTIME_EVCB ) ) ) )
  885.       {
  886.       return (MCIERR_OUT_OF_MEMORY);
  887.       }
  888.  
  889.    ReleaseProcSem ();
  890.  
  891.    /********************************************
  892.    * Fill In the window handle and device id
  893.    *********************************************/
  894.  
  895.  
  896.    pTempMCuePtEVCB->hwndCallback = pCueParms->hwndCallback;
  897.    pTempMCuePtEVCB->usDeviceID = ulpInstance->usWaveDeviceID;
  898.  
  899.    /********************************************
  900.    * Fill In Time event control block for a
  901.    * cue point ( all of these fields are REQUIRED)
  902.    * Note: We have altered the evcb to contain
  903.    * additional information (such as our callback
  904.    * userParm, instance etc.).  See audiomcd.h
  905.    * for an explanation of how this is done.
  906.    *********************************************/
  907.  
  908.    pTempMCuePtEVCB->evcb.ulType = EVENT_CUE_TIME;
  909.    pTempMCuePtEVCB->evcb.ulFlags = EVENT_SINGLE;
  910.    pTempMCuePtEVCB->evcb.hstream = ulpInstance->StreamInfo.hStream;
  911.  
  912.    /*********************************************
  913.    * Store the time at which the cue point
  914.    * is to be generated ( this must be in MMTIME
  915.    *********************************************/
  916.  
  917.    ulrc = ConvertToMM ( ulpInstance,
  918.                         &ulTempTime,
  919.                         pCueParms->ulCuepoint);
  920.  
  921.    pTempMCuePtEVCB->evcb.mmtimeStream = ulTempTime;
  922.  
  923.    /***************************************************
  924.    * Store the callback handle that the caller wishes
  925.    * the cuepoint notification to occur on.
  926.    * Remember each cuepoint can have its own callback.
  927.    ****************************************************/
  928.  
  929.    pTempMCuePtEVCB->mmCuePt = pCueParms->ulCuepoint;
  930.  
  931.    /*****************************************************
  932.    * Stick In INSTANCE Pointer in The Time EVCB, this will
  933.    * allow the event procedure to have access to our
  934.    * instance--it ordinarily would not have access to it.
  935.    * See comments in PlayEventProc and RecordEventProc.
  936.    ******************************************************/
  937.  
  938.    pTempMCuePtEVCB->ulpInstance = (ULONG) ulpInstance;
  939.  
  940.  
  941.    /*****************************************************
  942.    * Copy CuePoint User Parm into EVCB Structure
  943.    ******************************************************/
  944.    pTempMCuePtEVCB->usCueUsrParm =pCueParms->usUserParm;
  945.  
  946.    /*****************************************************
  947.    * Link this cue point into the list of cue points
  948.    ******************************************************/
  949.  
  950.    pTempMCuePtEVCB->pNextEVCB = CUEPOINT;
  951.    CUEPOINT = pTempMCuePtEVCB;
  952.  
  953.    /************************************************
  954.    * We can only enable events after a stream has
  955.    * been created--otherwise you will get errors.
  956.    * If we cannot enable the event right now, store
  957.    * this in a flag, and enable it before playback
  958.    * or record.
  959.    ************************************************/
  960.  
  961.    if (ulpInstance->ulCreateFlag == PREROLL_STATE)
  962.       {
  963.       ulrc = ADMCEnableEvent( (PEVCB) pTempMCuePtEVCB,
  964.                              (PHEVENT) &pTempMCuePtEVCB->HCuePtHndl );
  965.  
  966.       ulpInstance->usCuePt = EVENT_ENABLED;
  967.       }
  968.    else
  969.       {
  970.       ulpInstance->usCuePt = TRUE;
  971.       }
  972.  
  973.    return ( ulrc );
  974.  
  975. } /* CuePointAdd */
  976.  
  977.  
  978.  
  979.  
  980. /********************* START OF SPECIFICATIONS *********************
  981. *
  982. * SUBROUTINE NAME: CuePointDelete
  983. *
  984. * DESCRIPTIVE
  985. *
  986. * FUNCTION:  Removes cuepoint from linked list of cue points
  987. *
  988. * NOTES:
  989. *
  990. * ENTRY POINTS:
  991. *
  992. * INPUT:
  993. *
  994. * EXIT-NORMAL: Return Code 0.
  995. *
  996. * EXIT_ERROR:  Error Code.
  997. *
  998. * EFFECTS:
  999. *
  1000. * INTERNAL REFERENCES: MCIERR ().
  1001. *
  1002. * EXTERNAL REFERENCES:
  1003. *
  1004. *********************** END OF SPECIFICATIONS **********************/
  1005. RC CuePointDelete ( INSTANCE             *ulpInstance,
  1006.                     PMCI_CUEPOINT_PARMS pCueParms )
  1007.  
  1008. {
  1009.    MTIME_EVCB  *pTempMCuePtEVCB;         // temporary pointer to item in linked list
  1010.    MTIME_EVCB  *pPrevMCuePtEVCB;         // temporary pointer to item in linked list
  1011.  
  1012.    ULONG       ulFoundCuePoint = FALSE;  // Flag to indicate whether the cpt was found
  1013.    ULONG       ulrc = MCIERR_SUCCESS;    // @11889
  1014.  
  1015.    extern HHUGEHEAP     heap;                // Global MCD Heap
  1016.  
  1017.   /* If we have never enabled a cuepoint, we can't delete it */
  1018.  
  1019.   if ( !CUEPOINT )
  1020.      {
  1021.      return ( MCIERR_INVALID_CUEPOINT );
  1022.      }
  1023.  
  1024.   pTempMCuePtEVCB = pPrevMCuePtEVCB = CUEPOINT;
  1025.  
  1026.   /********************************************
  1027.   * Check to see if the cue point is already in
  1028.   * our linked list of cuepoints.  Continue
  1029.   * checking while we have a list and we have
  1030.   * not found the cuepoint.
  1031.   *********************************************/
  1032.  
  1033.   while ( pTempMCuePtEVCB && !ulFoundCuePoint )
  1034.     {
  1035.     if ( pTempMCuePtEVCB->mmCuePt == pCueParms->ulCuepoint)
  1036.        {
  1037.  
  1038.        /********************************************
  1039.        * If we found a cuepoint and the stream is
  1040.        * active, remove the cuepoint.  Simply
  1041.        * deleting it from our linked list is not
  1042.        * enough since the cuepoint will continue
  1043.        * to be reported until it is removed.
  1044.        ********************************************/
  1045.  
  1046.        if ( ulpInstance->usCuePt == EVENT_ENABLED )
  1047.  
  1048.           {
  1049.           /***********************************************
  1050.           * Check Validity of hCuePointEvent
  1051.           **********************************************/
  1052.           ulrc = ADMCDisableEvent ( pTempMCuePtEVCB->HCuePtHndl );
  1053.  
  1054.           } /* CreateFlag == PrerollState */
  1055.  
  1056.        ulFoundCuePoint = TRUE;
  1057.  
  1058.        /***********************************************
  1059.        * Ensure that the previous node points to the
  1060.        * next node.
  1061.        *********************************************/
  1062.  
  1063.        if ( pTempMCuePtEVCB != pPrevMCuePtEVCB )
  1064.           {
  1065.           pPrevMCuePtEVCB->pNextEVCB = pTempMCuePtEVCB->pNextEVCB;
  1066.           }
  1067.        else
  1068.           {
  1069.           /***********************************************
  1070.           * If we are deleting the first item in the list
  1071.           * ensure that we have a valid initial pointer
  1072.           **********************************************/
  1073.  
  1074.           CUEPOINT = pTempMCuePtEVCB->pNextEVCB;
  1075.           }
  1076.  
  1077.        /* Toast the node to delete */
  1078.  
  1079.        CleanUp( pTempMCuePtEVCB );
  1080.  
  1081.  
  1082.        } /* Found the CuePoint Block */
  1083.  
  1084.     /**********************************************
  1085.     * Else we didn't find the requested cue point
  1086.     * so advance a node
  1087.     **********************************************/
  1088.  
  1089.     else
  1090.        {
  1091.        if ( pTempMCuePtEVCB != pPrevMCuePtEVCB )
  1092.           {
  1093.           pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  1094.           pPrevMCuePtEVCB = pPrevMCuePtEVCB->pNextEVCB;
  1095.           }
  1096.        else
  1097.           {
  1098.           pTempMCuePtEVCB = pTempMCuePtEVCB->pNextEVCB;
  1099.           }
  1100.  
  1101.        } /* else we haven't found the requested cue point */
  1102.  
  1103.     } /* endwhile */
  1104.  
  1105.     /* If we couldn't find the cuepoint--report the error */
  1106.  
  1107.     if ( ulFoundCuePoint == FALSE)
  1108.        {
  1109.        return ( MCIERR_INVALID_CUEPOINT );
  1110.        }
  1111.  
  1112.     return ( ulrc );
  1113.  
  1114. } /* CuePointDelete */
  1115.  
  1116.  
  1117.