MMPM/2 Device Driver Reference:Audio Sample for Vendor-Specific Drivers

=Audio Sample for Vendor-Specific Drivers= OS/2 Warp Version 3 provides sample files that assist in the creation of vendor-specific drivers (VSDs). The VSD defines a generic device driver-like interface that effectively decomposes high-level media control interface functions into more fundamental operations at the DLL level.

Note: VSD functionality is available for OS/2 Warp, Version 3 and is not downward compatible.

The following figure illustrates the program flow from the Media Device Manager (MDM) through the VSD and finally on to the audio adapter.



In order to play or record audio data, the audio stream handler sends VSD_DDCMD messages to the VSD.
 * 1) Media Control Interface functions are passed from the Media Device Manager to the vendor-specific driver using VSD commands.
 * 2) The VSD passes information to its device driver. This provides a Ring-3 interface to control audio devices. The VSD sample provided with the DDK should be adequate to cover all basic audio functions. If your audio adapter requires special processing, you might have to supplement the sample VSD. To install the VSD, update the VSDDriver= option in the generic install routines (or CARDINFO.RC).
 * 3) The device driver controls the audio adapter.
 * 4) After the audio adapter is initialized, the MDM passes control to the Audio Stream Handler through the SPI interface.
 * 1) The SPI interface sends/receives audio data from the audio stream handler.
 * 2) The Audio Stream Handler controls audio data passed to and from the VSD.
 * 3) The VSD reports stream events (such as buffer completion) via the SHC_REPORT_INT message.

Source Code
Source code for the vendor-specific driver (VSD) sample is located in the IBM Device Driver Source Kit for OS/2. Source files include documentation headers that provide detailed descriptions of the programming concepts and routines used in incorporating the sample.

VSD Architecture
The VSD layer is a device-independent physical device driver-like layer that resides in Ring 3. It passes information between the media control interface subsystem and multimedia devices.

A VSD has the following characteristics:
 * Does not deal with media control interface notifications.
 * Usually uses a single standard time format (milliseconds).
 * Usually does not have to deal with file management.

Interface to the VSD
The interface to the Vendor Specific Driver (VSD) uses an entry point called VSDEntry. First a DosLoadModule is issued for the VSD's DLL. The DosLoadModule returns a handle for the VSD. Then with the VSD handle, a DosQueryProcAddr is issued to find the VSD entry point (VSDEntry). From this point on, calls to the VSD are made through the following API: ULONG   VSDEntry ( HVSD       hvsd,     // Handle to VSD driver                    ULONG      ulFunc,   // Function code                    ULONG      ulFlags,  // Flags for driver                    PVOID      pRequest) // Request Parameter Block/Value

Events
When the VSD receives VSD_DDCMD with DDCMDREGISTER, it should store the hid, hStream, and pSHDEntryPoint fields of the DDCMDREGISTER structure for use in reporting events. To report an event, the VSD should use the function pointer from the register to call the stream handler.

VSD_DDCMD
DDCMD_STOP (see the ulCmd field of the DDCMDCONTROL structure) operates differently for VSDs than for physical device drivers.

When a PDD receives a DDCMD_STOP, it is assumed that the stop is completed.

When a VSD receives a DDCMD_STOP, the stop is not considered complete when it is returned from the call. Rather it is considered complete when it the VSD is sent a STREAM_STOP_NOW (see ulFlag of the SHD_REPORTINT structure and ulFlagof the MSG_REPORTINT structure.)

Note: VSDs will receive VSD_DDCMDin the ulFunc parameter of the VSDEntry. To process specific VSD_DDCMDs, you must examine the pRequest parameter.

The following code sample shows how this can be written. LONG APIENTRY mixerDDCMDEntryPoint( HVSD   hvsd,                                     ULONG  ulFunc,                                     ULONG  ulFlags,                                     PVOID  pRequest ) {

PDDCMDCOMMON pCommon = (PDDCMDCOMMON) pRequest;

if (pCommon == NULL) {         return (ERROR_INVALID_BLOCK) ; }

switch (pCommon->ulFunction) {         case DDCMD_SETUP: return DDCmdSetup ((PDDCMDSETUP)pCommon, (PMCI_AMP_INSTANCE)hvsd );

case DDCMD_READ: return DDCmdRead ((PDDCMDREADWRITE)pCommon, (PMCI_AMP_INSTANCE)hvsd);

case DDCMD_WRITE: return DDCmdWrite ((PDDCMDREADWRITE)pCommon, (PMCI_AMP_INSTANCE)hvsd);

case DDCMD_STATUS: return DDCmdStatus ((PDDCMDSTATUS)pCommon, (PMCI_AMP_INSTANCE)hvsd);

case DDCMD_CONTROL: return DDCmdControl ((PDDCMDCONTROL)pCommon, (PMCI_AMP_INSTANCE)hvsd);

case DDCMD_REG_STREAM: return DDCmdRegister ((PDDCMDREGISTER)pCommon, (PMCI_AMP_INSTANCE)hvsd);

case DDCMD_DEREG_STREAM: return DDCmdDeRegister ((PDDCMDDEREGISTER)pCommon, (PMCI_AMP_INSTANCE)hvsd);

default: return (ERROR_INVALID_FUNCTION); } }

Communication to the Stream Handler
The SHDEntryPoint contains the following two messages. These messages are located in the SHDD.H file of the \MMOS2\MMTOOLKT\H subdirectory. SHDD.H contains the data structures, their type definitions, and #define statements for certain values. Note that the messages pass pointers to packets of data, to allow maximum flexibility for the future.


 * SHC_REPORT_INIT :The VSD uses this message when it needs data at interrupt time. For example, it uses this message to tell the stream handler that it has used up all the data and needs more.


 * When the stream handler gets the call, it knows the VSD is passing back a buffer that it might already have consumed. So the stream handler returns on that call, giving the VSD a fresh buffer to consume.


 * Note: It is possible for the stream handler to call back into the VSD when the stream handler receives an shc_report_init.


 * SHC_REPORT_EVENT :The stream handler uses this message to keep in sync with VSD activities. For example, the stream handler can request the VSD to report back every tenth of a second that data is played. The stream handler has all the logic to handle these events. The VSD examines the request, and during its checks when it realizes a tenth of a second has been played in data, the VSD calls SHD_REPORT_EVENT. The stream handler can do what it wants at this point, and the VSD returns.


 * The VSD keeps track of the processes. In other words, only the VSD knows how much data, to the millisecond, has been played out to the device. The stream handler can approximate the data played, using calculations based on how much data has gone by. But the stream handler cannot calculate the data played to the millisecond, or even to the fraction of a millisecond, the way the VSD can.

Stream Handler Values
There are certain values that the stream handler is expecting. For example, when the stream handler requests a stop or a pause on a DDCMD_CONTROL message, the pointer that comes back to the stream handler is a pointer to the cumulative time that the VSD has recorded in real time. So whenever the stream handler requests the device to stop, the VSD honors that request and informs the stream handler the real time that the VSD stopped within the stream.

Another value the stream handler looks for is returned on DDCMD_STATUS. This is also a pointer to the cumulative time from the VSD, with respect to when that stream was first started at the stream handler's request.

VSD Values
The stream handler passes a pointer to the VSD on DDCMD_STATUS. This points to a value used by the VSD for setting the referenced time of the VSD. It is not always correct for the VSD to start its time at 0 every time the stream handler does a start, because the stream handler might have performed a seek in the stream. The VSD might have played a minute of data and then performed a backwards seek to the 30-second mark in the data. If a start is issued, the VSD should start from the 30-second mark in that stream.

DDCMD_CONTROLhas an important NOTIFY subfunction that is used for cuepoint or event detection. The stream handler supports events in cuepoints-an application request to be notified when a particular location in the file is reached or a specific time period has elapsed. The stream handler uses two methods for detecting how much time has elapsed:


 * Using DDCMD_CONTROL NOTIFY, the stream handler requests to be notified by the VSD at a particular time and passes a pointer to the cue time.
 * The stream handler determines the time internally. This method is not as precise as the first method, because only the VSD knows the real time.

For example, suppose the stream handler does a DDCMD_CONTROL NOTIFY at one minute. If the VSD supports precise event detection, it must accept this request and put it into a queue somewhere, preferably a linked list. This linked list will have the time of one minute so that during the streaming process, the VSD occasionally checks to see whether it is at the one minute mark. When this event occurs, the VSD calls back on an SHD_REPORT_EVENT. Then you can free up the event detection linked list node.

Keep in mind that the VSD should have the capability to queue these requests because there might be additional requests. For example, an application might request to be notified at the one-minute mark, next at a minute and a half, and possibly every five minutes.

If the VSD does not support event detection, then when it gets called on a DDCMD_CONTROL NOTIFY, it responds with an ERROR_INVALID_REQUEST. This response tells the stream handler that it must do the event-detection itself.

Priorities
When the VSD receives DDCMD_READ and DDCMD_WRITE messages, it will occur on a time-critical thread from the audio stream handler. If other threads are running, the DDCMD thread will always run first because of priority.

Other commands such as VSD_SET and VSD_QUERY may come simultaneously at a normal priority. (You may be executing one command and then be jumped to a thread of higher priority.)

Device Type Function Table
Because the VSD interface supports commands for numerous data types, it is not necessary for every VSD to support all commands. The only commands that must be supported are those for the particular device type (for example, audio, video, and so on) that the VSD is implementing. This section provides guidelines for which functions and flags must be supported and which functions and flags are optional. The following table shows which functions are Required (R) and Optional (O) by device type.

Legend:
 * R - Required Command
 * O - Optional Command

The flags that must be supported by a VSD for the VSD_SET command vary according to the media types it supports. The following table illustrates which flags are required for the specified media type. Legend:
 * R - Required Command
 * O - Optional Command
 *  - Not Applicable

The flags that must be supported by a VSD for the VSD_QUERY command vary according to the media types it supports. The following table illustrates which flags are required for the specified media type. Legend:
 * R - Required Command
 * O - Optional Command
 *  - Not Applicable

Device States
Media devices that transport data are considered to be in one of the following states at any given time: When a device is opened and restored, the device context is assumed to be in the restored state. The closed state can be viewed as both the initial state and the termination state. Or this state can be thought of as not a state at all, because a device context does not exist before it is opened, and ceases to exist when it is closed.
 * Registered
 * Deregistered
 * Saved
 * Restored
 * Closed

The following figure lists the allowable device states across the top of the table and indicates the changes in state that occur when the command messages shown in the first column of the table are issued. This table assumes all error conditions keep the device in its current state. For example, a waveform player that is opened without an element remains in the stopped state when a play is issued, and the MCD receives an error code.

The following figure is provided as a guide to application developers and MCD writers. There can be no guarantee that every media device will conform to this table, but every effort should be made to hide the complexity of the device from the application.



Legend
 * * After a restore, the device is considered active and available for use. If the stream has been registered, it is restored to the state it was in before the VSD_SAVE.
 * - Error condition.

Install
To manually install the VSD, change the VSDDRIVER= statement for the relevant amp-mixer device to the new DLL name. To permanently install the VSD, see Adding Support for Audio and Video Adapters.