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 >
Wrap
C/C++ Source or Header
|
1993-04-12
|
17KB
|
561 lines
/********************* 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 */