home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
mmpm21tk.zip
/
TK
/
ADMCT
/
LOADSUBS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-05
|
37KB
|
1,336 lines
/********************* STARTOF SPECIFICATIONS *********************
*
* SUBROUTINE NAME: LOADSUBS.C
*
* DESCRIPTIVE NAME: Audio MCD Load subroutine file.
*
* Copyright (c) IBM Corporation 1991, 1993
* All Rights Reserved
*
* FUNCTION: Contain subroutines for MCI_LOAD/MCI_OPEN.
*
* NOTES: Concepts illustrated in this source module.
*
* A. Creating temporary filenames (CheckForValidElement)
* B. Aborting in process commands (LoadAbortNotify)
* C. Processing the OPEN_MMIO flag (OpenHandle)
* D. Rational as to when to open the card in record or
* playback mode (OpenHandle) (ProcessElement).
* E. Processing temp files (ProcessElement).
* F. Opening a file with MMIO (ProcessElement).
* G. Processing the MCI_READ_ONLY flag (ProcessElement).
* H. Creating a temporary file ( SetupTempFiles).
* I. Using mmioSendMessage API to talk to an IO Proc (SetupTempFiles).
* J. Loading a Vendor Specific Device (OpenInit).
* H. Retrieving a connection and opening the connected device.
* I. Stream Handler Setup (StreamSetup)
* J. Processing MCI_NOTIFY or MCI_WAIT and callback window handles
* (NotifyWaitSetup).
*
* ENTRY POINTS:
*
* INPUT: MCI_PLAY message.
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* FUNCTIONS DEFINED : CopyParms
* CheckForValidElement
* LoadAbortNotifies
* OpenHandle
* ProcessElement
* SetupTempFiles
* OpenInit
* DetermineConnections
* ConnectToAmp
* StreamSetup
* NotifyWaitSetup
* CreateSemaphores
* AllocateInstance
*
*
* INTERNAL REFERENCES: CreateNAssocStream ().
*
* EXTERNAL REFERENCES: SpiStopStream ().
* SpiAssociate ().
* SpiDisableEvent().
* SpiSeekStream ().
* mmioSendMessage().
* mmioClose ().
*
*********************** END OF SPECIFICATIONS **********************/
#define INCL_BASE
#define INCL_DOSMODULEMGR
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include <string.h>
#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 <mcipriv.h> // MCI Connection stuff
#include <mcd.h> // VSDIDriverInterface.
#include <hhpheap.h> // Heap Manager Definitions
#include <qos.h>
#include <audiomcd.h> // Component Definitions.
#include "admcfunc.h" // Function Prototypes
#include <sw.h>
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: CheckForValidElement
*
* DESCRIPTIVE NAME: Ensures that file names are valid
*
* FUNCTION: If the users passed in a file name for open/load this routine
* will ensure that it is valid. In addition, it will create a name
* if the user passed in open element w/no file name
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG CheckForValidElement( INSTANCE *ulpInstance,
PSZ pszFileName,
ULONG ulParam1 )
{
ULONG ulrc; // return code
ULONG ulPathLength; // Contains the max length
LONG lReturnCode;
/* Did the caller pass a filename on MCI_OPEN/MCI_LOAD */
if ( pszFileName )
{
/* Ensure that this filename is valid */
if (ulrc = CheckMem ( (PVOID) pszFileName, 1, PAG_WRITE))
{
return (MCIERR_MISSING_PARAMETER);
}
/*************************************************
* Store the filename for future reference -- i.e.
* MCI_INFO can request the name of the file
*************************************************/
strcpy ( ulpInstance->pszAudioFile, pszFileName);
/************************************************************
* Set flag to say that we did not create a new file--thus
* we do not have to clean up if the user doesn't save
************************************************************/
ulpInstance->ulCreatedName = FALSE;
}
else
{
/**************************************
* if the user requests a read only file
* and we must create it, return error
**************************************/
if ( ulParam1 & MCI_READONLY )
{
return ( MCIERR_MISSING_PARAMETER );
}
/**********************************************
* Query the default path to place temp files and
* generate a temporary file name
**********************************************/
ulrc = mciQuerySysValue( MSV_WORKPATH, &ulpInstance->pszAudioFile );
if ( !ulrc )
{
return ( MCIERR_INI_FILE );
}
ulrc = MCIERR_SUCCESS;
ulPathLength = CCHMAXPATH;
/* Have mmio generate a unique filename */
lReturnCode = DBCSGenerateUniqueFile( &ulpInstance->pszAudioFile,
&ulPathLength,
&ulpInstance->hTempFile );
if ( lReturnCode != MMIO_SUCCESS )
{
return ( MCIERR_FILE_NOT_FOUND );
}
/***************************************************
* Because we did create a temporary file we will
* be responsible for cleaning up in case the
* caller never calls MCI_SAVE (e.g. a bunch of
* temp files will be left in the workpath
* otherwise, so set a flag to indicate this fact.
**************************************************/
ulpInstance->ulCreatedName = TRUE;
} /* else the user did not pass in a name */
return ( ulrc );
} /* check for valid element */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: LoadAbortNotifies
*
* DESCRIPTIVE NAME: Ensures that notifies are aborted
*
* FUNCTION: Load will stop existing operations (i.e. like play/record ) and
* ensure that they can complete before loading the new file.
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG LoadAbortNotifies( INSTANCE *ulpInstance,
FUNCTION_PARM_BLOCK *pFuncBlock,
ULONG ulAbortNotify )
{
ULONG ulrc;
if ( ulAbortNotify == TRUE)
{
/*****************************************************
* Save cannot be interrupted or data will be lost, so
* if there is a save pending, wait for it to complete
******************************************************/
if ( ulpInstance->usNotPendingMsg == MCI_SAVE )
{
/* Wait for save to complete */
DosWaitEventSem( ulpInstance->hThreadSem, (ULONG ) -1 );
}
else
{
/*****************************************
* State that we are aborting the operation
* in process (i.e. play/record).
*****************************************/
PostMDMMessage ( MCI_NOTIFY_ABORTED,
ulpInstance->usNotPendingMsg,
pFuncBlock);
/******************************************
* The previous command was most a streaming
* command, so stop it from operating
*******************************************/
ThreadedStop( ulpInstance );
STRMSTATE = MCI_STOP;
} /* if pending message not save */
} /* notify pending is true */
else
{
/***********************************************
* MCI_STOP may have done a stop_pause to prevent
* the loss of data--see MCIStop for a more detailed
* explanation of why--ensure that the stream is
* stopped before continuing. If you don't the
* dreaded stream not stopped will result.
*************************************************/
if ( STRMSTATE == STOP_PAUSED )
{
ulrc = StopStream( ulpInstance, OPERATION_PLAY );
}
}
return ( MCIERR_SUCCESS );
} /* LoadAbortNotifies */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: OpenHandle
*
* DESCRIPTIVE NAME: Sets up for mmio handle passed in on the open
*
* FUNCTION: If a mmio handle is passed in on the open, this routine will
* do the appropriate setup for it.
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG OpenHandle( INSTANCE *ulpInstance,
ULONG ulParam1,
HMMIO hmmio )
{
ULONG ulrc = MCIERR_SUCCESS;
if (ulParam1 & MCI_OPEN_MMIO)
{
if ( !hmmio )
{
return ( MMIOERR_INVALID_HANDLE );
}
/* Copy the mmio handle to our instance for future use */
ulpInstance->hmmio = hmmio;
/*****************************************************
* Set a flag which indicates that the caller provided
* a file handle--therefore NEVER close this handle
*****************************************************/
ulpInstance->fOpenMMIO = TRUE;
ulrc = GetAudioHeader (ulpInstance);
/***************************************************
* If the file is non-existent (no data), open the
* card in record mode so the user can hear if
* anything is plugged in line-in or the
* microphone jack (we will assume they want to
* record since there is no data to play back).
* By contrast, if there is data, then we will
* assume that the user wants to be in playback mode
****************************************************/
if ( ulpInstance->ulDataSize != 0 )
{
AMPMIX.ulOperation = OPERATION_PLAY;
}
else
{
AMPMIX.ulOperation = OPERATION_RECORD;
}
/* Set flag to state that an element has been loaded */
ulpInstance->fFileExists = TRUE;
/* Flag to indicate that card has been inited */
ulpInstance->ulCapabilities = ( CAN_INSERT | CAN_DELETE | CAN_UNDOREDO +
CAN_SAVE | CAN_INSERT | CAN_RECORD );
/*-------------------------------------------------------
* Readonly means we cannot write to the file, therefore,
* there is no need to create temporary files etc. since we
* cannot change the original file.
*--------------------------------------------------------*/
if ( ulParam1 & MCI_READONLY )
{
ulpInstance->ulOpenTemp = MCI_FALSE;
ulpInstance->ulCapabilities &= ~( CAN_SAVE | CAN_RECORD );
}
else
{
ulpInstance->ulOpenTemp = MCI_TRUE;
} /* else read only flag was NOT specified */
} /* if open_mmio is passed in */
return ( ulrc );
} /* OpenHandle */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: Process Element
*
* DESCRIPTIVE NAME: Opens a file element
*
* FUNCTION: Opens a file and prepares a device to play and record.
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: MCIERR_SUCCESS.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG ProcessElement( INSTANCE *ulpInstance,
ULONG ulParam1,
ULONG ulOperation )
{
ULONG ulrc;
ULONG ulmmioOpenFlag;
/******************************************************
* If the caller wants to open temp, then modify the flags
* Temp files require that no one else be able to open
* the same file--so use exclusive. If we are not
* using temp files (for instance, if the READ_ONLY flag
* is passed) then allow anyone to open the file.
******************************************************/
if ( ulpInstance->ulOpenTemp )
{
ulmmioOpenFlag = MMIO_READWRITE | MMIO_EXCLUSIVE;
}
else
{
ulmmioOpenFlag = MMIO_READ | MMIO_DENYNONE;
}
/* Ask mmio to open the file */
ulrc = OpenFile( ulpInstance, ulmmioOpenFlag );
/* If open preceded smoothly, then the file exists!! */
if ( !ulrc )
{
/* If we created the file, it has no data so go into record mode */
if ( ulpInstance->ulCreatedName )
{
SetWaveDeviceDefaults ( ulpInstance, OPERATION_RECORD );
/* ensure that the header is up to date */
ulrc = SetAudioHeader( ulpInstance );
}
else /* the file has data so default to playback mode */
{
AMPMIX.ulOperation = OPERATION_PLAY;
}
} /* if no error on OpenFile */
else
{
/******************************************
* We will get file not found error if the
* file does not exist, so try to create it.
*******************************************/
if (ulrc == ERROR_FILE_NOT_FOUND)
{
/********************************
* if this is a read only file then
* we cannot create a new one
*********************************/
if ( ulParam1 & MCI_READONLY )
{
return ( MCIERR_FILE_NOT_FOUND );
}
AMPMIX.ulOperation = OPERATION_RECORD;
ulpInstance->ulCreateFlag = CREATE_STATE;
ulmmioOpenFlag = MMIO_CREATE | MMIO_READWRITE | MMIO_EXCLUSIVE;
/********************************
* Try to create the element
*******************************/
ulrc = OpenFile ( ulpInstance, ulmmioOpenFlag);
/* If we fail, try to return an MCI error */
if (ulrc)
{
if ( ulrc == ERROR_FILE_NOT_FOUND )
{
return ( MCIERR_FILE_NOT_FOUND );
}
else
{
return (ulrc);
}
} /* if an error occurred */
/* Ensure that the header is up to date */
SetWaveDeviceDefaults (ulpInstance, OPERATION_RECORD);
ulrc = SetAudioHeader( ulpInstance );
}
else
{
/* if open or load fail--we have no element */
ulpInstance->fFileExists = FALSE;
return ( ulrc );
}
} /* else there was an error on the load open */
return ( ulrc );
} /* ProcessElement */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: SetupTempFiles
*
* DESCRIPTIVE NAME: Prepares for temporary file work
*
* FUNCTION: If the io proc supports temp files and the user has not requested
* a readonly file, we will try to open a temp file
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG SetupTempFiles( INSTANCE *ulpInstance,
ULONG ulParam1 )
{
ULONG ulrc;
CHAR TempPath[ CCHMAXPATH ]; // holds path for temp files
/**********************************************
* Query the default path to place temp files and
* pass it on to the IO Proc
**********************************************/
ulrc = mciQuerySysValue( MSV_WORKPATH, TempPath );
if ( !ulrc )
{
return (MCIERR_INI_FILE);
}
/*****************************************************
* This message illustrates the use of mmioSendMessage:
* we are asking the IO Proc that we have loaded to
* make all subsequent changes temporary (i.e. if no
* save message is sent, then the file will remain in
* the original condition.
*****************************************************/
ulrc = mmioSendMessage( ulpInstance->hmmio,
MMIOM_TEMPCHANGE,
( LONG ) TempPath,
0 );
if (ulrc)
{
/* Use mmioGetLastError to get additional detail about the error */
ulrc = mmioGetLastError( ulpInstance->hmmio );
/* Cannot write means that the disk is full */
if (ulrc == MMIOERR_CANNOTWRITE )
{
return MCIERR_TARGET_DEVICE_FULL;
}
else
{
return ( ulrc );
}
} /* if there is an error */
/* Flag to indicate that temporary changes are active */
ulpInstance->ulUsingTemp = MCI_TRUE;
return ( ulrc );
} /* SetupTempFiles */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: OpenInit
*
* DESCRIPTIVE NAME: Sets up variables for open
*
* FUNCTION: Initializes variables to be used by the instance
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
void OpenInit( INSTANCE *ulpInstance )
{
extern HID hidASource;
extern HID hidATarget;
extern HID hidBSource;
extern HID hidBTarget;
ULONG ulrc;
ulpInstance->ulCapabilities = CAN_RECORD | CAN_SAVE | CAN_INSERT;
/* Stream hid's */
ulpInstance->StreamInfo.hidASource = hidASource;
ulpInstance->StreamInfo.hidATarget = hidATarget;
ulpInstance->StreamInfo.hidBSource = hidBSource;
ulpInstance->StreamInfo.hidBTarget = hidBTarget;
/************************************
* Wave Record Defaults.
***********************************/
SetWaveDeviceDefaults (ulpInstance, OPERATION_RECORD);
/*--------------------------------------------
* In case no device is opened, default to
* the mode requested in the ini file.
*--------------------------------------------*/
AMPMIX.ulOperation = ulpInstance->lDefaultOperation;// Play or Record
STRMSTATE = NO_STATE;
/*---------------------------------------------
* The MMPM2.INI file contains two variables that
* a streaming MCD should retrieve. The first one
* QOS_VALUE (Quality of Service) contains settings
* which describe the quality of service that the
* network the user is streaming from will try to
* support (e.g. GUARANTEED or DONTCARE). If this
* quality of service is not available, then another
* variable (QOSERRORFLAG) describes whether or not
* to notify the caller.
*--------------------------------------------------*/
ulrc = mciQuerySysValue( MSV_SYSQOSVALUE, &ulpInstance->lQosValue );
if ( !ulrc )
{
ulpInstance->lQosValue = DONTRESERVE;
}
ulrc = mciQuerySysValue( MSV_SYSQOSERRORFLAG, &ulpInstance->lQOSReporting );
if ( !ulrc )
{
ulpInstance->lQOSReporting = ERROR_DEFAULT;
}
} /* OpenInit */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: DetermineConnections
*
* DESCRIPTIVE NAME: Loads appropriate vendor specific device
*
* FUNCTION: In an ideal world, this function would determine who we are
* connected to from MDM, load it and let it set up the stream
* handlers( i.e. probably in the next release). Currently,
* it just loads the VSD (i.e. MAJOR hardcode )
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG DetermineConnections( INSTANCE *ulpInstance,
MMDRV_OPEN_PARMS *pDrvOpenParams )
{
// should this be max path????
CHAR szLoadError[MAX_ERROR_LENGTH]; // DosLoadModule
ULONG ulrc;
/*****************************************************
* Note, this section will have to change when improved
* connector support is added!!!
******************************************************/
/*******************************
* Load the Devspcfc DLL
********************************/
if ( (ulrc = DosLoadModule ( szLoadError,
sizeof( szLoadError ),
pDrvOpenParams->szDevDLLName,
&(ulpInstance->hModHandle))))
{
return ( ulrc );
}
strcpy ((PSZ)AMPMIX.szDriverName, pDrvOpenParams->szDevDLLName );
/*****************************************
* Get the AudioIF Driver Entry point
******************************************/
ulrc = DosQueryProcAddr ( ulpInstance->hModHandle,
0L,
VSDI,
(PFN *) &ulpInstance->pfnVSD) ;
return ( ulrc );
} /* DetermineConnections */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: ConnectToAmp
*
* DESCRIPTIVE NAME: Connects wave audio to the amp mixer.
*
* FUNCTION: Do the work necessary to ensure that the ini file contains valid
* information about who we are connected to. In addition,
* it will open the amp mixer and receive the associated stream
* handler from it (next release)?
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG ConnectToAmp( INSTANCE *ulpInstance,
MMDRV_OPEN_PARMS *pDrvOpenParams,
ULONG ulOpenFlags )
{
ULONG ulDeviceTypeID; // device id of connected device
ULONG ulrc; // return code variable
USHORT usConnLength; // length of conn struct
MCI_AMP_OPEN_PARMS MCIAmpOpenParms; // MCI AmpMixer Open Parameters
DEFAULTCONNECTIONS2 DefCon; // MCI Connections Block
CHAR szPDDName[MAX_PDD_NAME];
/*****************************
* Obtain WaveAudio Device ID
*****************************/
ulpInstance->usWaveDeviceID = pDrvOpenParams->usDeviceID;
ulDeviceTypeID = MAKEULONG ( MCI_DEVTYPE_WAVEFORM_AUDIO,
pDrvOpenParams->usDeviceOrd);
/******************************************************
* Ensure that the INI file contains the right device id
******************************************************/
if ( pDrvOpenParams->usDeviceType != MCI_DEVTYPE_WAVEFORM_AUDIO )
{
return ( MCIERR_INI_FILE );
}
usConnLength = sizeof(DEFAULTCONNECTIONS2);
ulrc = mciQueryDefaultConnections ( ulDeviceTypeID,
&DefCon,
&usConnLength);
/******************************************************
* Ensure that the INI file says that we are connected
* to an amp mixer. If it says that we are connected
* to ourselves, return an error.
******************************************************/
if ( ULONG_LOWD( DefCon.dwDeviceTypeID2 ) == MCI_DEVTYPE_WAVEFORM_AUDIO )
{
return ( MCIERR_INI_FILE );
}
/******************************
* Open an AMP/MIXER Instance
******************************/
MCIAmpOpenParms.pszDeviceType = (PSZ) DefCon.dwDeviceTypeID2;
MCIAmpOpenParms.hwndCallback = (ULONG) NULL;
GetPDDName (DefCon.dwDeviceTypeID2, szPDDName);
strcpy ( ulpInstance->szAudioDevName, szPDDName);
/* Copy the name of the pdd + vsd dll to amp structure */
strcpy ((PSZ) AMPMIX.szDeviceName,
ulpInstance->szAudioDevName);
strcpy ((PSZ) ulpInstance->StreamInfo.AudioDCB.szDevName,
ulpInstance->szAudioDevName);
/*******************************************
* The current amp/mixer uses an undocumented
* structure. Pass this structure in on the
* open also.
********************************************/
MCIAmpOpenParms.pDevDataPtr = (PVOID) &MIX;
/* Open what we are connected to--usually the amp */
ulrc = mciSendCommand (0,
MCI_OPEN,
MCI_OPEN_TYPE_ID| MCI_WAIT| ulOpenFlags,
(PVOID) &MCIAmpOpenParms,
0);
/* Remember the amp device id so that we can close it */
ulpInstance->usAmpDeviceID = MCIAmpOpenParms.usDeviceID;
return ( ulrc );
} /* ConnectToAmp */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: StreamSetup
*
* DESCRIPTIVE NAME: Gets the stream handlers
*
* FUNCTION: Do the work necessary to load the correct stream handlers. Currently
* this is hardcoded, however, in the future we will obtain this info
* from connections/ampmix etc(?)
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG StreamSetup ( void )
{
extern HID hidASource;
extern HID hidATarget;
extern HID hidBSource;
extern HID hidBTarget;
ULONG ulrc = MCIERR_SUCCESS;
/*********************************************************
* Get 'A' stream Handler Handles for Source & target operations
* The file system stream handler is the default 'A' handler
* but the memory stream handler will be used for playlists.
**********************************************************/
if (ulrc = SpiGetHandler((PSZ)DEFAULT_SOURCE_HANDLER_NAME,
&hidASource,
&hidATarget))
{
return ( ulrc );
}
/***********************************************************
* Get 'B' stream Handler Handles for Source & target operations
* The audio stream handler is considered the B stream handler
* since it will usually be the target.
*************************************************************/
ulrc = SpiGetHandler( (PSZ)DEFAULT_TARGET_HANDLER_NAME,
&hidBSource,
&hidBTarget);
return ( ulrc );
} /* StreamSetup */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: CreateSemaphores
*
* DESCRIPTIVE NAME: Creates semaphores for instance
*
* FUNCTION: Creates all the semaphores needed for playing, recording and
* serializing access to necessary instance data.
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG CreateSemaphores( FUNCTION_PARM_BLOCK *pFuncBlock )
{
ULONG ulrc;
INSTANCE *pInstance = ( INSTANCE * ) pFuncBlock->pInstance;
/*********************************************
* Create an event semaphore used in the
* streaming operations (see admcplay, admcrecd).
*********************************************/
ulrc = DosCreateEventSem ( (ULONG) NULL,
(PHEV) &pInstance->hEventSem,
DC_SEM_SHARED,
FALSE );
if (ulrc)
{
return (ulrc);
}
/************************************************
* Create an event semaphore used to synchronize
* various threads (See admcplay.c + admcrecd.c).
*************************************************/
ulrc = DosCreateEventSem ( (ULONG) NULL,
(PHEV) &pInstance->hThreadSem,
DC_SEM_SHARED,
FALSE );
if (ulrc)
{
return (ulrc);
}
ulrc = DosCreateMutexSem ( (ULONG) NULL,
(PHEV) &pInstance->hmtxDataAccess,
DC_SEM_SHARED,
FALSE);
if (ulrc)
{
return (ulrc); /* Failed Sem Create */
}
/************************************************
* Create semaphore which will prevent MCI_CLOSE
* from freeing instance before all threads are
* done processing.
************************************************/
ulrc = DosCreateMutexSem ( (ULONG) NULL,
(PHEV) &pInstance->hmtxCloseAccess,
DC_SEM_SHARED,
FALSE);
if (ulrc)
{
return (ulrc); /* Failed Sem Create */
}
/* Create semaphore to ensure that only one thread can abort another */
ulrc = DosCreateMutexSem ( NULL,
&pInstance->hmtxNotifyAccess,
DC_SEM_SHARED,
FALSE);
if (ulrc)
{
return (ulrc); /* Failed Sem Create */
}
/* Create semaphore to ensure that MCIDRV_SAVE is never locked out*/
ulrc = DosCreateMutexSem ( NULL,
&pInstance->hmtxSaveAccess,
DC_SEM_SHARED,
FALSE);
/***********************************************
* No need to check the return code, since we have
* to do a return to leave anyway
************************************************/
return ( ulrc );
} /* Create Semaphores */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: NotifyWaitSetup
*
* DESCRIPTIVE NAME: Prepares instance for either notify/wait/asynchronous operation
*
* FUNCTION: Stores callbacks and sets up the instance for either notify, wait
* or asynchronous operation.
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: MCIERR_SUCCESS.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
void NotifyWaitSetup( FUNCTION_PARM_BLOCK *pFuncBlock,
USHORT usMessage,
ULONG ulParam1,
ULONG ulParam2 )
{
if (!(ulParam1 & MCI_WAIT) )
{
if (usMessage != MCI_OPEN)
{
pFuncBlock->pInstance->fFakeNotify = FALSE;
/*****************************
* Default to a Notify
******************************/
pFuncBlock->ulParam1 |= MCI_NOTIFY;
/********************************
* Turn The Notify Flag On
*********************************/
pFuncBlock->ulNotify = TRUE;
/*********************************
* Get The Window Callback Handle
*********************************/
if ( ulParam1 & MCI_NOTIFY )
{
if ( usMessage == MCI_PLAY || usMessage == MCI_RECORD )
{
pFuncBlock->pInstance->hwndOldCallBack = pFuncBlock->pInstance->hwndCallBack;
pFuncBlock->pInstance->hwndCallBack = (((PMCI_GENERIC_PARMS)ulParam2)->hwndCallback);
}
else
{
pFuncBlock->hwndCallBack = (((PMCI_GENERIC_PARMS)ulParam2)->hwndCallback);
}
}
else
/********************************************************
* Even if the caller did not specify the MCI_NOTIFY
* flag, and they didn't specify wait, we will treat
* this call just like a notify, EXCEPT that when we
* call MDMDriverNotify, we will pass a bogus
* callback. This prevents us from having to do a
* tremendous amount of additional processing and the
* caller is happy because the work is done asychronously
*********************************************************/
{
/*---------------------------------------------------------
* Set flag to indicate that although we are going
* to act like it is a notify, the caller did not
* really pass in the notify flag. This will be
* important when we have a situation like a play with
* a notify, followed by a play without a wait or notify.
* In this scenario, an aborted message should be
* posted by the first play.
*--------------------------------------------------------*/
pFuncBlock->pInstance->fFakeNotify = TRUE;
if ( usMessage == MCI_PLAY || usMessage == MCI_RECORD )
{
pFuncBlock->pInstance->hwndOldCallBack = pFuncBlock->pInstance->hwndCallBack;
pFuncBlock->pInstance->hwndCallBack = 0;
}
else
{
pFuncBlock->hwndCallBack = 0;
}
} /* if !MCI_NOTIFY */
} /* Message .NE. MCI Open */
} /* Wait flag is not on */
return;
} /* NotifyWaitSetup */
/********************* START OF SPECIFICATIONS *******************************
*
* SUBROUTINE NAME: AllocateInstance
*
* DESCRIPTIVE NAME: allocates memory for the instance etc.
*
* FUNCTION: Stores callbacks and sets up the instance for either notify, wait
* or asynchronous operation.
*
*
*
* NOTES:
* ENTRY POINTS:
*
* INPUT:
*
* EXIT-NORMAL: Return Code 0.
*
* EXIT_ERROR: Error Code.
*
* EFFECTS:
*
* INTERNAL REFERENCES: HhpAllocMem().
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *******************************/
ULONG AllocateInstance( FUNCTION_PARM_BLOCK *pFuncBlock )
{
extern HHUGEHEAP heap; // Global MCD Heap
AcquireProcSem ();
/**************************************
* Waveform audio instance structure
****************************************/
if (!(pFuncBlock->pInstance = HhpAllocMem ( heap,
sizeof (INSTANCE))))
{
ReleaseProcSem ();
return ( MCIERR_OUT_OF_MEMORY );
}
ReleaseProcSem ();
return ( MCIERR_SUCCESS );
} /* AllocateInstance */