MMPM/2 Device Driver Reference:Audio Device Driver Exerciser (PMADDE) Tool
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
The Audio Device Driver Exerciser (PMADDE) is a PM-interface tool you can use to test code for low-level MMPM/2 components, such as audio device drivers or stream handlers. Using PMADDE, you can test various stages of your code at the Ring 0 level. This is useful when you want to verify that individual functions are working in your device driver without testing media control interface code (which might not be written yet). Each time you complete a function, you can test the function to see that it works, and then continue with the development of your driver.
- 1 Setting Up the Program
- 2 PMADDE Functions
- 3 PMADDE Scenario
- 4 PMADDE Script Interface
- 5 Stream Setup and Control
- 6 stream object
- 7 stream protocol
- 8 Stream Programming Interface Functions
Setting Up the Program
Before using PMADDE, OS/2 2.x with MMPM/2 must be installed on your computer. The PMADDE source files are located in the DDK\MMOS2\MMTOOLKT\NEATSTUF\PMADDE subdirectory. To build the PMADDE program, change to the PMADDE subdirectory, type NMAKE, and press Enter. Your output is the executable file (PMADDE.EXE). You can then type PMADDE from the command line to start the program. The Audio Device Driver Exerciser window is displayed.
The PMADDE program defaults to the first waveform audio device it locates. To change the default option, select Options. Select Change Device to display the Change Audio Device window.
This window contains information about each installed audio device including the logical device name, physical device name, and product information. Select the audio device you want to test.
The PMADDE tool uses Stream Programming Interface Functions to test your audio device driver. The Data Stream menu on the Audio Device Driver Exerciser window includes the following choices: (See Stream Setup and Control for additional information on SPI functions.)
- SpiGet Handler
- This option sends an SpiGetHandler function to return a stream handler ID and ensure the stream handler is loaded. Although this function does not perform any actions on the audio device driver, you must complete this function before creating a stream.
- This option sends an SpiCreateStream function to the stream handler to create a data stream of a given data type. The data is then passed to the audio device driver using a DDCMD_REG_STREAM message, which establishes a communication link and registers a stream instance with the device driver.
- This option sends an SpiAssociate function to link a stream object with a given stream source or target. A data object must be identified for use with a stream before the stream can be started.
- This option sends an SpiStartStream function to start data streaming for a stream instance or group of streams. The device driver receives several calls including DDCMD_SETUP, DDCMD_WRITE, and [[MMPM/2 Device Driver Reference:DDCMD Messages#DDCMD_CONTROL|DDCMD_CONTROL] (DDCMD_START) messages.
- This option sends an SpiStopStream function to the stream handler, which is translated to the audio device driver as a DDCMD_CONTROL (DDCMD_STOP) message.
- SpiInstall Protocol
- This option sends an SpiInstallProtocol function to install stream protocol in the stream handler. It also generates an internal Stream Protocol Control Block (SPCB) key, which is used to differentiate between multiple SPCBs of the same data stream type. If your device driver can perform using a type of data format that the MMPM/2 subsystem currently does not use as its default, use this option to install new protocol that your device driver supports.
- This option sends an SpiDisableSync function to destroy the stream you created with SpiCreate. SpiDestroy calls the DDCMD_CONTROL (DDCMD_STOP) and DDCMD_DEREG_STREAM messages at the inter-device driver communication (IDC) level. (See Inter-Device Driver Communication (IDC) Interface.)
- This option sends an SpiSeekStream function to set the time within the audio device driver. You can seek the stream to a certain position, back to 0, or position it forward.
- SpiQuery Time
- This option sends an SpiGetTime function to the stream handler, which issues a DDCMD_STATUS message to the audio device driver to report the current stream time in milliseconds.
The following test scenario uses the PMADDE program to play back a waveform audio file from the source file system stream handler (FSSH) to the target audio system stream handler (AUDIOSH$). See Stream Setup and Control for detailed information on the phases of operation for a data stream.
To get a handler ID, select Data Stream. Select SpiGet Handler for a list of MMPM/2 installed handlers.
Select AUDIOSH$ (audio stream handler) and FSSH (file system stream handler), and select OK.
Note: AUDIOSH$ and FSSH are the only handlers that can be tested using the PMADDE program. The source code can be modified to create tools that test stream handlers other than AUDIOSH$ and FSSH.
The Active Handlers window then lists the handler names and classes and the IDs for AUDIOSH$ and FSSH.
A handler ID is provided for an active handler to be a source (producer) and a target (consumer). After you have both a producer and consumer stream handler, you can advance to step 2 to create the stream.
To create the stream, select Data Stream. Select SpiCreate to display the Create Data Stream window.
Enter the input source and target stream handler IDs. For example, enter the FSSH source ID (4) and the AUDIOSH$ target ID (2). Select a stream data type, and select OK.
The Stream State field in the Active Streams window displays information about the stream that has been created. The audio device driver has accepted the audio IOCtls and the IDC APIs to create the stream.
To associate the stream with an audio file, select Data Stream. Select SpiAssociate to display the Associate Data Stream window.
Type the input stream number, an audio file name, and select OK. You can now start the stream you created, or you can create several streams.
To start the stream, select Data Stream. Select SpiStart to display the Start Stream window.
Type the stream number and select a start flag. The SpiStartStream function starts data streaming in a specific stream or in a synchronized group of streams. Select the Start flag to start the stream immediately. Select the Preroll flag to cause the source stream handler to start and fill the buffers. An event is generated by the Sync/Stream Manager when a stream is prerolled. The application can then start the stream (or streams) for improved real-time response and initial synchronization of streams.
You can perform a stop at any time on the waveform audio file. To stop a stream, select Data Stream. Select SpiStop to display the Stop Stream window.
Type the stream number and select the appropriate stop flag. There are three types of stops. The first is the regular stop or pause, which pauses the data stream but does not disturb any data. The second type of stop is a discard stop, which stops the stream immediately and discards any data left in the stream buffers. The third type is a flush stop, which stops the source stream handler, but the target stream handler continues until the last buffer held when the stop was requested is consumed by the target stream handler.
For a discard or flush stop, the Sync/Stream Manager detects when the stream handlers have stopped and return all buffers. At this point, the Sync/Stream Manager notifies the application with an EVENT_STREAM_STOPPED event in the Event Monitor window.
Streams can be restarted after a stop or end-of-stream (EOS). For the EOS case, the stream would need to be reassociated with another object or a seek backward to some point in the stream would need to be performed to actually start streaming again. A flush stop after a pause stop causes the stream to flush the existing buffers to the output device.
Note: Typically, data streaming continues until the end of the stream. When this happens, the Sync/Stream Manager sends an EVENT_EOS event to the event routine of the application. To restart the stream after you have paused or stopped it, select SpiStart from the Data Stream menu. The program restarts the stream and informs you when an end-of-stream (EOS) is reached.
To get the stream time, select SpiQuery Time from the Data Stream menu.
Type the input stream number and select OK. The stream time is displayed in milliseconds.
PMADDE Script Interface
To pipe a test script that already exists into the program, select Run Script File from the Options menu.
Select the script file you want to pipe into the PMADDE program, and select OK. If the script file exists, the user interface of the PMADDE program is disabled and commands are accepted from the script file only. The following figure is an example of a PMADDE test script.
;***************************************************** ;** Audio Device Driver Exerciser V 1.0 ;** Test Script File. ;***************************************************** BEGIN ; DEVICENAME AUDIO1$ ; device name GETHANDLER AUDIOSH$ ; stream handler name GETHANDLER FSSH ; CREATE 3 2 3 ; Source ID, Target ID & Data type index SLEEP 1000 ; Sleep for 1000 milliseconds CREATE 3 2 3 ; SLEEP 1000 ; ASSOCIATE 1 WELCOM.WAV ; stream number & Audio file SLEEP 1000 ; ASSOCIATE 2 PMADDE.WAV ; SLEEP 1000 ; START 1 0 ; stream number & flag (0=Start, 1=Preroll) SLEEP 5000 ; START 2 0 ; END ;
The following information describes the syntax associated with the PMADDE script language.
- Starts the script file.
- DEVICENAME device name
- Specifies the physical device name.
- CREATE hidSource hidTarget datatype
- Creates a data stream of datatype from hidSourceto hidTarget. Select SpiCreate from the Data Stream menu to view the stream data types available. The data types listed correspond to a number beginning with 0. The second data type in the list is 1, the third is 2, and so on. To create a data stream from FSSH to AUDIOSH$ of data type PCM, 16-bit, 44 kHz, and mono, type the following:
CREATE 4 2 3;
- ASSOCIATE stream # filename
- Associates a data stream with a data object.
- START stream# startflags
- Starts a data stream. The startflagscan be one of the following:
- STOP stream# stopflags
- Stops a data stream. The stopflags can be one of the following:
- SEEK stream# mode units position
- Seeks to the specified positionin the data stream using the specified units and specified mode.
- DESTROY stream#
- Destroys the specified stream.
- QRYTIME stream#
- Queries the stream time of the specified stream.
- SLEEP sleepinterval
- Suspends execution of the script file for the duration of the sleepinterval (in milliseconds)
- Ends the script file.
You can also create a test script by recording your keystrokes to be piped into the PMADDE program at a later time. You must specify a name for the script file you want to create when starting the PMADDE program. If the script file exists, the user interface is disabled and commands are accepted from the script file only. If the script file specified does not already exist, all actions are recorded and a script file is created. For example, to create a script file named TEST.SCR, use the following syntax:
PMADDE TEST.SCR logfile
Note: You must specify a logfile(for example, TEST.LOG) when creating a test script. If you are using the command-line interface to execute a test script that already exists, you must also specify a logfile.
Stream Setup and Control
There are five phases of operation for a data stream:
Each of these five phases involves specific operational steps that an application can control. In any phase, the program can take action to modify certain options. The five phases are described below.
Phase 1. Configuration
After installation, each system has predefined or default connection configurations that allow applications to operate according to general default parameters chosen by the user or by the installation program. An example of stream configuration is where waveform audio data is configured to stream to the Line 1 Output on the IBM Audio Playback and Capture Adapter. This is a default connection that determines which hardware output resource the waveform audio stream will connect to. These configuration options are established when you run the Multimedia Setup program of the MMPM/2 system. Application installation utility programs can also set up connection defaults. Note that the source and target stream handler, as well as the source and target device association, must be specified when the stream is created.
Phase 2. Creation
When a media control driver (or other multimedia application) determines that data will be streamed between devices, it can invoke SpiCreateStream, which results in the stream being created. The caller specifies the source and target stream handler IDs, source and target device-specific information, and the stream data type. (Use the SpiEnumerateHandlers function to return a list of stream handler names. You can then use the SpiGetHandler function to return a handler ID given a handler name. Use the SpiEnumerateProtocols function to determine which data types a given stream handler can process.)
The Sync/Stream Manager notifies each of the two stream handlers that a stream is being created, and each stream handler must return a valid stream protocol control block (SPCB) to the Sync/Stream Manager. The Sync/Stream Manager will negotiate the parameters of the stream and notify the handlers by a SHC_NEGOTIATE_RESULT call to each handler. Negotiation consists of determining which SPCB parameters both stream handlers can accept. This includes stream buffer sizes and the number of buffers needed to maintain continuous streaming of data.
Typically, the Sync/Stream Manager allocates buffers for the stream, but it is possible to use the application buffer directly. The SPCBBUF_ USERPROVIDED flag in the SPCB indicates whether to use provided buffers or to allocate buffers. This is useful for streaming to or from the memory stream handler. In a split stream situation, a particular stream might not allocate its own buffers but use the buffers of another stream. In other words, it might share buffers. This is useful for interleaved data coming from one source but going to more than one destination.
For Sync/Stream Manager-allocated buffers, stream buffer allocation is done during stream creation. The number of buffers to allocate is taken from the "negotiated" SPCB. The buffers are allocated and then locked, so that they will not be paged out to disk. The buffers are unlocked and freed upon an SpiDestroyStream request. These buffers are available at Ring 3 in the process linear space and Ring 0 in global linear system memory. The Sync/Stream Manager will provide global descriptor table (GDT) selectors to allow Ring 0 stream handlers to access the buffer memory. The stream handler can assume that the Sync/Stream Manager manages the GDT selectors used. The maximum buffer size is 64KB.
Both handlers (source and target) share access to the buffers allocated by the Sync/Stream Manager. Note that if the minimum buffer space (specified in the SPCB) is not available, the stream creation will fail. The allocation of memory when the stream is created prevents the need to perform allocations of physical memory when the stream is active, which could result in disruption of data flow affecting the real-time performance of the stream. Therefore, it is advantageous to allow the Sync/Stream Manager to allocate buffers and lock them at stream creation time instead of providing buffers to the Sync/Stream Manager that probably cannot be locked when the stream is created.
Phase 3. Association
After a stream is created, and before it is possible to start the stream, it is necessary to make sure that a data resource, or stream object, is identified for use with the stream. For example, if the application wishes to stream waveform data from application memory (the application dynamically creates the waveform), then the application must make an association between the stream and the memory object. This is accomplished using the SpiAssociate function.
An association for a specific stream handler must match the type of the stream handler as well as the data type of the stream. Each stream handler will list supported object types in response to calling SpiEnumerateProtocols. Note that only one data object can be associated with a stream once the stream is created, and it is specific to a particular stream handler (that is, source or target). Associations can be changed, but the stream cannot be active; it must be stopped first (discard stop, flush stop, or EOS). The SpiAssociate function can be used to "reassociate" data objects for a stream handler as long as the stream handler is the type that the stream was created to handle.
Note:Devices should be associated with stream handlers only when the stream is created.
Phase 4. Streaming/Synchronization
There are several stream operation functions, and each can be used in conjunction with stream synchronization.
The following paragraphs contain outlines of the function descriptions.
- Starts data streaming in a specific stream or a synchronized group of streams, depending on the flags for this function. This function also allows a stream or group of streams to be prerolled. Preroll allows the source stream handlers to start and fill the buffers. An event is generated by the Sync/Stream Manager when the streams are prerolled. The application can then start the streams for better real-time response and initial synchronization of streams.
- If multiple streams are involved, when the synchronization master is started or prerolled, all slavestreams can also be started or prerolled. This synchronization relationship can be set up by using the SpiEnableSync function after all streams are created.
- The active stream protocol governs the amount of data buffered and the rate of data flow maintained. Both source and target stream handlers are controlled by the stream protocol (SPCB). Both handlers contribute to the contents of the SPCB when the stream is created. Stream events such as cue points are detected by the appropriate stream handler and an event notification is sent to the process that owns the stream.
- Stops data streaming in a given stream or streams. There are three types of stops for this command. The first is the regular stop or pause, which pauses the data stream, but does not disturb any data. The second kind of stop is a discard stop, which requests that the stream be stopped immediately and the data left in the stream buffers be discarded. The third type is a flush stop. This stop requests that the source stream handler be stopped, but that the target stream handler continue until the last buffer held at the time the stop was requested is consumed by the target stream handler.
- For a discard or flush stop, the Sync/Stream Manager will detect when the stream handlers have stopped and return all buffers. At this point, the Sync/Stream Manager notifies the application with an EVENT_STREAM_STOPPED event.
- Streams can be restarted after a stop or end-of-stream (EOS). For the EOS case, the stream would need to be reassociated with another object or a seek backward to some point in the stream would need to be performed to actually start streaming again. A flush stop after a pause stop causes the stream to flush the existing buffers to the output device.
- Note: Typically, data streaming continues until the end of the stream. When this happens, the Sync/Stream Manager sends an EVENT_EOS event to the applications event routine.
- Seeks to a specific point in the stream source object. Depending on the type of object associated with the stream at a source or target, this function directs the appropriate stream handler to relocate the current stream index, or position, to the specified location. The object types that support this function are memory, file, CD track, and library object. Use this function to reposition the stream forward or backward from its current position. This can be performed only on a newly created, unstarted stream or a stopped stream (discard stop, flush stop, or EOS).
- Establishes stream synchronization between multiple streams. Stream synchronization is automatically handled by the stream protocol, depending on whether a given stream is the synchronization masteror slave. Once a synchronization relationship is established, synchronization is maintained according to real-time events detected at the master and passed on to the slaves. The application does not have additional stream events to process due to synchronization. Only one stream can be a master.
- Stops stream synchronization for a given stream or streams. A previously designated stream master is disabled, and all synchronization under that master is deactivated.
- Fills in the current stream-specific time information. This allows an application to query the stream time. This function is supported for any stream that is active or stopped, and will not disrupt data transport in the stream. A more accurate method to determine the stream time is to enable stream time events, which will report stream time continuously and in real-time to the application.
Phase 5. Destruction
When a stream is no longer to be used by an application, it must be destroyed. Note that the stream handlers involved can remain active with other streams, and will remain available to create additional streams ( without additional calls to SpiGetHandler). The application will receive no further stream events in its event handling routine after calling the SpiDestroyStream function. All system resources allocated to the stream are released, including the physical memory used to create stream buffers. After the stream is destroyed, the stream handler state reverts back to its condition immediately prior to the creation of the stream. If the stream being destroyed is a master stream of a sync group, all synchronization under that master stream will become inactive. If the stream is a slave in a sync group, the stream will be removed from the sync group and will not affect the master or other slave streams in the group.
A stream object is the data resource or device channel that represents either the data source or target for a stream. In order for a stream to obtain data, it must be associated with a source stream object. This can be a waveform audio data object such as a file on the file system, or it can be a MIDI mapper stream handler from the MIDI hardware adapter. Also, the stream target handler must be associated with a target stream object. This could be a file which will be written to, or it could be an output device that will store, convert, or transmit the data.
Association of a stream with a source stream object, target stream object, or both may be permanent. In other cases, associations must be made whenever the stream is created and before the stream may be manipulated. For example, if there is only one audio adapter with only one input line, then the audio stream handler device driver will always associate a stream with that input line whenever it acts as a source.
Associations are tied to the concept of connections at the media control interface level of the system. Default connections can be made between logical devices and the actual physical device that performs the function of the logical device. Media drivers must use this connection information to determine the source and target handler names to be used on a subsequent SpiGetHandler. The connection information is also used to provide the source and target device or object associations used on an SpiCreateStream function.
Devices may be associated with stream handlers at stream creation time only. An SpiAssociate request can be used, however, to "re-associate" data objects with stream handlers after the stream has been created. The stream must be stopped (discarded, flushed, or EOS) to do this.
A stream protocol defines key parameters that control the behavior of a data stream. The application can query, install, or deinstall a specific SPCB from a stream handler. Each stream handler supports one or more stream protocols. An SPCB is uniquely identified by the value of the stream data type (SPCB key). One field in the SPCB key allows the stream handler to have multiple SPCB's installed for the same data type. This field can be used by an application to specify which SPCB, for any data type, it wants to use. Each application in the system could define multiple SPCB for the same data type (see the ulTypefield in the SPCBKEY data structure). The application can modify a stream protocol by installing a new SPCB and deinstalling the old SPCB.
Stream Programming Interface Functions
The stream programming interface (SPI) contains functions exported by the Sync/Stream Manager to support applications that control real-time data streams. These functions are used to perform stream creation, association, configuration, operation, synchronization, and destruction functions. SPI functions also include enabling applications to modify Stream Protocol Control Blocks (SPCBs) and querying a stream's time information.
|SpiAssociate||Associates a data object with a stream handler.|
|SpiCreateStream||Creates a stream instance between a source and a target stream handler.|
|SpiDestroyStream||Removes a stream instance from the system.|
|SpiDetermineSyncMaster||Determines the best master stream to be used in a sync group.|
|SpiDisableEvent||Disables event detection for a particular event.|
|SpiDisableSync||Removes a group of streams.|
|SpiEnableEvent||Enables event detection for a particular event.|
|SpiEnableSync||Establishes a group of streams to synchronize the streams.|
|SpiEnumerateHandlers||Returns a list of the stream handler names installed in the SPI.INI file.|
|SpiEnumerateProtocols||Returns a list of stream protocol keys for the specified stream handler.|
|SpiGetHandler||Returns the handler ID for the specified stream handler.|
|SpiGetProtocol||Queries a stream handler for a specified stream protocol.|
|SpiGetTime||Queries the current stream time.|
|SpiInstallProtocol||Installs or removes a specified stream protocol for a stream handler.|
|SpiSeekStream||Seeks to a specified point in the stream object or sets the current stream time.|
|SpiStartStream||Starts data streaming for a single stream instance or a group of streams.|
|SpiSendMsg||Sends a message to a stream handler.|
|SpiStopStream||Stops data streaming for a single stream instance or a group of streams.|