C++程序  |  705行  |  25.99 KB

/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/*
 * cras_iodev represents playback or capture devices on the system.  Each iodev
 * will attach to a thread to render or capture audio.  For playback, this
 * thread will gather audio from the streams that are attached to the device and
 * render the samples it gets to the iodev.  For capture the process is
 * reversed, the samples are pulled from the device and passed on to the
 * attached streams.
 */
#ifndef CRAS_IODEV_H_
#define CRAS_IODEV_H_

#include "cras_dsp.h"
#include "cras_iodev_info.h"
#include "cras_messages.h"

struct buffer_share;
struct cras_ramp;
struct cras_rstream;
struct cras_audio_area;
struct cras_audio_format;
struct audio_thread;
struct cras_iodev;
struct rate_estimator;

/* Callback type for loopback listeners.  When enabled, this is called from the
 * playback path of an iodev with the samples that are being played back.
 */
typedef int (*loopback_hook_t)(const uint8_t *frames, unsigned int nframes,
			       const struct cras_audio_format *fmt,
			       void *cb_data);

/* State of an iodev.
 * no_stream state is only supported on output device.
 * Open state is only supported for device supporting start ops.
 */
enum CRAS_IODEV_STATE {
	CRAS_IODEV_STATE_CLOSE = 0,
	CRAS_IODEV_STATE_OPEN = 1,
	CRAS_IODEV_STATE_NORMAL_RUN = 2,
	CRAS_IODEV_STATE_NO_STREAM_RUN = 3,
};

/* Holds an output/input node for this device.  An ionode is a control that
 * can be switched on and off such as headphones or speakers.
 * Members:
 *    dev - iodev which this node belongs to.
 *    idx - ionode index.
 *    plugged - true if the device is plugged.
 *    plugged_time - If plugged is true, this is the time it was attached.
 *    volume - per-node volume (0-100)
 *    capture_gain - per-node capture gain/attenuation (in 100*dBFS)
 *    left_right_swapped - If left and right output channels are swapped.
 *    type - Type displayed to the user.
 *    position - Specify where on the system this node locates.
 *    mic_positions - Whitespace-separated microphone positions using Cartesian
 *      coordinates in meters with ordering x, y, z. The string is formatted as:
 *      "x1 y1 z1 ... xn yn zn" for an n-microphone array.
 *    name - Name displayed to the user.
 *    active_hotword_model - name of the currently selected hotword model.
 *    softvol_scalers - pointer to software volume scalers.
 *    software_volume_needed - For output: True if the volume range of the node
 *      is smaller than desired. For input: True if this node needs software
 *      gain.
 *    max_software_gain - The maximum software gain in dBm if needed.
 *    stable_id - id for node that doesn't change after unplug/plug.
 *    stable_id_new - New stable_id, it will be deprecated and be put on
 *      stable_id.
 */
struct cras_ionode {
	struct cras_iodev *dev;
	uint32_t idx;
	int plugged;
	struct timeval plugged_time;
	unsigned int volume;
	long capture_gain;
	int left_right_swapped;
	enum CRAS_NODE_TYPE type;
	enum CRAS_NODE_POSITION position;
	char mic_positions[CRAS_NODE_MIC_POS_BUFFER_SIZE];
	char name[CRAS_NODE_NAME_BUFFER_SIZE];
	char active_hotword_model[CRAS_NODE_HOTWORD_MODEL_BUFFER_SIZE];
	float *softvol_scalers;
	int software_volume_needed;
	long max_software_gain;
	unsigned int stable_id;
	unsigned int stable_id_new;
	struct cras_ionode *prev, *next;
};

/* An input or output device, that can have audio routed to/from it.
 * set_volume - Function to call if the system volume changes.
 * set_mute - Function to call if the system mute state changes.
 * set_capture_gain - Function to call if the system capture_gain changes.
 * set_capture_mute - Function to call if the system capture mute state changes.
 * set_swap_mode_for_node - Function to call to set swap mode for the node.
 * open_dev - Opens the device.
 * close_dev - Closes the device if it is open.
 * update_supported_formats - Refresh supported frame rates and channel counts.
 * frames_queued - The number of frames in the audio buffer, and fills tstamp
 *                 with the associated timestamp. The timestamp is {0, 0} when
 *                 the device hasn't started processing data (and on error).
 * delay_frames - The delay of the next sample in frames.
 * get_buffer - Returns a buffer to read/write to/from.
 * put_buffer - Marks a buffer from get_buffer as read/written.
 * flush_buffer - Flushes the buffer and return the number of frames flushed.
 * start - Starts running device. This is optionally supported on output device.
 *         If device supports this ops, device can be in CRAS_IODEV_STATE_OPEN
 *         state after being opened.
 *         If device does not support this ops, then device will be in
 *         CRAS_IODEV_STATE_NO_STREAM_RUN.
 * no_stream - (Optional) When there is no stream, we let device keep running
 *             for some time to save the time to open device for the next
 *             stream. This is the no stream state of an output device.
 *             The default action of no stream state is to fill zeros
 *             periodically. Device can implement this function to define
 *             its own optimization of entering/exiting no stream state.
 * output_should_wake - (Optional) Checks if audio thread should schedule a
 *                      wake for this output device. The default condition is
 *                      whether the device is running. Device can implement this
 *                      function to use its own condition.
 * output_underrun - (Optional) Handle output device underrun.
 * update_active_node - Update the active node when the selected device/node has
 *     changed.
 * update_channel_layout - Update the channel layout base on set iodev->format,
 *     expect the best available layout be filled to iodev->format.
 * set_hotword_model - Sets the hotword model to this iodev.
 * get_hotword_models - Gets a comma separated string of the list of supported
 *     hotword models of this iodev.
 * get_num_underruns - Gets number of underrun recorded so far.
 * get_num_severe_underruns - Gets number of severe underrun recorded since
 *                            iodev was created.
 * format - The audio format being rendered or captured to hardware.
 * ext_format - The audio format that is visible to the rest of the system.
 *     This can be different than the hardware if the device dsp changes it.
 * rate_est - Rate estimator to estimate the actual device rate.
 * area - Information about how the samples are stored.
 * info - Unique identifier for this device (index and name).
 * nodes - The output or input nodes available for this device.
 * active_node - The current node being used for playback or capture.
 * direction - Input or Output.
 * supported_rates - Array of sample rates supported by device 0-terminated.
 * supported_channel_counts - List of number of channels supported by device.
 * supported_formats - List of audio formats (s16le, s32le) supported by device.
 * buffer_size - Size of the audio buffer in frames.
 * min_buffer_level - Extra frames to keep queued in addition to requested.
 * dsp_context - The context used for dsp processing on the audio data.
 * dsp_name - The "dsp_name" dsp variable specified in the ucm config.
 * is_enabled - True if this iodev is enabled, false otherwise.
 * software_volume_needed - True if volume control is not supported by hardware.
 * streams - List of audio streams serviced by dev.
 * state - Device is in one of close, open, normal, or no_stream state defined
 *         in enum CRAS_IODEV_STATE.
 * min_cb_level - min callback level of any stream attached.
 * max_cb_level - max callback level of any stream attached.
 * buf_state - If multiple streams are writing to this device, then this
 *     keeps track of how much each stream has written.
 * idle_timeout - The timestamp when to close the dev after being idle.
 * pre_dsp_hook - Hook called before applying DSP, but after mixing.  Used for
 *     system loopback.
 * post_dsp_hook - Hook called after applying DSP.  Can be used for echo
 *     reference.
 * pre_dsp_hook_cb_data - Callback data that will be passing to pre_dsp_hook.
 * post_dsp_hook_cb_data - Callback data that will be passing to post_dsp_hook.
 * reset_request_pending - The flag for pending reset request.
 * ramp - The cras_ramp struct to control ramping up/down at mute/unmute and
 *        start of playback.
 */
struct cras_iodev {
	void (*set_volume)(struct cras_iodev *iodev);
	void (*set_mute)(struct cras_iodev *iodev);
	void (*set_capture_gain)(struct cras_iodev *iodev);
	void (*set_capture_mute)(struct cras_iodev *iodev);
	int (*set_swap_mode_for_node)(struct cras_iodev *iodev,
				      struct cras_ionode *node,
				      int enable);
	int (*open_dev)(struct cras_iodev *iodev);
	int (*close_dev)(struct cras_iodev *iodev);
	int (*update_supported_formats)(struct cras_iodev *iodev);
	int (*frames_queued)(const struct cras_iodev *iodev,
			     struct timespec *tstamp);
	int (*delay_frames)(const struct cras_iodev *iodev);
	int (*get_buffer)(struct cras_iodev *iodev,
			  struct cras_audio_area **area,
			  unsigned *frames);
	int (*put_buffer)(struct cras_iodev *iodev, unsigned nwritten);
	int (*flush_buffer)(struct cras_iodev *iodev);
	int (*start)(const struct cras_iodev *iodev);
	int (*output_should_wake)(const struct cras_iodev *iodev);
	int (*output_underrun)(struct cras_iodev *iodev);
	int (*no_stream)(struct cras_iodev *iodev, int enable);
	void (*update_active_node)(struct cras_iodev *iodev,
				   unsigned node_idx, unsigned dev_enabled);
	int (*update_channel_layout)(struct cras_iodev *iodev);
	int (*set_hotword_model)(struct cras_iodev *iodev,
				 const char *model_name);
	char *(*get_hotword_models)(struct cras_iodev *iodev);
	unsigned int (*get_num_underruns)(const struct cras_iodev *iodev);
	unsigned int (*get_num_severe_underruns)(const struct cras_iodev *iodev);
	struct cras_audio_format *format;
	struct cras_audio_format *ext_format;
	struct rate_estimator *rate_est;
	struct cras_audio_area *area;
	struct cras_iodev_info info;
	struct cras_ionode *nodes;
	struct cras_ionode *active_node;
	enum CRAS_STREAM_DIRECTION direction;
	size_t *supported_rates;
	size_t *supported_channel_counts;
	snd_pcm_format_t *supported_formats;
	snd_pcm_uframes_t buffer_size;
	unsigned int min_buffer_level;
	struct cras_dsp_context *dsp_context;
	const char *dsp_name;
	int is_enabled;
	int software_volume_needed;
	struct dev_stream *streams;
	enum CRAS_IODEV_STATE state;
	unsigned int min_cb_level;
	unsigned int max_cb_level;
	struct buffer_share *buf_state;
	struct timespec idle_timeout;
	loopback_hook_t pre_dsp_hook;
	loopback_hook_t post_dsp_hook;
	void *pre_dsp_hook_cb_data;
	void *post_dsp_hook_cb_data;
	int reset_request_pending;
	struct cras_ramp* ramp;
	struct cras_iodev *prev, *next;
};

/*
 * Ramp request used in cras_iodev_start_ramp.
 *
 * - CRAS_IODEV_RAMP_REQUEST_UP_UNMUTE: Mute->unmute.
 *   Change device to unmute state after ramping is stared,
 *                 that is, (a) in the plot.
 *
 *                                  ____
 *                            .... /
 *                      _____/
 *                          (a)
 *
 * - CRAS_IODEV_RAMP_REQUEST_DOWN_MUTE: Unmute->mute.
 *   Change device to mute state after ramping is done, that is,
 *                 (b) in the plot.
 *
 *                      _____
 *                           \....
 *                                \____
 *                                (b)
 *
 * - CRAS_IODEV_RAMP_REQUEST_UP_START_PLAYBACK: Ramping is requested because
 *   first sample of new stream is ready, there is no need to change mute/unmute
 *   state.
 */

enum CRAS_IODEV_RAMP_REQUEST {
	CRAS_IODEV_RAMP_REQUEST_UP_UNMUTE = 0,
	CRAS_IODEV_RAMP_REQUEST_DOWN_MUTE  = 1,
	CRAS_IODEV_RAMP_REQUEST_UP_START_PLAYBACK = 2,
};

/*
 * Utility functions to be used by iodev implementations.
 */

/* Sets up the iodev for the given format if possible.  If the iodev can't
 * handle the requested format, format conversion will happen in dev_stream.
 * It also allocates a dsp context for the iodev.
 * Args:
 *    iodev - the iodev you want the format for.
 *    fmt - the desired format.
 */
int cras_iodev_set_format(struct cras_iodev *iodev,
			  const struct cras_audio_format *fmt);

/* Clear the format previously set for this iodev.
 *
 * Args:
 *    iodev - the iodev you want to free the format.
 */
void cras_iodev_free_format(struct cras_iodev *iodev);

/* Initializes the audio area for this iodev.
 * Args:
 *    iodev - the iodev to init audio area
 *    num_channels - the total number of channels
 */
void cras_iodev_init_audio_area(struct cras_iodev *iodev,
				int num_channels);

/* Frees the audio area for this iodev.
 * Args:
 *    iodev - the iodev to free audio area
 */
void cras_iodev_free_audio_area(struct cras_iodev *iodev);

/* Free resources allocated for this iodev.
 *
 * Args:
 *    iodev - the iodev you want to free the resources for.
 */
void cras_iodev_free_resources(struct cras_iodev *iodev);

/* Fill timespec ts with the time to sleep based on the number of frames and
 * frame rate.
 * Args:
 *    frames - Number of frames in buffer..
 *    frame_rate - 44100, 48000, etc.
 *    ts - Filled with the time to sleep for.
 */
void cras_iodev_fill_time_from_frames(size_t frames,
				      size_t frame_rate,
				      struct timespec *ts);

/* Sets the timestamp for when the next sample will be rendered.  Determined by
 * combining the current time with the playback latency specified in frames.
 * Args:
 *    frame_rate - in Hz.
 *    frames - Delay specified in frames.
 *    ts - Filled with the time that the next sample will be played.
 */
void cras_iodev_set_playback_timestamp(size_t frame_rate,
				       size_t frames,
				       struct cras_timespec *ts);

/* Sets the time that the first sample in the buffer was captured at the ADC.
 * Args:
 *    frame_rate - in Hz.
 *    frames - Delay specified in frames.
 *    ts - Filled with the time that the next sample was captured.
 */
void cras_iodev_set_capture_timestamp(size_t frame_rate,
				      size_t frames,
				      struct cras_timespec *ts);

/* Update the "dsp_name" dsp variable. This may cause the dsp pipeline to be
 * reloaded.
 * Args:
 *    iodev - device which the state changes.
 */
void cras_iodev_update_dsp(struct cras_iodev *iodev);


/* Sets swap mode on a node using dsp. This function can be called when
 * dsp pipline is not created yet. It will take effect when dsp pipeline
 * is created later. If there is dsp pipeline, this function causes the dsp
 * pipeline to be reloaded and swap mode takes effect right away.
 * Args:
 *    iodev - device to be changed for swap mode.
 *    node - the node to be changed for swap mode.
 *    enable - 1 to enable swap mode, 0 otherwise.
 * Returns:
 *    0 on success, error code on failure.
 */
int cras_iodev_dsp_set_swap_mode_for_node(struct cras_iodev *iodev,
					   struct cras_ionode *node,
					   int enable);

/* Handles a plug event happening on this node.
 * Args:
 *    node - ionode on which a plug event was detected.
 *    plugged - true if the device was plugged, false for unplugged.
 */
void cras_ionode_plug_event(struct cras_ionode *node, int plugged);

/* Returns true if node a is preferred over node b. */
int cras_ionode_better(struct cras_ionode *a, struct cras_ionode *b);

/* Sets an attribute of an ionode on a device.
 * Args:
 *    ionode - ionode whose attribute we want to change.
 *    attr - the attribute we want to change.
 *    value - the value we want to set.
 */
int cras_iodev_set_node_attr(struct cras_ionode *ionode,
			     enum ionode_attr attr, int value);

/* Adds a node to the iodev's node list. */
void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node);

/* Removes a node from iodev's node list. */
void cras_iodev_rm_node(struct cras_iodev *iodev, struct cras_ionode *node);

/* Assign a node to be the active node of the device */
void cras_iodev_set_active_node(struct cras_iodev *iodev,
				struct cras_ionode *node);

/* Adjust the system volume based on the volume of the given node. */
static inline unsigned int cras_iodev_adjust_node_volume(
		const struct cras_ionode *node,
		unsigned int system_volume)
{
	unsigned int node_vol_offset = 100 - node->volume;

	if (system_volume > node_vol_offset)
		return system_volume - node_vol_offset;
	else
		return 0;
}

/* Get the volume scaler for the active node. */
static inline unsigned int cras_iodev_adjust_active_node_volume(
		struct cras_iodev *iodev, unsigned int system_volume)
{
	if (!iodev->active_node)
		return system_volume;

	return cras_iodev_adjust_node_volume(iodev->active_node, system_volume);
}

/* Get the gain adjusted based on system for the active node. */
static inline long cras_iodev_adjust_active_node_gain(
		const struct cras_iodev *iodev, long system_gain)
{
	if (!iodev->active_node)
		return system_gain;

	return iodev->active_node->capture_gain + system_gain;
}

/* Returns true if the active node of the iodev needs software volume. */
static inline int cras_iodev_software_volume_needed(
		const struct cras_iodev *iodev)
{
	if (iodev->software_volume_needed)
		return 1;

	if (!iodev->active_node)
		return 0;

	return iodev->active_node->software_volume_needed;
}

/* Returns maximum software gain for the iodev.
 * Args:
 *    iodev - The device.
 * Returs:
 *    0 if software gain is not needed, or if there is no active node.
 *    Returns max_software_gain on active node if there is one. */
static inline long cras_iodev_maximum_software_gain(
		const struct cras_iodev *iodev)
{
	if (!cras_iodev_software_volume_needed(iodev))
		return 0;
	if (!iodev->active_node)
		return 0;
	return iodev->active_node->max_software_gain;
}

/* Gets the software gain scaler should be applied on the deivce.
 * Args:
 *    iodev - The device.
 * Returns:
 *    A scaler translated from system gain and active node gain dBm value.
 *    Returns 1.0 if software gain is not needed. */
float cras_iodev_get_software_gain_scaler(const struct cras_iodev *iodev);

/* Gets the software volume scaler of the iodev. The scaler should only be
 * applied if the device needs software volume. */
float cras_iodev_get_software_volume_scaler(struct cras_iodev *iodev);

/* Indicate that a stream has been added from the device. */
int cras_iodev_add_stream(struct cras_iodev *iodev,
			  struct dev_stream *stream);

/* Indicate that a stream has been removed from the device. */
struct dev_stream *cras_iodev_rm_stream(struct cras_iodev *iodev,
					const struct cras_rstream *stream);

/* Get the offset of this stream into the dev's buffer. */
unsigned int cras_iodev_stream_offset(struct cras_iodev *iodev,
				      struct dev_stream *stream);

/* Get the maximum offset of any stream into the dev's buffer. */
unsigned int cras_iodev_max_stream_offset(const struct cras_iodev *iodev);

/* Tell the device how many frames the given stream wrote. */
void cras_iodev_stream_written(struct cras_iodev *iodev,
			       struct dev_stream *stream,
			       unsigned int nwritten);

/* All streams have written what they can, update the write pointers and return
 * the amount that has been filled by all streams and can be comitted to the
 * device.
 */
unsigned int cras_iodev_all_streams_written(struct cras_iodev *iodev);

/* Return the state of an iodev. */
enum CRAS_IODEV_STATE cras_iodev_state(const struct cras_iodev *iodev);

/* Open an iodev, does setup and invokes the open_dev callback. */
int cras_iodev_open(struct cras_iodev *iodev, unsigned int cb_level);

/* Open an iodev, does teardown and invokes the close_dev callback. */
int cras_iodev_close(struct cras_iodev *iodev);

/* Gets the available buffer to write/read audio.*/
int cras_iodev_buffer_avail(struct cras_iodev *iodev, unsigned hw_level);

/* Marks a buffer from get_buffer as read. */
int cras_iodev_put_input_buffer(struct cras_iodev *iodev, unsigned int nframes);

/* Marks a buffer from get_buffer as written. */
int cras_iodev_put_output_buffer(struct cras_iodev *iodev, uint8_t *frames,
				 unsigned int nframes);

/* Returns a buffer to read from.
 * Args:
 *    iodev - The device.
 *    area - Filled with a pointer to the audio to read/write.
 *    frames - Filled with the number of frames that can be read/written.
 */
int cras_iodev_get_input_buffer(struct cras_iodev *iodev,
				struct cras_audio_area **area,
				unsigned *frames);

/* Returns a buffer to read from.
 * Args:
 *    iodev - The device.
 *    area - Filled with a pointer to the audio to read/write.
 *    frames - Filled with the number of frames that can be read/written.
 */
int cras_iodev_get_output_buffer(struct cras_iodev *iodev,
				 struct cras_audio_area **area,
				 unsigned *frames);

/* Update the estimated sample rate of the device. */
int cras_iodev_update_rate(struct cras_iodev *iodev, unsigned int level,
			   struct timespec *level_tstamp);

/* Resets the rate estimator of the device. */
int cras_iodev_reset_rate_estimator(const struct cras_iodev *iodev);

/* Returns the rate of estimated frame rate and the claimed frame rate of
 * the device. */
double cras_iodev_get_est_rate_ratio(const struct cras_iodev *iodev);

/* Get the delay from DSP processing in frames. */
int cras_iodev_get_dsp_delay(const struct cras_iodev *iodev);

/* Returns the number of frames in the hardware buffer.
 * Args:
 *    iodev - The device.
 *    tstamp - The associated hardware time stamp.
 * Returns:
 *    Number of frames in the hardware buffer.
 *    Returns -EPIPE if there is severe underrun.
 */
int cras_iodev_frames_queued(struct cras_iodev *iodev,
			     struct timespec *tstamp);

/* Get the delay for input/output in frames. */
static inline int cras_iodev_delay_frames(const struct cras_iodev *iodev)
{
	return iodev->delay_frames(iodev) + cras_iodev_get_dsp_delay(iodev);
}

/* Returns true if the device is open. */
static inline int cras_iodev_is_open(const struct cras_iodev *iodev)
{
	if (iodev && iodev->state != CRAS_IODEV_STATE_CLOSE)
		return 1;
	return 0;
}

/* Register a pre-dsp loopback hook.  Pass NULL to clear. */
void cras_iodev_register_pre_dsp_hook(struct cras_iodev *iodev,
				      loopback_hook_t loop_cb,
				      void *cb_data);

/* Register a post-dsp loopback hook.  Pass NULL to clear. */
void cras_iodev_register_post_dsp_hook(struct cras_iodev *iodev,
				       loopback_hook_t loop_cb,
				       void *cb_data);

/* Put 'frames' worth of zero samples into odev. */
int cras_iodev_fill_odev_zeros(struct cras_iodev *odev, unsigned int frames);

/* Gets the number of frames to play when audio thread sleeps.
 * Args:
 *    iodev[in] - The device.
 *    hw_level[out] - Pointer to number of frames in hardware.
 *    hw_tstamp[out] - Pointer to the timestamp for hw_level.
 * Returns:
 *    Number of frames to play in sleep for this output device.
 */
unsigned int cras_iodev_frames_to_play_in_sleep(struct cras_iodev *odev,
						unsigned int *hw_level,
						struct timespec *hw_tstamp);

/* Checks if audio thread should wake for this output device.
 * Args:
 *    iodev[in] - The output device.
 * Returns:
 *    1 if audio thread should wake for this output device. 0 otherwise.
 */
int cras_iodev_odev_should_wake(const struct cras_iodev *odev);

/* The default implementation of no_stream ops.
 * The default behavior is to fill some zeros when entering no stream state.
 * Note that when a device in no stream state enters into no stream state again,
 * device needs to fill some zeros again.
 * Do nothing to leave no stream state.
 * Args:
 *    iodev[in] - The output device.
 *    enable[in] - 1 to enter no stream playback, 0 to leave.
 * Returns:
 *    0 on success. Negative error code on failure.
 * */
int cras_iodev_default_no_stream_playback(struct cras_iodev *odev, int enable);


/* Get current state of iodev.
 * Args:
 *    iodev[in] - The device.
 * Returns:
 *    One of states defined in CRAS_IODEV_STATE.
 */
enum CRAS_IODEV_STATE cras_iodev_state(const struct cras_iodev *iodev);

/* Possibly transit state for output device.
 * Check if this output device needs to transit from open state/no_stream state
 * into normal run state. If device does not need transition and is still in
 * no stream state, call no_stream ops to do its work for one cycle.
 * Args:
 *    odev[in] - The output device.
 * Returns:
 *    0 on success. Negative error code on failure.
 */
int cras_iodev_prepare_output_before_write_samples(struct cras_iodev *odev);

/* Get number of underruns recorded so far.
 * Args:
 *    iodev[in] - The device.
 * Returns:
 *    An unsigned int for number of underruns recorded.
 */
unsigned int cras_iodev_get_num_underruns(const struct cras_iodev *iodev);

/* Get number of severe underruns recorded so far.
 * Args:
 *    iodev[in] - The device.
 * Returns:
 *    An unsigned int for number of severe underruns recorded since iodev
 *    was created.
 */
unsigned int cras_iodev_get_num_severe_underruns(
		const struct cras_iodev *iodev);

/* Request main thread to re-open device. This should be used in audio thread
 * when it finds device is in a bad state. The request will be ignored if
 * there is still a pending request.
 * Args:
 *    iodev[in] - The device.
 * Returns:
 *    0 on success. Negative error code on failure.
 */
int cras_iodev_reset_request(struct cras_iodev* iodev);

/* Handle output underrun.
 * Args:
 *    odev[in] - The output device.
 * Returns:
 *    0 on success. Negative error code on failure.
 */
int cras_iodev_output_underrun(struct cras_iodev *odev);

/* Start ramping samples up/down on a device.
 * Args:
 *    iodev[in] - The device.
 *    request[in] - The request type. Check the docstrings of
 *                  CRAS_IODEV_RAMP_REQUEST.
 * Returns:
 *    0 on success. Negative error code on failure.
 */
int cras_iodev_start_ramp(struct cras_iodev *odev,
			  enum CRAS_IODEV_RAMP_REQUEST request);

/* Set iodev to mute/unmute state.
 * Args:
 *    iodev[in] - The device.
 * Returns:
 *    0 on success. Negative error code on failure.
 */
int cras_iodev_set_mute(struct cras_iodev* iodev);

/*
 * Checks if an output iodev's volume is zero.
 * If there is an active node, check the adjusted node volume.
 * If there is no active node, check system volume.
 * Args:
 *    odev[in] - The device.
 * Returns:
 *    1 if device's volume is 0. 0 otherwise.
 */
int cras_iodev_is_zero_volume(const struct cras_iodev *odev);

#endif /* CRAS_IODEV_H_ */