Previous Next

Wave Filters

Wave filters represent devices that render and/or capture wave-formatted digital audio data. Applications typically access the capabilities of these devices either through the DirectSound API or through the Windows Multimedia waveOutXxx and waveInXxx functions. For information about the wave formats that WDM audio drivers can support, see WAVEFORMATEX and WAVEFORMATEXTENSIBLE.

A wave-rendering filter receives as input a wave digital audio stream and outputs either an analog audio signal (to a set of speakers or external mixer) or a digital audio stream (to an S/PDIF connector, for example).

A wave-capture filter receives as input either an analog audio signal (from a microphone or input jack) or a digital stream (from an S/PDIF connector, for example). The same filter outputs a wave stream containing digital-audio data.

A single wave filter can perform both rendering and capture simultaneously. This type of filter is needed, for example, to represent an audio device that can play audio through a set of speakers and record audio through a microphone at the same time.

WaveCyclic Versus WavePci

The wave port drivers that PortCls provides can be used to create two types of wave filters:

A WaveCyclic filter can represent an audio device that resides on one of the following system buses: ISA, PCI, or PCMCIA. As the name "WavePci" implies, a WavePci filter usually represents a type of device that connects to a PCI bus, although, in principle at least, a WavePci device might instead connect to an ISA bus, for example. Unlike the simpler devices supported by WaveCyclic, a device supported by WavePci must have scatter/gather DMA capabilities. An audio device that resides on PCI bus but lacks scatter/gather DMA can be represented as a WaveCyclic filter but not as a WavePci filter.

A WavePci device is able to perform scatter/gather DMA transfers to or from buffers that can be located at arbitrary memory addresses and that begin and end with arbitrary byte alignments. In contrast, the DMA hardware for a WaveCyclic device requires only the ability to move data to or from a single buffer that the device's miniport driver allocates. A WaveCyclic miniport driver is free to allocate a cyclic buffer that meets the limited capabilities of its DMA channel. For example, the DMA channel for a typical WaveCyclic device might require a buffer that satisfies the following restrictions:

In return for this simplicity, however, a WaveCyclic device must rely on software copying of data to or from the cyclic buffer, whereas a WavePci device relies on the scatter/gather capabilities of its DMA hardware to avoid such copying. The IRPs that deliver wave audio data to a rendering device or retrieve data from a capture device are accompanied by data buffers, and each of these buffers contains a portion of the audio stream that is being rendered or captured. A WavePci device is able to access these buffers directly through its scatter/gather DMA engine, whereas a WaveCyclic device requires that the data be copied to its cyclic buffer from the IRP, or vice versa.

WaveCyclic Filter

A WaveCyclic filter is implemented as a port/miniport driver pair. A WaveCyclic filter factory creates a WaveCyclic filter as follows:

The code example in Subdevice Creation illustrates this process. The port and miniport drivers communicate with each other through their IPortWaveCyclic and IMiniportWaveCyclic interfaces.

The WaveCyclic filter's cyclic buffer always consists of a contiguous block of virtual memory. The port driver's implementation of the IDmaChannel::AllocateBuffer method always allocates a buffer that is contiguous in both physical and virtual memory address space. If, as mentioned previously, the WaveCyclic device's DMA engine imposes additional constraints on the buffer memory, the miniport driver is free to implement its own buffer-allocation method to meet these constraints.

A WaveCyclic miniport driver that asks for a large buffer (for example, eight physically contiguous memory pages) should be prepared to settle for a smaller buffer size if the operating system denies the original request. In Windows 98/Me, a driver might safely assume that it can always obtain its buffers at system startup time before significant memory fragmentation has occurred. This assumption is not valid for a Windows 2000 (or later) system, which might run for months between reboots. During this time, an audio device might occasionally be unloaded and reloaded to rebalance system resources (see Stopping a Device to Rebalance Resources).

A WaveCyclic device with built-in, bus-mastering DMA hardware is called a master device. Alternatively, a WaveCyclic device can be slave device with no built-in DMA-hardware capabilities. A slave device has to rely on the system DMA controller to perform any data transfers that it requires. The sb16 sample driver in the Windows DDK is an example of a WaveCyclic miniport driver for a slave device. For more information about master and slave devices, see IDmaChannel and IDmaChannelSlave.

A WaveCyclic miniport driver can implement its own DMA-channel object instead of using the default DMA-channel object, which is created by one of the port driver's NewXxxDmaChannel methods:

IPortWaveCyclic::NewMasterDmaChannel

IPortWaveCyclic::NewSlaveDmaChannel

The adapter driver's custom IDmaChannel implementation can perform custom handling of data to meet special hardware constraints. For example, the Windows Multimedia functions use wave formats in which 16-bit samples are always signed values, but the audio-rendering hardware might be designed to use unsigned 16-bit values instead. In this case, the driver's custom IDmaChannel::CopyTo method can be written to convert the signed source values to the unsigned destination values that the hardware requires. Although this technique can be useful for working around hardware-design flaws, it can also incur a significant cost in software overhead.

For an example of a driver that implements its own DMA-channel object, see the sb16 sample audio adapter in the Windows DDK. If the constant OVERRIDE_DMA_CHANNEL is defined to be TRUE, the conditional compilation statements in the source code enable the implementation of a proprietary IDmaChannel object, which the driver uses in place of the default IDmaChannel object from the IPortWaveCyclic::NewXxxDmaChannel call.

WavePci Filter

A WavePci filter is implemented as a port/miniport pair. A WavePci filter factory creates a WavePci filter as follows:

The code example in Subdevice Creation illustrates this process. The port and miniport drivers communicate with each other through their IPortWavePci and IMiniportWavePci interfaces.

A WavePci device's scatter/gather DMA engine should handle buffers that straddle memory page boundaries. For example, a buffer that contains 10 milliseconds worth of 16-bit PCM audio samples for a 48-kHz, 5.1-channel wave stream has the following size:

(6 samples/frame)*(2 bytes/sample)*(48K frames/second)*(10 milliseconds) = 5760 bytes

This exceeds the memory page size (4096 bytes), which means that the buffer contains either one or two page boundaries, depending on how it is positioned in memory. The buffer contains an integral number (480) of frames of audio data, but one or two of these frames might straddle page boundaries.

For this reason, the scatter/gather DMA hardware for a WavePci device should be designed to handle audio frames (such as frame 197 in the following figure) that are split between two physically noncontiguous pages in memory.

An Audio Buffer at an Offset from the Start of a Page

At the top of the preceding figure is a 5760-byte buffer that straddles the boundary between two pages. In this example, the buffer begins at a 1728-byte offset from the start of the first page, which aligns the start of the buffer to a 64-byte boundary in memory. Assume that each audio frame occupies 12 bytes and contains six channels. The first page contains all of frames 0 through 196 but only the first four bytes of frame 197.

At the bottom of the figure is a detailed view of audio frame 197, which shows that only the samples for channels 0 and 1 fall within the first page. The samples for channels 2 through 5 are contained in the second page.

Although the two pages appear next to each other at the top of the figure, they are, in fact, contiguous only in kernel virtual memory. Because the pages containing the buffer are non-contiguous in physical memory, a scatter/gather DMA controller, which uses physical addresses, must specify the two parts of the buffer as two separate entries in its transfer queue. The WavePci port driver automatically splits the buffer into two separate physical mappings at the page boundary.

Even if the example above is changed to align the buffer with the start of the first page, the split-frame problem does not disappear. The following figure demonstrates this point. In this case, frame 341 gets split at the page boundary with the samples for channels 0 and 1 again falling within the first page and the samples for channels 2 through 5 located in the second page.

An Audio Buffer Aligned to the Start of a Page

A WavePci device whose scatter/gather DMA controller does not properly handle split audio frames is limited in the kinds of audio data formats it can handle, although software workarounds might help alleviate some hardware design flaws. For more information, see WavePci Latency.

For more information, see Implementation Issues for WavePci Devices.