www.fgks.org   »   [go: up one dir, main page]

Skip to main content

Non-PCM Wave Formats and WDM Audio Drivers

Updated: December 4, 2001


On This Page

 
Audio Updates for Windows Me  Audio Updates for Windows Me
Requirements for a Non-PCM Pin Factory
  Requirements for a Non-PCM Pin Factory
Example: DataRangeIntersection Routine for a Non-PCM Format
  Example: DataRangeIntersection Routine for a Non-PCM Format
Converting between Format Tags and Format SubType GUIDs
  Converting between Format Tags and Format SubType GUIDs
Kernel Streaming Topology Considerations
  Kernel Streaming Topology Considerations
Specifics for waveOut Clients
  Specifics for waveOut Clients
Specifics for DirectSound Clients
  Specifics for DirectSound Clients
AC-3 Data Ranges
  AC-3 Data Ranges
Example: Declaring Non-PCM Data Ranges
  Example: Declaring Non-PCM Data Ranges
USB Audio Details
  USB Audio Details
Considerations for Older Operating Systems
  Considerations for Older Operating Systems
Call to Action  Call to Action


This article discusses implementation details for driver developers, including how to determine if a Windows Driver Model (WDM) audio driver supports a given wave format and how to implement a data range intersection handler on your non-PCM pin. This article assumes basic knowledge of kernel streaming, WDM Audio, and PortCls adapter drivers as described in the Windows DDK. The information included in this article applies for Microsoft Windows 98 Second Edition, Windows 2000, Windows Millennium Edition (Windows Me), and Windows XP.

Windows Me includes the capability to play non-PCM audio data through a PortCls driver using standard APIs (waveOut, Microsoft DirectSound, Microsoft DirectShow). On operating systems released before Windows Me, this capability was not possible.

For more information, see the Windows DDK, available at http://www.microsoft.com/whdc/devtools/ddk/default.mspx.

Audio Updates for Windows Me

New waveOut and DirectSound capabilities have been provided in Windows Me. Specifically, waveOut non-PCM data flows directly to PortCls (or USBAudio) instead of going through Kernel Audio Mixer (KMixer), as in earlier versions of the Windows operating systems. DirectSound now uses the correct data subtype and the specified node requirements.

waveOut

The layer between waveOut applications and VxD wave drivers is thin. Drivers and applications that support a custom wave format can stream that format without the operating system understanding the format.

In the WDM Audio framework in operating system versions earlier than Windows Me, all waveOut data passes through the KMixer. A waveOutOpen call will succeed only if KMixer supports the formatregardless of whether the driver supports the format. If KMixer does not support the format, waveOutOpen will return WAVERR_BADFORMAT.

KMixer natively handles WAVE_FORMAT_PCM on all WDM operating systems; support for WAVE_FORMAT_IEEE_FLOAT, plus WAVEFORMATEXTENSIBLE variants of PCM and IEEE float formats, was added in Windows 98 Second Edition. Windows 95/98 and Windows NT do not support non-PCM formats via waveOut (or the DirectShow waveOut renderer) on WDM audio drivers. Drivers for earlier versions of Windows are referred to as "legacy" drivers in this article.

Microsoft DirectSound

For legacy waveOut drivers and VxD drivers, DirectSound supports only WAVEFORMATEX (non-EXTENSIBLE) PCM formats with 8 bits or 16 bits per sample, 1 or 2 channels, and a sampling rate between 100 Hz and 100 KHz, for both primary and secondary buffers. In addition, for VxD drivers the formats allowed for primary buffers may be further restricted by driver limitations if using cooperative-level DSSCL_WRITEPRIMARY. These legacy/VxD limitations have not changed in Windows Me, nor are they likely to change in the future. See the Microsoft DirectX documentation for SetFormat in the Windows Driver Development Kit (DDK). The Windows DDK is available on the web at:
http://www.microsoft.com/whdc/devtools/ddk/default.mspx

For WDM drivers, PCM formats are supported in WAVEFORMATEX and WAVEFORMATEXTENSIBLE form. In addition, the IEEE_FLOAT format is supported for both primary and secondary DSBCAPS_LOCSOFTWARE buffers (mixed by KMixer) in both WAVEFORMATEX and EXTENSIBLE form.

Note: Primary buffers have a limited role on WDM drivers: they still serve to obtain the IDirectSound3DListener interface, set the device's global volume and pan, and so on, but they no longer represent the single output stream from the sound card. Instead, the primary buffers are mixed by KMixer, allowing several WRITEPRIMARY DirectSound applications to run simultaneously. This also implies that SetFormat on a primary buffer has only an indirect effect on the final mixing format.

On operating systems released before Windows Me,

CreateSoundBuffer fails with non-PCM formats, regardless of the DirectSound version, even if the driver supports the format. This is also true for the DirectShow DirectSound renderer. Various internal assumptions caused CreateSoundBuffer to work properly only with PCM:

  • Older DirectSound versions used a PCM subtype when creating KS pins instead of deriving the subtype from the WAVEFORMATEX.wFormatTag in the DirectSoundBuffer.

  • DirectSound required data paths to have VOL and SRC nodes on every DirectSound buffer, even if the client had not specified pan, volume, or frequency controls. This worked because these nodes are in every PCM data patheither in KMixer or in a hardware mixer. For non-PCM data streams, however, KMixer is not in the graph, nor are these nodes generally in the hardware topology. DirectSound does not support output of non-PCM formats on operating systems older than Windows Me. CreateSoundBuffer will fail with in these scenarios with an error code of DSERR_BADFORMAT.

Requirements for a Non-PCM Pin Factory

To support a custom data format, you should define a separate pin factory with your non-PCM data format, apart from any PCM pin factories. PCM and non-PCM data formats cannot share the same single-instance pin factory because the sole pin instance will be set aside for KMixer. This is not the case if the pin factory supports multiple instancesPCM and non-PCM can coexist on the same pin factory in that case. However, there is no guarantee that these pin instances will be available to the non-PCM client at run time because PCM clients may have already allocated them. A separate pin factory for your custom format is the safest option.

In order for the pin to be discovered and used by DirectSound (for DirectX 7 and later), you must define this non-PCM pin factory on a filter that already supports PCM do not put the non-PCM pin in a separate miniport or filter. If you put the non-PCM pin in a separate miniport or filter, or if your device does not support PCM, DirectSound will not detect the non-PCM pin.

You must implement a data range intersection handler on your non-PCM pin. PortCls provides a built-in handler that always chooses PCM; as a result, you will need to add your own handler.

  • For a non-PCM pin, do not support WAVE_FORMAT_PCM in the intersection handler.

    Note that this handler can be called with an OutputBufferLength of 0, in which case it is asking only for the size of the preferred data range, not the actual data itself.

  • Fill in the non-PCM data ranges size in the ResultantFormatLength parameter; return STATUS_BUFFER_OVERFLOW.

    See the sample code in "Example: DataRangeIntersection Routine for a Non-PCM Format" later in this article.

  • Test your DataRangeIntersection routine; use Grapher to instantiate your pinit first calls your intersection handler in order to determine an acceptable default format. The Grapher utility is included as part of the Windows DDK.

  • Support a non-PCM format by making the driver properly handle the non-PCM format in the following locations at a minimum: miniportStream::Init and SetFormat, plus miniport::NewStream and DataRangeIntersection.

Example: DataRangeIntersection Routine for a Non-PCM Format

The following DataRangeIntersection function is for a miniport that supports AC3-over-S/PDIF. For all pins except the non-PCM pin, it returns STATUS_NOT_IMPLEMENTED, allowing PortCls to run the default handler.

The DataRangeIntersection function determines the highest quality intersection of two data ranges. This function has the following prototype:

STDMETHODIMP_(NTSTATUS) 















    CMiniportWaveCyclic::DataRangeIntersection(















        IN  ULONG  PinId,















        IN  PKSDATARANGE  ClientDataRange,















        IN  PKSDATARANGE  MyDataRange,















        IN  ULONG  OutputBufferLength,















        OUT PVOID  ResultantFormat,















        OUT PULONG  ResultantFormatLength 















        );















Parameters

PinId Pin for which data intersection is being determined.

ClientDataRange Pointer to KSDATARANGE structure that contains the data range submitted by client in the data range intersection property request.

MyDataRange The data range of the pin to be compared with client's data range. In this case, you can ignore your data range, because you can only support one range.

OutputBufferLength Size of the buffer pointed to by the resultant format parameter.

ResultantFormat Pointer to value where the resultant format should be returned.

ResultantFormatLength Actual length of the resultant format placed in ResultantFormat. This should be less than or equal to OutputBufferLength.

The following source code shows the implementation of the DataRangeIntersection function:

STDMETHODIMP_(NTSTATUS)















CMiniportWaveCyclic::DataRangeIntersection (















    IN  ULONG         PinId,















    IN  PKSDATARANGE  ClientDataRange,















    IN  PKSDATARANGE  MyDataRange,















    IN  ULONG         OutputBufferLength,















    OUT PVOID         ResultantFormat,















    OUT PULONG        ResultantFormatLength )















{















    PAGED_CODE();































    // For all other pins, let PortCls















    // handle the request (PCM only).















    if (KSPIN_WAVE_AC3_RENDER_SINK != PinId)















    {















        return STATUS_NOT_IMPLEMENTED;















    }















	















    // The ClientDataRange should be AC-3.















    // Otherwise, there is no intersection.















    if (!IsEqualGUIDAligned(ClientDataRange->MajorFormat,















           KSDATAFORMAT_TYPE_AUDIO) && 















        !IsEqualGUIDAligned(ClientDataRange->MajorFormat, 















           KSDATAFORMAT_TYPE_WILDCARD))















    {















        return STATUS_NO_MATCH;















    }















    if (!IsEqualGUIDAligned(ClientDataRange->SubFormat,















           KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF) &&















        !IsEqualGUIDAligned(ClientDataRange->SubFormat, 















           KSDATAFORMAT_TYPE_WILDCARD))















    {















        return STATUS_NO_MATCH;















    }















    















    if (IsEqualGUIDAligned(ClientDataRange->Specifier, 















          KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||















        IsEqualGUIDAligned(ClientDataRange->Specifier, 















          KSDATAFORMAT_TYPE_WILDCARD))















    {















        *ResultantFormatLength = sizeof(KSDATAFORMAT_WAVEFORMATEX);















    }















    else if (IsEqualGUIDAligned(ClientDataRange->Specifier, 















               KSDATAFORMAT_SPECIFIER_DSOUND))















    {















        *ResultantFormatLength = sizeof(KSDATAFORMAT_DSOUND);















    }















    else















    {















        return STATUS_NO_MATCH;















    }































    // Validate return buffer size. If the request is 















    // only for the size of the resultant structure, 















    // return it now.















    if (!OutputBufferLength) 















    {















        return STATUS_BUFFER_OVERFLOW;















    } 















    else if (OutputBufferLength < *ResultantFormatLength) 















    {















        return STATUS_BUFFER_TOO_SMALL;















    }















    















    PKSDATAFORMAT_WAVEFORMATEX  resultantFormatWFX;















    PWAVEFORMATEX  pWaveFormatEx;































    resultantFormatWFX = (PKSDATAFORMAT_WAVEFORMATEX) ResultantFormat;































    // Return the best (only) available format.















    //SampleSize must match nBlockAlign.















    resultantFormatWFX->DataFormat.FormatSize = *ResultantFormatLength;















    resultantFormatWFX->DataFormat.Flags        = 0; // no special format flags















    resultantFormatWFX->DataFormat.SampleSize   = 4; // stereo, 2 bytes/sample 















    resultantFormatWFX->DataFormat.Reserved     = 0; // always leave this zero















    resultantFormatWFX->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;















    INIT_WAVEFORMATEX_GUID(&resultantFormatWFX->DataFormat.SubFormat,















      WAVE_FORMAT_DOLBY_AC3_SPDIF );































    // Extra space for the (larger)















    // DirectSound specifier















    if (IsEqualGUIDAligned(ClientDataRange->Specifier, 















          KSDATAFORMAT_SPECIFIER_DSOUND))















    {















        PKSDATAFORMAT_DSOUND resultantFormatDSound;















        resultantFormatDSound = (PKSDATAFORMAT_DSOUND)ResultantFormat;































        resultantFormatDSound->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_DSOUND;















        















        // DirectSound format capabilities are not















        // expressed this way in KS, so we express 















        // no capabilities. 















        resultantFormatDSound->BufferDesc.Flags = 0;















        resultantFormatDSound->BufferDesc.Control=0;































        pWaveFormatEx = &resultantFormatDSound->BufferDesc.WaveFormatEx;















    }















    else  // WAVEFORMATEX or WILDCARD (WAVEFORMATEX)















    {















        resultantFormatWFX->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;















        pWaveFormatEx = (PWAVEFORMATEX)((PKSDATAFORMAT) resultantFormatWFX + 1);















    }































    pWaveFormatEx->wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;     















    pWaveFormatEx->nChannels       = 2; // stereo stream















    pWaveFormatEx->nSamplesPerSec  = 48000; // de facto standard for AC3-SPDIF















    pWaveFormatEx->wBitsPerSample  = 16; // normal SPDIF sample size















    pWaveFormatEx->cbSize          = 0; // no extra format info follows















    pWaveFormatEx->nBlockAlign     = pWaveFormatEx->nChannels * pWaveFormatEx->wBitsPerSample / 8;















    pWaveFormatEx->nAvgBytesPerSec = pWaveFormatEx->nSamplesPerSec * pWaveFormatEx->nBlockAlign;















    return STATUS_SUCCESS;















}

Microsoft has created a software-only virtual audio device driver (MSVAD) that fully illustrates these implementation details. This is available in the Windows DDK.

Converting between Format Tags and Format SubType GUIDs

Wave formats can be specified through the format tags and format globally unique identifiers (GUIDs). Converting format tags to the associated format GUID is an important part of future operating system compatibility.

Note: Non-PCM WAVE_FORMAT_EXTENSIBLE formats are handled in the same way (separate pin factory recommended, intersection handler required, and so on). The extensible SubFormat GUID generated from a wave format tag is used in the KSDATAFORMAT structure as the SubType GUID.

For more information about multi-channel or high-bit-depth formats, see Multiple Channel Audio Data and WAVE Files.

KsMedia.h shows how to define new GUIDs in a static manner:

#define STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX \















0x00000000L, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71















DEFINE_GUIDSTRUCT(    "00000000-0000-0010-8000-00aa00389b71", 















KSDATAFORMAT_SUBTYPE_WAVEFORMATEX);















#define KSDATAFORMAT_SUBTYPE_WAVEFORMATEX \















DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_WAVEFORMATEX)















The following macros convert between wave format tags and associated GUIDs:

#if !defined( DEFINE_WAVEFORMATEX_GUID )















#define DEFINE_WAVEFORMATEX_GUID(x) \















(USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71















#endif































#define INIT_WAVEFORMATEX_GUID(Guid, x) { \















    *(Guid) = KSDATAFORMAT_SUBTYPE_WAVEFORMATEX; \















    (Guid)->Data1 = (USHORT)(x); \















}































#define IS_VALID_WAVEFORMATEX_GUID(Guid) \















        (!memcmp(((PUSHORT)&KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, \















((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT)))































#define EXTRACT_WAVEFORMATEX_ID(Guid)    (USHORT)((Guid)->Data1)

Use these macros, or a combination of them, to create and handle your format GUID that is based on a custom wave format tag, such as WAVE_FORMAT_AC3_SPDIF (0x0092)"

#define STATIC_KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF \















DEFINE_WAVEFORMATEX_GUID(WAVE_FORMAT_DOLBY_AC3_SPDIF)































DEFINE_GUIDSTRUCT(    "00000092-0000-0010-8000-00aa00389b71",















KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF);































#define KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF \















DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF)















...















INIT_WAVEFORMATEX_GUID(pMyGuid,myWaveFormatTag);















...















if (IS_VALID_WAVEFORMATEX_GUID(aWaveFormatExGuidPtr)) {















    aWaveFormatTag = EXTRACT_WAVEFORMATEX_ID(aWaveFormatExGuidPtr);















}















Kernel Streaming Topology Considerations

For basic information about this topic, see "Kernel Streaming Topology to Audio Mixer API Translation" in the Windows 2000 DDK.

A non-PCM pin will correspond to a SRC line in the mixer API. If this data path flows to a unique bridge pin, an additional DST line will be exposed as well. This may cause problems in mixer API clients, such as SndVol32 replacements. These problems could include "phantom" mixer strips in the application UI, or AVs in the application's mixer parsing code.

If this is undesirable, it is possible to eliminate the DST line by feeding your non-PCM data path eventually into a SUM node that is shared by the PCM data path (join this DST to the main DST line). However, this solution misrepresents the true hardware topology and could lead to problems in the future, especially with clients that attempt to control the non-PCM data stream through nodes downstream from the SUM node. The best course of action is to fix the mixer API client so that it ignores DST/SRC lines without controls.

When viewing your wave filter in KSCATEGORY_AUDIO in Grapher or KsStudio, there should be a separate pin for non-PCM data. (KsStudio is a revised version of the Grapher utility that will be available in the Windows DDK. When viewing the composite system audio graph through KSCATEGORY_AUDIO_DEVICE, you should see your non-PCM data range or ranges on the main wave output pin, in addition to any PCM data ranges. Note that the system audio device (SysAudio.sys) generates KSCATEGORY_AUDIO_DEVICE automaticallya driver should not register itself manually in this category.

A non-PCM data path does not have to be connected to the topology miniport. This would be beneficial only if the non-PCM data path interacted with the rest of the devices topology, for example, if it went through a common mixer or sample rate converter, and so on. A streaming pin connected to a bridge pin, both on the wave miniport, is a valid, complete topology for a non-PCM data stream that flows directly to a S/PDIF port.

Specifics for waveOut Clients

The waveOutOpen API will continue to return WAVERR_BADFORMAT if a driver does not support a particular wave format.

Note that looping a non-PCM format wave header is currently unsupported. However, because of architectural limitations, failure is deferred until header submittal (not header preparation). Specifically, non-PCM wave headers with WHDR_BEGINLOOP or WHDR_ENDLOOP set in dwFlags may pass waveOutPrepareHeader, but will fail waveOutWrite (MMSYSERR_INVALPARAM). As long as WHDR_BEGINLOOP and WHDR_ENDLOOP are not specified in dwFlags, a dwLoops of >1 will not cause waveOutWrite to fail.

While non-PCM is playing, waveOutBreakLoop will fail with return code MMSYSERR_INVALPARAM.

Looping support for non-PCM formats is planned for a post-Windows XP operating system release.

Specifics for DirectSound Clients

The information in this section applies to Windows 98 Second Edition, Windows 2000, Windows Me, Windows XP and future operating systems that support WDM.

To determine if a WDM driver supports a given wave format, attempt to create a DSBCAPS_LOCHARDWARE buffer in the desired format on that driver. This is the only way within the DirectSound API to discover whether the non-PCM data format is supported.

Secondary DSBCAPS_LOCHARDWARE buffers in any valid format (both WAVEFORMATEX and EXTENSIBLE) are supported if the specific driver being used supports the format. This means having a non-PCM data range with the SPECIFIER_DSOUND designation.

To use non-PCM formats in DirectSound, simply create a WAVEFORMATEX or WAVEFORMATEXTENSIBLE structure describing the format and pass it to CreateSoundBuffer in the lpwfxFormat member of the DSBUFFERDESC structure. No other changes to existing DirectSound code are required to use these formats. However, note that certain formats are less likely to support controls that are taken for granted for PCM data. For example, a card supporting digital output of AC3-encoded data probably would not support the DSBCAPS_CTRLPAN or DSBCAPS_CTRLVOLUME controls on that data, so attempting to create the DirectSound buffer with those flags would fail.

DirectSound playback through VxD drivers or legacy waveOut drivers is still limited to PCM; this has not been addressed.

AC-3 Data Ranges

Wave format tag 0x0092 is defined as AC-3 over S/PDIF. Tags 0x0240 and 0x0241 are synonymous and treated in an identical manner by many DVD applications. To eliminate redundancy, Microsoft recommends that drivers and applications support wave format tag 0x0092. Microsoft does not recommend supporting 0x0240 or 0x0241 at this time.

If AC-3 data is intended to be passed digitally without decode, it can be treated the same as a 2-channel, 16-bit, 48 kHz PCM stream. In fact, when specifying an AC-3 over S/PDIF data range, the wave format tag is the only element that differs from a data range of PCM data being sent out of the S/PDIF port.

Note: AC-3 data is streamed in units called frames. Each frame can be independently decoded into 1536 samples of PCM audio (multiplied by the number of channels in the frame). This represents 32 milliseconds of audio at 48 kHz sample rate. A 5.1 channel AC-3 frame occupies fewer bytes than 1536 stereo PCM samples. There are exceptions to this, but those types of AC-3 frames are very uncommon, cannot be transmitted over S/PDIF, and will not be discussed in this article. Therefore, to prevent delivering the compressed audio bitstream over the S/PDIF interface faster than real time (that is, to prevent delivering 32 ms of audio in less than 32 ms), an AC-3 frame must be padded with zeros until it takes up the same number of bytes as 1536 stereo PCM samples.

If attempting to send unpadded AC-3 to a PortCls adapter driver that uses WaveCyclic, note that when the port driver senses data starvation, it will fill the cyclic buffer with silence. The port driver senses data starvation because the data stream contains fewer bytes than a two-channel uncompressed stream. When the cyclic buffer is filled with silence, it causes problems on the AC-3 decode because these periods of silence will not correspond to AC-3 frames.

Finally, take into account hardware specifics, such as indicating a non-PCM S/PDIF stream by setting the /AUDIO bit on the S/PDIF transceiver if you are doing AC-3 S/PDIF pass-through. This bit in the S/PDIF frame header will indicate to the receiver/decoder that the data stream must be decoded.

Example: Declaring Non-PCM Data Ranges

The following KSDATARANGE_AUDIO declaration shows how to declare non-PCM data ranges for the AC-3 over S/PDIF format:

















//=====================================================















static KSDATARANGE_AUDIO PinDataRangesAC3Stream[] =















{















  {















    {















      sizeof(KSDATARANGE_AUDIO),















      0,















      0,















      0,















      STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),















      STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF),















      STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)















    },















    2,      // Max number of channels.















    16,     // Minimum number of bits per sample.















    16,     // Maximum number of bits per channel.















    48000,  // Minimum rate.















    48000   // Maximum rate.















  },































  // If you do not include this second data range 















  // (which is identical except for the 















  // SPECIFIER_DSOUND), then your non-PCM pin will not 















  // be seen by DirectSound on Windows 98 Second















  // Edition or Windows 2000, regardless of the 















  // presence of QFE/service pack or the DirectX 















  // version.(see Considerations for Older Operating 















  // Systems, below)















  {















    {















      sizeof(KSDATARANGE_AUDIO),















      0,















      0,















      0,















      STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),















      STATICGUIDOF(KSDATAFORMAT_SUBTYPE_DOLBY_AC3_SPDIF),















      STATICGUIDOF(KSDATAFORMAT_SPECIFIER_DSOUND)















    },















    2,      // Max number of channels.















    16,     // Minimum number of bits per sample.















    16,     // Maximum number of bits per channel.















    48000,  // Minimum rate.















    48000   // Maximum rate.















  }















};















USB Audio Details

The Microsoft USB Audio driver, USBAudio.sys, does not currently support padded AC-3 formats. Support for USB Audio Type III formats, including padded AC-3 formats, is planned for a future operating system release.

For more information about USB Audio Type III formats, see the Universal Serial Bus Device Class Definition for Audio Data Formats, available at: http://www.usb.org/developers/devclass/  This link leaves the Microsoft.com site

The USB Audio driver can accept non-padded, or "raw," AC-3. USBAudio.sys supports the internal format of the DirectShow DVDSplitter, which one can directly connect to USBAudio using KsProxy. Specifically, the non-padded AC-3 data range exposed by USBAudio is KSDATAFORMAT_SUBTYPE_AC3_AUDIO, the same GUID as MEDIASUBTYPE_DOLBY_AC3.

DirectSound non-PCM playback to USBAudio is not supported. It is planned that this will be remedied in a future operating system release.

Considerations for Older Operating Systems

A Quick Fix Engineering (QFE) package that contains all fixes necessary to enable non-PCM through waveOut is available for Windows 98 Second Edition. The QFE can be obtained through Microsoft Product Support Services, ask for 269601USA8.EXE. Windows 2000 Service Pack 2 (SP2) also contains these fixes. Microsoft has no plans to provide this fix for the original release of Windows 98.

Note: Due to operating system limitations, DirectSound 8 and later versions will pass non-PCM data through WDM audio drivers on Windows 98 Second Edition only if the QFE is installed. Similarly, DirectSound 8 and later versions will pass non-PCM data on Windows 2000 only if the supporting service pack is also installed. DirectSound 8 will not pass non-PCM data on the original version of Windows 98 or earlier operating systems.

PortCls clones each data range with KSDATAFORMAT_SPECIFIER_WAVEFORMATEX to an identical one with KSDATAFORMAT_SPECIFIER_DSOUND.This cloning is transparent to the miniport but can be observed with Grapher or KsStudio. This capability is provided in Windows Me, but will not be addressed in QFE packages or service packs for other operating systems or versions. Historically, DirectSound supported only PCM, and PortCls cloned only KSDATAFORMAT_SUBTYPE_PCM formats.

In order for a driver to support non-PCM on DirectSound on operating systems released before Windows Me, it should list two data ranges for each non-PCM data formatone with KSDATAFORMAT_SPECIFIER_WAVEFORMATEX and another with KSDATAFORMAT_SPECIFIER_DSOUND. This is shown in the data range sample code provided in "Example: Declaring Non-PCM DataRanges" earlier in this article.

Note: Windows 98 and Windows Me provide compatibility support for PCMWAVEFORMAT of packed-24 and packed-32 sizes. Windows 98 Second Edition and Windows 2000 do not. The QFE package for Windows 98 Second Edition provides this support. However, this solution should be treated as a short-term patch during the conversion period to WAVE_FORMAT_EXTENSIBLE formats. Applications must be changed to use the new extensible format, and media files that can be safely converted should be.

Because of a bug in early versions of the system graph builder, an AUDIO_DEVICE wave data path without nodes will crash on Windows 98 and Windows 98 Second Edition. Because PCM pins are either hardware mixing pins (with SUM, VOL, SRC nodes, and so on) or have KMixer (and its nodes) inserted above them, this problem affects non-PCM pins only. In order for your driver to work on Windows 98 Second Edition, you should have at least one node on your non-PCM pin. When passing AC-3 over S/PDIF, for example, KSNODETYPE_SPDIF_INTERFACE might be appropriate where you implement a property to manipulate the SCMS bits.

Call to Action

Support non-PCM and EXTENSIBLE formats in your drivers:

  • Implement your non-PCM pin topology as defined in this article.

  • Implement a data range intersection handler on your non-PCM pin as defined in this article.

  • If your device handles AC-3, support wave format tag 0x0092 (and the associated format GUID). Microsoft does not recommend supporting 0x0240 or 0x0241 at this time.

  • Implement the fixes for Windows 98 Second Edition and Windows 2000 SP as described in this article.

Support non-PCM and EXTENSIBLE formats in your applications:

  • To determine whether a driver supports a given non-PCM wave format, attempt to create a DSBCAPS_LOCHARDWARE buffer in the desired format on that driver (if using DirectSound), or call the waveOutOpen API (if using waveOut).

  • If your application plays AC-3 content, support wave format tag 0x0092 (and the associated format GUID). Microsoft does not recommend supporting 0x0240 or 0x0241 at this time.

Rate:  
DCSIMG