home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / mmpm2tk / mmpmtlk2 / admct / admcplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  37.4 KB  |  1,171 lines

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