home *** CD-ROM | disk | FTP | other *** search
- /********************* START OF SPECIFICATIONS *********************
- *
- * SUBROUTINE NAME: ADMCSAVE.c
- *
- * DESCRIPTIVE NAME: Audio MCD WaveAudio Save Routines
- *
- * Copyright (c) IBM Corporation 1991, 1993
- * All Rights Reserved
- *
- *
- * FUNCTION:Save an Waveform Audio Element.
- *
- * MCI_SAVE is not a required command, however, if a streaming MCD takes
- * advantage of temporary files, then it should use MCI_SAVE.
- *
- *
- * NOTES:
- *
- *
- *********************** END OF SPECIFICATIONS **********************/
-
- #define INCL_DOSSEMAPHORES
- #define INCL_DOSPROCESS
- #define INCL_ERRORS
-
- #include <os2.h> // OS2 defines.
- #include <string.h> // String functions.
- #include <os2medef.h> // MME includes files.
- #include <audio.h> // Audio Device Defines.
- #include <ssm.h> // SSM spi includes.
- #include <meerror.h> // MM Error Messages.
- #include <mmioos2.h> // MMIO Include.
- #include <mcios2.h> // MM System Include.
- #include <mmdrvos2.h> // MCI Driver Include.
- #include <mcd.h> // AudioIFDriverInterface.
- #include <hhpheap.h> // Heap Manager Definitions
- #include <qos.h>
- #include <audiomcd.h> // Component Definitions
- #include "admcfunc.h" // Function Prototypes
-
-
- /********************* START OF SPECIFICATIONS *********************
- *
- * SUBROUTINE NAME: MCISAVEFILE
- *
- * DESCRIPTIVE Audio MCD Save File.
- *
- * FUNCTION: Save Existing element to desired format.
- * This function first ensures that the flags are vaild.
- * Then it ensures that all pointers point to valid memory.
- * If any operations are currently active, they are then
- * aborted.
- * Finally, the save operation itself is then done.
- *
- * NOTES: This function illustrates how to use the mmioSendMessage
- * API to save a file. It also explains when/why one would
- * want to spawn a thread for an operation. Finally, it shows
- * how to smoothly interrupt a previous operation.
- *
- * ENTRY POINTS:
- *
- * INPUT: MCI_SAVE message.
- *
- * EXIT-NORMAL: MCIERR_SUCCESS
- *
- * EXIT_ERROR: Error Code.
- *
- * EFFECTS:
- *
- * INTERNAL REFERENCES: StartSave.
- * PostMDMMessage
- *
- * EXTERNAL REFERENCES: DosWaitEventSem
- * DosResetEventSem
- * DosCreateThread
- *
- *********************** END OF SPECIFICATIONS **********************/
- RC MCISaveFile (FUNCTION_PARM_BLOCK * pFuncBlock)
- {
- ULONG ulrc; // Error Value
- ULONG ulParam1;
- ULONG ulCheckFlags;
- ULONG ulCnt;
- ULONG ulAbortNotify = 0; // whether or not to abort a command
-
- INSTANCE *ulpInstance; // Local Instance
- PMCI_SAVE_PARMS pSaveParms; // Msg Data
-
- PSZ pszSaveName;
-
- /*****************************************
- * Initialize some variables
- *****************************************/
-
- ulParam1 = pFuncBlock->ulParam1;
- pSaveParms = (PMCI_SAVE_PARMS) pFuncBlock->ulParam2;
- ulpInstance = (INSTANCE *) pFuncBlock->ulpInstance;
-
- /*****************************************
- * Ensure that the MCI_SAVE_PARMS contain
- * valid memory.
- *****************************************/
-
- ulrc = CheckMem ( (PVOID)pSaveParms,
- sizeof (MCI_SAVE_PARMS),
- PAG_READ);
-
- if (ulrc != MCIERR_SUCCESS)
- {
- return ( MCIERR_MISSING_PARAMETER );
- }
-
-
- ulCheckFlags = ulParam1;
-
- ulCheckFlags &= ~( MCI_WAIT + MCI_NOTIFY + MCI_SAVE_FILE);
-
- /*****************************************
- * The save routine only permits MCI_WAIT,
- * MCI_NOTIFY + MCI_SAVE_FILE. If any other
- * flags are passed in, then return an error
- ******************************************/
-
- if (ulCheckFlags > 0)
- {
- return ( MCIERR_INVALID_FLAG );
- }
-
- /********************************************
- * Check to see if the IO Proc we have loaded
- * has the ability to save files. The riff
- * wave proc does, but others (like the AVC
- * IO Proc) do not.
- ********************************************/
-
- if ( !ulpInstance->ulCapabilities & CAN_SAVE )
- {
- return (MCIERR_UNSUPPORTED_FUNCTION);
- }
-
- /* If no file is loaded, a save is impossible */
-
- if ( ulpInstance->fFileExists != TRUE )
- {
- return (MCIERR_FILE_NOT_FOUND);
- }
-
- /*********************************************
- * If temp files are not active, then all the
- * changes have been made to the actual file
- * and a save is not practical nor necessary
- **********************************************/
-
- if ( !ulpInstance->ulUsingTemp )
- {
- return (MCIERR_UNSUPPORTED_FUNCTION);
- }
-
-
- /* Check to see if the user passed in a filename */
-
- if ( ulParam1 & MCI_SAVE_FILE )
- {
- /*****************************************
- * Ensure that they passed a valid pointer
- *****************************************/
-
- ulrc = CheckMem ( (PVOID) pSaveParms->pszFileName,
- 1,
- PAG_READ ) ;
-
- if (ulrc != MCIERR_SUCCESS)
- return (MCIERR_MISSING_PARAMETER);
-
- /* Create a local copy of the pointer */
-
- pszSaveName = (PSZ) pSaveParms->pszFileName;
- }
- else
- {
-
- /*****************************************
- * If the caller had us generate a filename
- * on the open, then save w/o a new filename
- * is invalid
- *****************************************/
- if ( ulpInstance->ulCreatedName )
- {
- return ( MCIERR_MISSING_FLAG );
- }
-
- pszSaveName = NULL;
- }
-
-
-
-
- /*****************************************
- * To ensure proper syncronization, acquire
- * the semaphore which is used to control
- * who can check to see which processes are
- * active. This function will also tell us
- * if there is an operation to abort or
- * supercede.
- ******************************************/
-
- GetNotifyAbortAccess ( ulpInstance, &ulAbortNotify );
-
- /**********************************************************
- * If there other commands alive (such as a play/save or
- * record, then they should be aborted by the save command
- * To abort the command it is necessary to post a message
- * a stop the stream
- ***********************************************************/
- if ( ulAbortNotify )
-
- {
- /* Stop any commands in progress */
-
- GenericThreadAbort( ulpInstance, pFuncBlock, 0 );
-
- /************************************************
- * Ensure that no other threads think an operation
- * is active by setting a flag.
- *************************************************/
-
- ulpInstance->usNotifyPending = FALSE;
-
- }
-
- /*****************************************
- * If the stream is in a state where a stop
- * is required (i.e. buffers have not been
- * flush to the disk) then stop the stream
- ******************************************/
-
- if ( STRMSTATE != MCI_STOP )
- {
- ulrc = SpiStopStream (STREAM.hStream, SPI_STOP_DISCARD );
-
- if (!ulrc)
- {
- DosWaitEventSem (ulpInstance->hEventSem, (ULONG) ONE_MINUTE );
- }
-
- } /* If stream is not in stopped state */
-
-
-
- /************************************************
- * If the caller used the MCI_WAIT flag, then all
- * of the processing can be done on one thread.
- ************************************************/
- if ( ulParam1 & MCI_WAIT )
-
- {
- // investigate--change to fWaitPending
-
- ulpInstance->usWaitPending = TRUE;
- ulpInstance->usWaitMsg= MCI_SAVE;
-
- ulrc = StartSave (pFuncBlock);
-
- ulpInstance->usWaitPending = FALSE;
-
- }
- else
- /***************************************************
- ** To determine whether or not an operation must be
- ** done on a thread, use the following criteria:
- **
- ** A. Will the operation take a long time.
- ** B. Is there any way to make it appear as if
- ** a thread was active.
- **
- ** In the case of a save, it can potentially be a
- ** LONG operation and we do not want to bully the
- ** applications thread, therefore,
- **
- ** We must perform the save on a thread since
- ** notify was requested (note, if neither notify
- ** or wait are specified, then operate like a notify
- ** except without positing the message.
- ****************************************************/
-
- {
- /* Let other threads know that a save is about to start */
-
- ulpInstance->usNotifyPending = TRUE;
- ulpInstance->usNotPendingMsg = MCI_SAVE;
-
- /********************************************
- * Save thread will post a semaphore when it
- * safe to do processing, so reset it,
- * start the thread, and wait till its safe
- * to go on.
- ********************************************/
-
- DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
-
- ulrc = _beginthread ( (PFNTHREAD)StartSave,
- 0,
- NOTIFY_THREAD_STACKSIZE,
- (ULONG) pFuncBlock );
-
- /*************************************************
- * Wait for the save thread to indicate that it is
- * safe to continue.
- **************************************************/
- if ( ulrc != -1 )
- {
- DosWaitEventSem (ulpInstance->hThreadSem, -1);
- ulrc = MCIERR_SUCCESS;
- }
- else
- {
- ulrc = MCIERR_OUT_OF_MEMORY;
- }
-
- } /* this call is not a wait */
-
- DosResetEventSem (ulpInstance->hThreadSem, &ulCnt);
-
- /* Ensure that we are in stopped state after a save */
-
- STRMSTATE = MCI_STOP;
-
- /* Remove any undo nodes if they were allocated */
-
- RemoveUndoNodes( ulpInstance );
-
- return ( ulrc );
-
- } /* MCISaveFile */
-
-
-
- /********************* START OF SPECIFICATIONS *******************************
- *
- * SUBROUTINE NAME: StartSave.
- *
- * DESCRIPTIVE NAME: Saves a file using mmio message MMIOM_SAVE
- *
- * FUNCTION:
- *
- *
- * NOTES: This routine is called using a separate thread spawned by
- * MCD on MCI Notify.
- *
- * ENTRY POINTS:
- *
- * INPUT:
- *
- * EXIT-NORMAL: Return Code 0.
- *
- * EXIT_ERROR: Error Code.
- *
- * EFFECTS:
- *
- * INTERNAL REFERENCES: None
- *
- * EXTERNAL REFERENCES: mmioSendMessage
- * mmioGetLastError
- * DosDelete
- *
- *********************** END OF SPECIFICATIONS *******************************/
- RC StartSave (FUNCTION_PARM_BLOCK *pFuncBlockCopy )
- {
-
- ULONG ulrc = MCIERR_SUCCESS;
- ULONG ulErr = MCI_NOTIFY_SUCCESSFUL;
- ULONG ulParam1;
-
- INSTANCE *ulpInstance;
-
- PMCI_SAVE_PARMS pSaveParms;
-
- CHAR chSaveName[ CCHMAXPATH ];
- PSZ pszSaveName;
-
- FUNCTION_PARM_BLOCK FuncBlock;
-
- memmove( &FuncBlock, pFuncBlockCopy, sizeof( FUNCTION_PARM_BLOCK ) );
-
-
- /* Initialize some variable */
-
- ulpInstance = (INSTANCE *) FuncBlock.ulpInstance;
- pSaveParms = (PMCI_SAVE_PARMS) FuncBlock.ulParam2;
- ulParam1 = FuncBlock.ulParam1;
-
- /***************************************************
- * If a notify thread passed the filename pointer,
- * we must save the string since that thread could
- * return before we finish processing and the pointer
- * may no longer be valid.
- ***************************************************/
-
- if ( ulParam1 & MCI_SAVE_FILE )
- {
- strcpy( chSaveName, ( PSZ ) pSaveParms->pszFileName );
- pszSaveName = (PSZ) chSaveName;
- }
- else
- {
- pszSaveName = NULL;
- }
-
- /*********************************************
- * We can free the save thread now that we have
- * obtained any possible file names
- **********************************************/
-
- DosPostEventSem ( ulpInstance->hThreadSem );
-
-
- /**********************************************
- * This call illustrates the use of the
- * mmioSendMessage. We are requesting that the
- * IO Proc that is currently loaded save all of
- * the changes that have been done to the file.
- ***********************************************/
-
- ulrc = mmioSendMessage( ulpInstance->hmmio,
- MMIOM_SAVE,
- (LONG) pszSaveName,
- 0 );
-
- /*********************************************
- * If there were no errors, then the filename the
- * caller requested is the default file name
- **********************************************/
-
- if ( ulParam1 & MCI_SAVE_FILE && !ulrc )
- {
- /* If we created a temp file, it is our duty to remove it */
-
- if ( ulpInstance->ulCreatedName )
- {
- DosDelete( ( PSZ ) ulpInstance->pszAudioFile );
- }
-
- /***************************************
- * Keep the name of the new file. This
- * will be useful if the caller does an
- * MCI_INFO for the filename.
- ***************************************/
-
- strcpy( ( PSZ ) ulpInstance->pszAudioFile,
- chSaveName );
-
- }
-
- /**************************************************
- * Set flag which indicates that we did not create
- * the current element. This flag is used by the
- * close and load routines to determine whether or
- * not it is necessary to remove a file that the
- * mcd created.
- **************************************************/
-
- ulpInstance->ulCreatedName = FALSE;
-
-
-
- /**********************************************
- * If an error occurred, then inform the caller
- * of the problem.
- **********************************************/
-
- if ( ulrc )
- {
- /******************************************
- * Right now, we just know what error
- * occurred, mmioGetLastError will give
- * us more details on exactly what happened
- ******************************************/
-
- ulErr = mmioGetLastError( ulpInstance->hmmio );
-
- /*********************************
- * If the path is not valid return
- * file not found
- *********************************/
-
- if ( ulErr == ERROR_FILE_NOT_FOUND ||
- ulErr == ERROR_PATH_NOT_FOUND ||
- ulErr == ERROR_INVALID_DRIVE)
- {
- ulErr = MCIERR_FILE_NOT_FOUND;
- }
-
- /*******************************************
- * CANNOT_WRITE comes back when there is no
- * disk space
- ********************************************/
-
- else if ( ulErr == MMIOERR_CANNOTWRITE )
- {
- ulErr = MCIERR_TARGET_DEVICE_FULL;
- }
-
- /*******************************************
- * File attribute errors can happen when
- * one writes to a readonly device (like a CD)
- * or a readonly file etc.
- ********************************************/
-
- else if ( ulErr == ERROR_ACCESS_DENIED ||
- ulErr == ERROR_SHARING_VIOLATION )
- {
- ulErr = MCIERR_FILE_ATTRIBUTE;
- }
-
- /* If notify, send message to application */
-
- if (ulParam1 & MCI_NOTIFY)
- {
-
- PostMDMMessage (ulErr, MCI_SAVE, &FuncBlock);
- }
-
- /* else return to caller with error */
-
- else
- {
-
- return ( ulErr );
- }
- }
-
- else if (ulParam1 & MCI_NOTIFY)
- {
- PostMDMMessage (ulErr, MCI_SAVE, &FuncBlock);
- }
-
-
- /* If this call was done with a wait, we are done */
-
- if ( ulParam1 & MCI_WAIT )
- {
- return ( MCIERR_SUCCESS );
- }
-
-
- /*********************************************
- * If any operation sees that the save thread
- * is still processing, they will wait on the
- * thread semaphore. Since we are done with
- * save processing post the semaphore so
- * waiting threads can continue.
- *********************************************/
-
- ulpInstance->usNotifyPending = FALSE;
- DosPostEventSem ( ulpInstance->hThreadSem );
-
- return ( ulErr );
-
- } /* Start Save */
-
-