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

  1. /********************* START OF SPECIFICATIONS *********************
  2. *
  3. * SUBROUTINE NAME: ADMCSAVE.c
  4. *
  5. * DESCRIPTIVE NAME: Audio MCD WaveAudio Save Routines
  6. *
  7. *              Copyright (c) IBM Corporation  1991, 1993
  8. *                        All Rights Reserved
  9. *
  10. *
  11. * FUNCTION:Save an Waveform Audio Element.
  12. *
  13. *  MCI_SAVE is not a required command, however, if a streaming MCD takes
  14. *  advantage of temporary files, then it should use MCI_SAVE.
  15. *
  16. *
  17. * NOTES:
  18. *
  19. *
  20. *********************** END OF SPECIFICATIONS **********************/
  21.  
  22. #define INCL_DOSSEMAPHORES
  23. #define INCL_DOSPROCESS
  24. #define INCL_ERRORS
  25.  
  26. #include <os2.h>                        // OS2 defines.
  27. #include <string.h>                     // String functions.
  28. #include <os2medef.h>                   // MME includes files.
  29. #include <audio.h>                      // Audio Device Defines.
  30. #include <ssm.h>                        // SSM spi includes.
  31. #include <meerror.h>                    // MM Error Messages.
  32. #include <mmioos2.h>                    // MMIO Include.
  33. #include <mcios2.h>                     // MM System Include.
  34. #include <mmdrvos2.h>                     // MCI Driver Include.
  35. #include <mcd.h>                        // AudioIFDriverInterface.
  36. #include <hhpheap.h>                    // Heap Manager Definitions
  37. #include <qos.h>
  38. #include <audiomcd.h>                   // Component Definitions
  39. #include "admcfunc.h"                   // Function Prototypes
  40.  
  41.  
  42. /********************* START OF SPECIFICATIONS *********************
  43. *
  44. * SUBROUTINE NAME: MCISAVEFILE
  45. *
  46. * DESCRIPTIVE      Audio MCD Save File.
  47. *
  48. * FUNCTION:  Save Existing element to desired format.
  49. *            This function first ensures that the flags are vaild.
  50. *            Then it ensures that all pointers point to valid memory.
  51. *            If any operations are currently active, they are then
  52. *            aborted.
  53. *            Finally, the save operation itself is then done.
  54. *
  55. * NOTES: This function illustrates how to use the mmioSendMessage
  56. *        API to save a file.  It also explains when/why one would
  57. *        want to spawn a thread for an operation.  Finally, it shows
  58. *        how to smoothly interrupt a previous operation.
  59. *
  60. * ENTRY POINTS:
  61. *
  62. * INPUT: MCI_SAVE message.
  63. *
  64. * EXIT-NORMAL: MCIERR_SUCCESS
  65. *
  66. * EXIT_ERROR:  Error Code.
  67. *
  68. * EFFECTS:
  69. *
  70. * INTERNAL REFERENCES:  StartSave.
  71. *                       PostMDMMessage
  72. *
  73. * EXTERNAL REFERENCES:  DosWaitEventSem
  74. *                       DosResetEventSem
  75. *                       DosCreateThread
  76. *
  77. *********************** END OF SPECIFICATIONS **********************/
  78. RC  MCISaveFile (FUNCTION_PARM_BLOCK * pFuncBlock)
  79. {
  80.   ULONG             ulrc;              // Error Value
  81.   ULONG             ulParam1;
  82.   ULONG             ulCheckFlags;
  83.   ULONG             ulCnt;
  84.   ULONG             ulAbortNotify = 0; // whether or not to abort a command
  85.  
  86.   INSTANCE          *ulpInstance;      // Local Instance
  87.   PMCI_SAVE_PARMS   pSaveParms;       // Msg Data
  88.  
  89.   PSZ               pszSaveName;
  90.  
  91.   /*****************************************
  92.   * Initialize some variables
  93.   *****************************************/
  94.  
  95.   ulParam1 =    pFuncBlock->ulParam1;
  96.   pSaveParms = (PMCI_SAVE_PARMS) pFuncBlock->ulParam2;
  97.   ulpInstance = (INSTANCE *) pFuncBlock->ulpInstance;
  98.  
  99.   /*****************************************
  100.   * Ensure that the MCI_SAVE_PARMS contain
  101.   * valid memory.
  102.   *****************************************/
  103.  
  104.   ulrc = CheckMem ( (PVOID)pSaveParms,
  105.                     sizeof (MCI_SAVE_PARMS),
  106.                     PAG_READ);
  107.  
  108.   if (ulrc != MCIERR_SUCCESS)
  109.      {
  110.      return ( MCIERR_MISSING_PARAMETER );
  111.      }
  112.  
  113.  
  114.   ulCheckFlags = ulParam1;
  115.  
  116.   ulCheckFlags &= ~( MCI_WAIT + MCI_NOTIFY + MCI_SAVE_FILE);
  117.  
  118.   /*****************************************
  119.   * The save routine only permits MCI_WAIT,
  120.   * MCI_NOTIFY + MCI_SAVE_FILE.  If any other
  121.   * flags are passed in, then return an error
  122.   ******************************************/
  123.  
  124.   if (ulCheckFlags > 0)
  125.      {
  126.      return ( MCIERR_INVALID_FLAG );
  127.      }
  128.  
  129.   /********************************************
  130.   * Check to see if the IO Proc we have loaded
  131.   * has the ability to save files.  The riff
  132.   * wave proc does, but others (like the AVC
  133.   * IO Proc) do not.
  134.   ********************************************/
  135.  
  136.   if ( !ulpInstance->ulCapabilities & CAN_SAVE )
  137.     {
  138.     return (MCIERR_UNSUPPORTED_FUNCTION);
  139.     }
  140.  
  141.   /* If no file is loaded, a save is impossible */
  142.  
  143.   if ( ulpInstance->fFileExists != TRUE )
  144.      {
  145.      return (MCIERR_FILE_NOT_FOUND);
  146.      }
  147.  
  148.   /*********************************************
  149.   * If temp files are not active, then all the
  150.   * changes have been made to the actual file
  151.   * and a save is not practical nor necessary
  152.   **********************************************/
  153.  
  154.   if ( !ulpInstance->ulUsingTemp )
  155.     {
  156.     return (MCIERR_UNSUPPORTED_FUNCTION);
  157.     }
  158.  
  159.  
  160.   /* Check to see if the user passed in a filename */
  161.  
  162.   if ( ulParam1 & MCI_SAVE_FILE )
  163.     {
  164.     /*****************************************
  165.     * Ensure that they passed a valid pointer
  166.     *****************************************/
  167.  
  168.     ulrc = CheckMem ( (PVOID) pSaveParms->pszFileName,
  169.                       1,
  170.                       PAG_READ ) ;
  171.  
  172.     if (ulrc != MCIERR_SUCCESS)
  173.         return (MCIERR_MISSING_PARAMETER);
  174.  
  175.     /* Create a local copy of the pointer */
  176.  
  177.     pszSaveName = (PSZ) pSaveParms->pszFileName;
  178.     }
  179.   else
  180.     {
  181.  
  182.     /*****************************************
  183.     * If the caller had us generate a filename
  184.     * on the open, then save w/o a new filename
  185.     * is invalid
  186.     *****************************************/
  187.     if  ( ulpInstance->ulCreatedName )
  188.        {
  189.        return ( MCIERR_MISSING_FLAG );
  190.        }
  191.  
  192.     pszSaveName = NULL;
  193.     }
  194.  
  195.  
  196.  
  197.  
  198.    /*****************************************
  199.    * To ensure proper syncronization, acquire
  200.    * the semaphore which is used to control
  201.    * who can check to see which processes are
  202.    * active. This function will also tell us
  203.    * if there is an operation to abort or
  204.    * supercede.
  205.    ******************************************/
  206.  
  207.    GetNotifyAbortAccess ( ulpInstance, &ulAbortNotify );
  208.  
  209.     /**********************************************************
  210.     * If there other commands alive (such as a play/save or
  211.     * record, then they should be aborted by the save command
  212.     * To abort the command it is necessary to post a message
  213.     * a stop the stream
  214.     ***********************************************************/
  215.     if ( ulAbortNotify )
  216.  
  217.       {
  218.       /* Stop any commands in progress */
  219.  
  220.       GenericThreadAbort( ulpInstance, pFuncBlock, 0 );
  221.  
  222.       /************************************************
  223.       * Ensure that no other threads think an operation
  224.       * is active by setting a flag.
  225.       *************************************************/
  226.  
  227.       ulpInstance->usNotifyPending = FALSE;
  228.  
  229.     }
  230.  
  231.   /*****************************************
  232.   * If the stream is in a state where a stop
  233.   * is required (i.e. buffers have not been
  234.   * flush to the disk) then stop the stream
  235.   ******************************************/
  236.  
  237.   if ( STRMSTATE != MCI_STOP )
  238.       {
  239.       ulrc = SpiStopStream (STREAM.hStream, SPI_STOP_DISCARD );
  240.  
  241.         if (!ulrc)
  242.           {
  243.           DosWaitEventSem (ulpInstance->hEventSem, (ULONG) ONE_MINUTE );
  244.           }
  245.  
  246.       } /* If stream is not in stopped state */
  247.  
  248.  
  249.  
  250.   /************************************************
  251.   * If the caller used the MCI_WAIT flag, then all
  252.   * of the processing can be done on one thread.
  253.   ************************************************/
  254.   if ( ulParam1 & MCI_WAIT )
  255.  
  256.     {
  257.     // investigate--change to fWaitPending
  258.  
  259.     ulpInstance->usWaitPending = TRUE;
  260.     ulpInstance->usWaitMsg= MCI_SAVE;
  261.  
  262.     ulrc = StartSave (pFuncBlock);
  263.  
  264.     ulpInstance->usWaitPending = FALSE;
  265.  
  266.     }
  267.   else
  268.     /***************************************************
  269.     ** To determine whether or not an operation must be
  270.     ** done on a thread, use the following criteria:
  271.     **
  272.     **   A. Will the operation take a long time.
  273.     **   B. Is there any way to make it appear as if
  274.     **      a thread was active.
  275.     **
  276.     **  In the case of a save, it can potentially be a
  277.     **  LONG operation and we do not want to bully the
  278.     **  applications thread, therefore,
  279.     **
  280.     ** We must perform the save on a thread since
  281.     ** notify was requested (note, if neither notify
  282.     ** or wait are specified, then operate like a notify
  283.     ** except without positing the message.
  284.     ****************************************************/
  285.  
  286.     {
  287.     /* Let other threads know that a save is about to start */
  288.  
  289.     ulpInstance->usNotifyPending = TRUE;
  290.     ulpInstance->usNotPendingMsg = MCI_SAVE;
  291.  
  292.     /********************************************
  293.     * Save thread will post a semaphore when it
  294.     * safe to do processing, so reset it,
  295.     * start the thread, and wait till its safe
  296.     * to go on.
  297.     ********************************************/
  298.  
  299.     DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
  300.  
  301.     ulrc = _beginthread ( (PFNTHREAD)StartSave,
  302.                           0,
  303.                           NOTIFY_THREAD_STACKSIZE,
  304.                           (ULONG) pFuncBlock );
  305.  
  306.     /*************************************************
  307.     * Wait for the save thread to indicate that it is
  308.     * safe to continue.
  309.     **************************************************/
  310.     if ( ulrc != -1 )
  311.        {
  312.        DosWaitEventSem (ulpInstance->hThreadSem, -1);
  313.        ulrc = MCIERR_SUCCESS;
  314.        }
  315.     else
  316.        {
  317.        ulrc = MCIERR_OUT_OF_MEMORY;
  318.        }
  319.  
  320.     } /* this call is not a wait */
  321.  
  322.     DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
  323.  
  324.     /* Ensure that we are in stopped state after a save */
  325.  
  326.     STRMSTATE = MCI_STOP;
  327.  
  328.     /* Remove any undo nodes if they were allocated */
  329.   
  330.     RemoveUndoNodes( ulpInstance );
  331.  
  332.     return ( ulrc );
  333.  
  334. } /* MCISaveFile */
  335.  
  336.  
  337.  
  338. /********************* START OF SPECIFICATIONS *******************************
  339. *
  340. * SUBROUTINE NAME: StartSave.
  341. *
  342. * DESCRIPTIVE NAME: Saves a file using mmio message MMIOM_SAVE
  343. *
  344. * FUNCTION:
  345. *
  346. *
  347. * NOTES: This routine is called using  a separate thread spawned by
  348. *        MCD on MCI Notify.
  349. *
  350. * ENTRY POINTS:
  351. *
  352. * INPUT:
  353. *
  354. * EXIT-NORMAL: Return Code 0.
  355. *
  356. * EXIT_ERROR:  Error Code.
  357. *
  358. * EFFECTS:
  359. *
  360. * INTERNAL REFERENCES: None
  361. *
  362. * EXTERNAL REFERENCES: mmioSendMessage
  363. *                      mmioGetLastError
  364. *                      DosDelete
  365. *
  366. *********************** END OF SPECIFICATIONS *******************************/
  367. RC StartSave (FUNCTION_PARM_BLOCK *pFuncBlockCopy )
  368. {
  369.  
  370.    ULONG               ulrc = MCIERR_SUCCESS;
  371.    ULONG               ulErr = MCI_NOTIFY_SUCCESSFUL;
  372.    ULONG               ulParam1;
  373.  
  374.    INSTANCE            *ulpInstance;
  375.  
  376.    PMCI_SAVE_PARMS    pSaveParms;
  377.  
  378.    CHAR                chSaveName[ CCHMAXPATH ];
  379.    PSZ                 pszSaveName;
  380.  
  381.   FUNCTION_PARM_BLOCK  FuncBlock;
  382.  
  383.   memmove( &FuncBlock, pFuncBlockCopy, sizeof( FUNCTION_PARM_BLOCK ) );
  384.  
  385.  
  386.    /* Initialize some variable */
  387.  
  388.    ulpInstance = (INSTANCE *) FuncBlock.ulpInstance;
  389.    pSaveParms = (PMCI_SAVE_PARMS) FuncBlock.ulParam2;
  390.    ulParam1    = FuncBlock.ulParam1;
  391.  
  392.    /***************************************************
  393.    * If a notify thread passed the filename pointer,
  394.    * we must save the string since that thread could
  395.    * return before we finish processing and the pointer
  396.    * may no longer be valid.
  397.    ***************************************************/
  398.  
  399.    if ( ulParam1 & MCI_SAVE_FILE )
  400.       {
  401.       strcpy( chSaveName, ( PSZ ) pSaveParms->pszFileName );
  402.       pszSaveName = (PSZ) chSaveName;
  403.       }
  404.    else
  405.       {
  406.       pszSaveName = NULL;
  407.       }
  408.  
  409.    /*********************************************
  410.    * We can free the save thread now that we have
  411.    * obtained any possible file names
  412.    **********************************************/
  413.  
  414.    DosPostEventSem ( ulpInstance->hThreadSem );
  415.  
  416.  
  417.    /**********************************************
  418.    * This call illustrates the use of the
  419.    * mmioSendMessage.  We are requesting that the
  420.    * IO Proc that is currently loaded save all of
  421.    * the changes that have been done to the file.
  422.    ***********************************************/
  423.  
  424.    ulrc = mmioSendMessage( ulpInstance->hmmio,
  425.                            MMIOM_SAVE,
  426.                            (LONG) pszSaveName,
  427.                            0 );
  428.  
  429.    /*********************************************
  430.    * If there were no errors, then the filename the
  431.    * caller requested is the default file name
  432.    **********************************************/
  433.  
  434.    if ( ulParam1 & MCI_SAVE_FILE && !ulrc )
  435.       {
  436.       /* If we created a temp file, it is our duty to remove it */
  437.  
  438.       if ( ulpInstance->ulCreatedName )
  439.          {
  440.          DosDelete( ( PSZ ) ulpInstance->pszAudioFile );
  441.          }
  442.  
  443.       /***************************************
  444.       * Keep the name of the new file.  This
  445.       * will be useful if the caller does an
  446.       * MCI_INFO for the filename.
  447.       ***************************************/
  448.  
  449.       strcpy( ( PSZ ) ulpInstance->pszAudioFile,
  450.                chSaveName );
  451.  
  452.       }
  453.  
  454.    /**************************************************
  455.    * Set flag which indicates that we did not create
  456.    * the current element.  This flag is used by the
  457.    * close and load routines to determine whether or
  458.    * not it is necessary to remove a file that the
  459.    * mcd created.
  460.    **************************************************/
  461.  
  462.    ulpInstance->ulCreatedName = FALSE;
  463.  
  464.  
  465.  
  466.    /**********************************************
  467.    * If an error occurred, then inform  the caller
  468.    * of the problem.
  469.    **********************************************/
  470.  
  471.    if ( ulrc )
  472.       {
  473.       /******************************************
  474.       * Right now, we just know what error
  475.       * occurred, mmioGetLastError will give
  476.       * us more details on exactly what happened
  477.       ******************************************/
  478.  
  479.       ulErr = mmioGetLastError( ulpInstance->hmmio );
  480.  
  481.       /*********************************
  482.       * If the path is not valid return
  483.       * file not found
  484.       *********************************/
  485.  
  486.       if ( ulErr == ERROR_FILE_NOT_FOUND ||
  487.            ulErr == ERROR_PATH_NOT_FOUND ||
  488.            ulErr == ERROR_INVALID_DRIVE)
  489.          {
  490.          ulErr = MCIERR_FILE_NOT_FOUND;
  491.          }
  492.  
  493.       /*******************************************
  494.       * CANNOT_WRITE comes back when there is no
  495.       * disk space
  496.       ********************************************/
  497.  
  498.       else if ( ulErr == MMIOERR_CANNOTWRITE )
  499.          {
  500.          ulErr = MCIERR_TARGET_DEVICE_FULL;
  501.          }
  502.  
  503.       /*******************************************
  504.       * File attribute errors can happen when
  505.       * one writes to a readonly device (like a CD)
  506.       * or a readonly file etc.
  507.       ********************************************/
  508.  
  509.       else if ( ulErr == ERROR_ACCESS_DENIED ||
  510.                 ulErr == ERROR_SHARING_VIOLATION  )
  511.          {
  512.          ulErr = MCIERR_FILE_ATTRIBUTE;
  513.          }
  514.  
  515.       /* If notify, send message to application */
  516.  
  517.       if (ulParam1 & MCI_NOTIFY)
  518.          {
  519.  
  520.          PostMDMMessage (ulErr, MCI_SAVE, &FuncBlock);
  521.          }
  522.  
  523.       /* else return to caller with error */
  524.  
  525.       else
  526.          {
  527.  
  528.          return ( ulErr );
  529.          }
  530.       }
  531.  
  532.    else if (ulParam1 & MCI_NOTIFY)
  533.       {
  534.       PostMDMMessage (ulErr, MCI_SAVE, &FuncBlock);
  535.       }
  536.  
  537.  
  538.    /* If this call was done with a wait, we are done */
  539.  
  540.    if ( ulParam1 & MCI_WAIT )
  541.       {
  542.       return ( MCIERR_SUCCESS );
  543.       }
  544.  
  545.  
  546.    /*********************************************
  547.    * If any operation sees that the save thread
  548.    * is still processing, they will wait on the
  549.    * thread semaphore.  Since we are done with
  550.    * save processing post the semaphore so
  551.    * waiting threads can continue.
  552.    *********************************************/
  553.  
  554.    ulpInstance->usNotifyPending = FALSE;
  555.    DosPostEventSem ( ulpInstance->hThreadSem );
  556.  
  557.    return ( ulErr );
  558.  
  559. } /* Start Save */
  560.  
  561.