/* 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. */ /* * Alsa Helpers - Keeps the interface to alsa localized to this file. */ #ifndef _CRAS_ALSA_HELPERS_H #define _CRAS_ALSA_HELPERS_H #include <alsa/asoundlib.h> #include <stdint.h> #include <stdlib.h> struct cras_audio_format; /* Sets the channel layout from given format to the pcm handle. * Args: * handle - Pointer to the opened pcm to set channel map to. * fmt - The format containing the channel layout info. * Returns: * 0 if a matched channel map is set to HW, -1 otherwise. */ int cras_alsa_set_channel_map(snd_pcm_t *handle, struct cras_audio_format *fmt); /* Gets the supported channel mapping of the pcm handle which matches * the channel layout in the format. * Args: * handle - Pointer to the opened pcm to get channel map info. * fmt - The format to fill channel layout into. * Returns: * 0 if an exactly matched channel map is found, -1 otherwise. */ int cras_alsa_get_channel_map(snd_pcm_t *handle, struct cras_audio_format *fmt); /* Opens an alsa device, thin wrapper to snd_pcm_open. * Args: * handle - Filled with a pointer to the opened pcm. * dev - Path to the alsa device to test. * stream - Alsa stream type, input or output. * Returns: * See docs for snd_pcm_open. */ int cras_alsa_pcm_open(snd_pcm_t **handle, const char *dev, snd_pcm_stream_t stream); /* Closes an alsa device, thin wrapper to snd_pcm_close. * Args: * handle - Filled with a pointer to the opened pcm. * Returns: * See docs for snd_pcm_close. */ int cras_alsa_pcm_close(snd_pcm_t *handle); /* Starts an alsa device, thin wrapper to snd_pcm_start. * Args: * handle - Filled with a pointer to the opened pcm. * Returns: * See docs for snd_pcm_start. */ int cras_alsa_pcm_start(snd_pcm_t *handle); /* Drains an alsa device, thin wrapper to snd_pcm_drain. * Args: * handle - Filled with a pointer to the opened pcm. * Returns: * See docs for snd_pcm_drain. */ int cras_alsa_pcm_drain(snd_pcm_t *handle); /* Forward/rewind appl_ptr so it becomes ahead of hw_ptr by fuzz samples. * After moving appl_ptr, device can play the new samples as quick as possible. * avail = buffer_frames - appl_ptr + hw_ptr * => hw_ptr - appl_ptr = avail - buffer_frames. * The difference between hw_ptr and app_ptr can be inferred from snd_pcm_avail. * So the amount of frames to forward appl_ptr is * avail - buffer_frames + fuzz. * When hw_ptr is wrapped around boundary, this value may be negative. Use * snd_pcm_rewind to move appl_ptr backward. * * Case 1: avail - buffer_frames + fuzz > 0 * * -------|----------|----------------------------------- * app_ptr hw_ptr * |------------->| forward target * * Case 2: avail - buffer_frames + fuzz < 0 * * -------|----------|----------------------------------- * hw_ptr app_ptr * |<------| rewind target * * Args: * handle - Filled with a pointer to the opened pcm. * ahead - Number of frames appl_ptr should be ahead of hw_ptr. * Returns: * 0 on success. A negative error code on failure. */ int cras_alsa_resume_appl_ptr(snd_pcm_t *handle, snd_pcm_uframes_t ahead); /* Probes properties of the alsa device. * Args: * dev - Path to the alsa device to test. * stream - Alsa stream type, input or output. * rates - Pointer that will be set to the arrary of valid samples rates. * Must be freed by the caller. * channel_counts - Pointer that will be set to the array of valid channel * counts. Must be freed by the caller. * formats - Pointer that will be set to the arrary of valid PCM formats. * Must be freed by the caller. * Returns: * 0 on success. On failure an error code from alsa or -ENOMEM. */ int cras_alsa_fill_properties(const char *dev, snd_pcm_stream_t stream, size_t **rates, size_t **channel_counts, snd_pcm_format_t **formats); /* Sets up the hwparams to alsa. * Args: * handle - The open PCM to configure. * format - The audio format desired for playback/capture. * buffer_frames - Number of frames in the ALSA buffer. * period_wakeup - Flag to determine if period_wakeup is required * 0 - disable, 1 - enable * dma_period_time - If non-zero, set the dma period time to this value * (in microseconds). * Returns: * 0 on success, negative error on failure. */ int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format, snd_pcm_uframes_t *buffer_frames, int period_wakeup, unsigned int dma_period_time); /* Sets up the swparams to alsa. * Args: * handle - The open PCM to configure. * enable_htimestamp - If non-zero, enable and configure hardware timestamps, * updated to reflect whether MONOTONIC RAW htimestamps * are supported by the kernel implementation. * Returns: * 0 on success, negative error on failure. */ int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp); /* Get the number of used frames in the alsa buffer. * * When underrun is not severe, this function masks the underrun situation * and set avail as 0. When underrun is severe, returns -EPIPE so caller * can handle it. * Args: * handle[in] - The open PCM to configure. * buf_size[in] - Number of frames in the ALSA buffer. * severe_underrun_frames[in] - Number of frames as the threshold for severe * underrun. * dev_name[in] - Device name for logging. * avail[out] - Filled with the number of frames available in the buffer. * tstamp[out] - Filled with the hardware timestamp for the available frames. * This value is {0, 0} when the device hasn't actually started * reading or writing frames. * underruns[in,out] - Pointer to the underrun counter updated if there was * an underrun. * Returns: * 0 on success, negative error on failure. -EPIPE if severe underrun * happens. */ int cras_alsa_get_avail_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size, snd_pcm_uframes_t severe_underrun_frames, const char *dev_name, snd_pcm_uframes_t *avail, struct timespec *tstamp, unsigned int *underruns); /* Get the current alsa delay, make sure it's no bigger than the buffer size. * Args: * handle - The open PCM to configure. * buf_size - Number of frames in the ALSA buffer. * delay - Filled with the number of delay frames. * Returns: * 0 on success, negative error on failure. */ int cras_alsa_get_delay_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size, snd_pcm_sframes_t *delay); /* Wrapper for snd_pcm_mmap_begin where only buffer is concerned. * Offset and frames from cras_alsa_mmap_begin are neglected. * Args: * handle - The open PCM to configure. * dst - Pointer set to the area for reading/writing the audio. * underruns - counter to increment if an under-run occurs. * Returns: * zero on success, negative error code for fatal errors. */ int cras_alsa_mmap_get_whole_buffer(snd_pcm_t *handle, uint8_t **dst, unsigned int *underrun); /* Wrapper for snd_pcm_mmap_begin * Args: * handle - The open PCM to configure. * format_bytes - Number of bytes in a single frame. * dst - Pointer set to the area for reading/writing the audio. * offset - Filled with the offset to pass back to commit. * frames - Passed with the max number of frames to request. Filled with the * max number to use. * underruns - counter to increment if an under-run occurs. * Returns: * zero on success, negative error code for fatal * errors. */ int cras_alsa_mmap_begin(snd_pcm_t *handle, unsigned int format_bytes, uint8_t **dst, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, unsigned int *underruns); /* Wrapper for snd_pcm_mmap_commit * Args: * handle - The open PCM to configure. * offset - offset from call to mmap_begin. * frames - # of frames written/read. * underruns - counter to increment if an under-run occurs. * Returns: * zero on success, negative error code for fatal * errors. */ int cras_alsa_mmap_commit(snd_pcm_t *handle, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames, unsigned int *underruns); /* When the stream is suspended, due to a system suspend, loop until we can * resume it. Won't actually loop very much because the system will be * suspended. * Args: * handle - The open PCM to configure. * Returns: * zero on success, negative error code for fatal * errors. */ int cras_alsa_attempt_resume(snd_pcm_t *handle); #endif /* _CRAS_ALSA_HELPERS_H */