Microphone Library Overview


The DRC microphone API set encapsulates all the pieces that control access to the microphone on the DRC. It manages the state of the driver chain, performs data and sample rate conversion, and matches the sampling frequency used in the audio subsystem (AX) of 32kHz exactly.

To keep data copies to a minimum, the API is designed around a shared ring buffer architecture. APIs exist to query the amount of available samples and to set the number of samples consumed by the audio system. That way, the finite state machine in the microphone driver can properly manage itself as the data source of the ring buffer.

The memory used for the ring buffer is provided by a hierarchically higher-level process, the application. If that application wants to perform DMA directly from that shared ring buffer then it is the application's responsibility to manage buffer alignment and memory coherency.

It is the application's responsibility to check the fill level of the shared ring buffer before drawing from it. PCM data arrives in bursts. Under normal operating conditions where the link with the DRC is intact, bursts of PCM data arrive in 16ms intervals. The microphone driver matches the average incoming data rate to the 32kHz audio sample clock used in the AX subsystem. That is, with a minimum of 32ms of buffered PCM data gapless playback can be assured. This defines a minimum ring buffer size of 2048 bytes which is enforced in the microphone driver.

The design goal of the DRC microphone library is to minimize the amount of software complexity and cost when the streaming of PCM audio samples is in progress. To that end, a rate matching and zero fill algorithm are integrated into the DRC microphone library. The task of the audio rendering loop is to query how many samples are available in the ring buffer, make that memory coherent, i.e., flush the data cache, and inform the DRC microphone library of the number of samples processed in that manner.

The APIs that are called from within the audio rendering callback, MICGetStatus and MICSetDataConsumed are lightweight.

In the event that the application does not draw audio samples as quickly as they arrive, then the microphone driver will overwrite the oldest data. That ensures that after the drawing of samples matches the incoming rate, only a single skip occurred.

In the event that the application draws data faster than it arrives, which can be either by design (such as simple pitch-shifting schemes) or due to link loss with the DRC. In those cases an application will read old data that is left in the ring buffer. To avoid this condition an application must query the amount of available data prior to using it for playback.

Link loss with the DRC can occur at any time. It can be in the form of delayed delivery of PCM data, the drop of one or more PCM data packets, or it can reach the level of console and DRC being disconnected. The rate matching algorithm in the DRC microphone library detects when audio packets are overdue and the shared ring buffer is about to underflow. When that is about to happen, all zero samples are put into the buffer. When PCM data from the DRC resume, they are put into the ring buffer as before. Should too many samples arrive, due to the temporary link loss and subsequent catch-up, then the excess is discarded to keep the ring buffer level within its nominal latency.

A link loss may not be temporary. That means that the DRC and console become disconnected. When that happens, the equivalent of calling MICClose followed by MICUninit is automatically performed by the library. The DRC microphone library implements a policy that when the DRC has become disconnected, the library and underlying driver stack revert to an uninitialized, quiescent, and closed state. Flags in MICGetStatus indicate the connection state. Attempts to initialize or open the DRC microphone library will return an error indicating the loss of connection.

The Cafe Core OS (COS) has the concept of foreground and background processes and foreground, background switching. An application is given notification via the system message queue. The steps for an orderly switch to background are calling MICClose followed by MICUninit. That will leave the underlying driver stack in a quiescent state. In the event that an application does not perform those steps, then they are performed in the DRC microphone library and the DRC microphone sub system will behave as if it has been disconnected.

Both a return to foreground as well as reconnection require that the DRC microphone library be reinitialized.

The DRC microphone allows for some adjustments, such as the microphone gain. For that purpose a pair of APIs, MICGetState and MICSetState, are used to query or set a given parameter. The turn around time to query or set a particular parameter is on the order of several milliseconds for most requests. Much of the time is spent with the executing thread being blocked.

The set and get state APIs, as well as the open and close APIs are inherently slow and should not be called directly from the main drawing loop. It is recommended that applications create a separate thread that performs those slower operations. Most of the time is spent waiting on synchronization objects which means that the actual CPU load created by calling those functions is small.

Usage Model

The driver is meant to be initialized once by calling MICInit. At that time the shared memory is provided to the driver and is used thereafter. That memory needs to be kept writable to the DRC microphone library until MICUninit has returned, the device has become disconnected, or the application has been put into the background.

The streaming of PCM data is started by calling MICOpen and stopped by calling MICClose. Streaming can be started and stopped as often as the application sees fit. It is not until MICOpen is called that audio samples can arrive in the shared buffer.

After MICOpen has returned with no error a voice (in AX sense) can be configured to be used with the ringbuffer filled by the DRC microphone library. Playback through that ringbuffer requires minimal software intervention.

After streaming is started, the application needs to call MICGetStatus to get the number of PCM samples that are ready in the shared ring buffer. After a sufficient number of samples is in the buffer, the application is free to consume them as it sees fit. To keep the ring buffer state between the DRC microphone library and the application coherent, the application must inform the driver of the number of samples it has consumed from the shared ring buffer by calling MICSetDataConsumed.

Typically, this task of state management is performed within the AX system's callback function. It will also be necessary to make the ring buffer memory coherent before DMA can be performed by flushing the respective portion of the data cache.

Calling MICGetStatus will also return flags. Those flags indicate whether the driver is 'open' and whether the DRC is presently connected. After the DRC becomes disconnected, the MIC_STATUS_FLAG_CONNECTED bit will no longer be set or the error MIC_ERROR_NOT_INIT is returned. Both indicate loss of connection. The error return value indicates that the DRC microphone library has finished uninitializing.

As soon as a disconnect indication is given, the voice playing the DRC microphone PCM stream needs to be stopped. If the application wishes to resume DRC microphone sound playback, it can poll by trying to initialize the DRC microphone library with MICInit until it succeeds.

Since the ring buffer fill matches the nominal 32kHz sample rate of the AX system exactly, it is permissible to derive all microphone playback timing from the AX system generated interrupts. However, the application is strongly encouraged to check that the number of samples available in the buffer is sufficient for the number of samples scheduled for consumption.

The APIs MICOpen, MICClose, MICGetState, MICSetState, and MICUninit take several milliseconds to 10s of milliseconds to return, although most of the time is spent waiting on COS synchronization objects. It is recommended that execution of those APIs be performed in a separate thread that can tolerate such delays.

Connection state notifications are available elsewhere in the system and they are not duplicated in the DRC microphone library. However, the connection state can be polled. Calling MICInit with the DRC disconnected will return MIC_ERROR_NOT_CONNECTED. Such polling can be performed within the applications draw loop since the status check or the actual init operation will execute quickly.

It is recommended to poll using MICInit to go from a disconnected to connected state, and MICGetStatus to go from connected to disconnected state.

The DRC's microphone gain is programmable. The functions MICSetState and MICGetState are used for that purpose.

Headset Known Issue

When the headset is either plugged into or unplugged from the DRC headphone jack, an audible 'pop' may be heard. The issue may be especially noticeable for voice chat partners and is hardware specific.

Future Plans

We are planning to extend the mic_status_t data structure by adding an unsigned integer variable that shows the number of samples that were generated by zero fill. It is intended to convey the quality of the link to the application. This counter starts at zero and is monotonically increasing until MICUninit is called, the link is lost, or the application has switched to the background.

See Also

Error Codes

Revision History

2013/05/08 Automated cleanup pass.
2012/06/08 Update to match SDK 2.06.
2011/10/27 Initial version.