1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 /*
7  * Alsa Helpers - Keeps the interface to alsa localized to this file.
8  */
9 
10 #ifndef _CRAS_ALSA_HELPERS_H
11 #define _CRAS_ALSA_HELPERS_H
12 
13 #include <alsa/asoundlib.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 
17 struct cras_audio_format;
18 
19 
20 /* Sets the channel layout from given format to the pcm handle.
21  * Args:
22  *    handle - Pointer to the opened pcm to set channel map to.
23  *    fmt - The format containing the channel layout info.
24  * Returns:
25  *    0 if a matched channel map is set to HW, -1 otherwise.
26  */
27 int cras_alsa_set_channel_map(snd_pcm_t *handle,
28 			      struct cras_audio_format *fmt);
29 
30 /*  Gets the supported channel mapping of the pcm handle which matches
31  *  the channel layout in the format.
32  *  Args:
33  *     handle - Pointer to the opened pcm to get channel map info.
34  *     fmt - The format to fill channel layout into.
35  *  Returns:
36  *     0 if an exactly matched channel map is found, -1 otherwise.
37  */
38 int cras_alsa_get_channel_map(snd_pcm_t *handle,
39 			      struct cras_audio_format *fmt);
40 
41 /* Opens an alsa device, thin wrapper to snd_pcm_open.
42  * Args:
43  *    handle - Filled with a pointer to the opened pcm.
44  *    dev - Path to the alsa device to test.
45  *    stream - Alsa stream type, input or output.
46  * Returns:
47  *    See docs for snd_pcm_open.
48  */
49 int cras_alsa_pcm_open(snd_pcm_t **handle, const char *dev,
50 		       snd_pcm_stream_t stream);
51 
52 /* Closes an alsa device, thin wrapper to snd_pcm_close.
53  * Args:
54  *    handle - Filled with a pointer to the opened pcm.
55  * Returns:
56  *    See docs for snd_pcm_close.
57  */
58 int cras_alsa_pcm_close(snd_pcm_t *handle);
59 
60 /* Starts an alsa device, thin wrapper to snd_pcm_start.
61  * Args:
62  *    handle - Filled with a pointer to the opened pcm.
63  * Returns:
64  *    See docs for snd_pcm_start.
65  */
66 int cras_alsa_pcm_start(snd_pcm_t *handle);
67 
68 /* Drains an alsa device, thin wrapper to snd_pcm_drain.
69  * Args:
70  *    handle - Filled with a pointer to the opened pcm.
71  * Returns:
72  *    See docs for snd_pcm_drain.
73  */
74 int cras_alsa_pcm_drain(snd_pcm_t *handle);
75 
76 /* Forward/rewind appl_ptr so it becomes ahead of hw_ptr by fuzz samples.
77  * After moving appl_ptr, device can play the new samples as quick as possible.
78  *    avail = buffer_frames - appl_ptr + hw_ptr
79  * => hw_ptr - appl_ptr = avail - buffer_frames.
80  * The difference between hw_ptr and app_ptr can be inferred from snd_pcm_avail.
81  * So the amount of frames to forward appl_ptr is
82  * avail - buffer_frames + fuzz.
83  * When hw_ptr is wrapped around boundary, this value may be negative. Use
84  * snd_pcm_rewind to move appl_ptr backward.
85  *
86  * Case 1: avail - buffer_frames + fuzz > 0
87  *
88  * -------|----------|-----------------------------------
89  *      app_ptr     hw_ptr
90  *        |------------->| forward target
91  *
92  * Case 2: avail - buffer_frames + fuzz < 0
93  *
94  * -------|----------|-----------------------------------
95  *      hw_ptr      app_ptr
96  *           |<------| rewind target
97  *
98  * Args:
99  *    handle - Filled with a pointer to the opened pcm.
100  *    ahead - Number of frames appl_ptr should be ahead of hw_ptr.
101  * Returns:
102  *    0 on success. A negative error code on failure.
103  */
104 int cras_alsa_resume_appl_ptr(snd_pcm_t *handle, snd_pcm_uframes_t ahead);
105 
106 /* Probes properties of the alsa device.
107  * Args:
108  *    handle - The open PCM to configure.
109  *    rates - Pointer that will be set to the arrary of valid samples rates.
110  *            Must be freed by the caller.
111  *    channel_counts - Pointer that will be set to the array of valid channel
112  *                     counts.  Must be freed by the caller.
113  *    formats - Pointer that will be set to the arrary of valid PCM formats.
114  *              Must be freed by the caller.
115  * Returns:
116  *   0 on success.  On failure an error code from alsa or -ENOMEM.
117  */
118 int cras_alsa_fill_properties(snd_pcm_t *handle,
119 			      size_t **rates, size_t **channel_counts,
120 			      snd_pcm_format_t **formats);
121 
122 /* Sets up the hwparams to alsa.
123  * Args:
124  *    handle - The open PCM to configure.
125  *    format - The audio format desired for playback/capture.
126  *    buffer_frames - Number of frames in the ALSA buffer.
127  *    period_wakeup - Flag to determine if period_wakeup is required
128  *                      0 - disable, 1 - enable
129  *    dma_period_time - If non-zero, set the dma period time to this value
130  *                      (in microseconds).
131  * Returns:
132  *    0 on success, negative error on failure.
133  */
134 int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
135 			   snd_pcm_uframes_t *buffer_frames, int period_wakeup,
136 			   unsigned int dma_period_time);
137 
138 /* Sets up the swparams to alsa.
139  * Args:
140  *    handle - The open PCM to configure.
141  *    enable_htimestamp - If non-zero, enable and configure hardware timestamps,
142  *                        updated to reflect whether MONOTONIC RAW htimestamps
143  *                        are supported by the kernel implementation.
144  * Returns:
145  *    0 on success, negative error on failure.
146  */
147 int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp);
148 
149 /* Get the number of used frames in the alsa buffer.
150  *
151  * When underrun is not severe, this function masks the underrun situation
152  * and set avail as 0. When underrun is severe, returns -EPIPE so caller
153  * can handle it.
154  * Args:
155  *    handle[in] - The open PCM to configure.
156  *    buf_size[in] - Number of frames in the ALSA buffer.
157  *    severe_underrun_frames[in] - Number of frames as the threshold for severe
158  *                                 underrun.
159  *    dev_name[in] - Device name for logging.
160  *    avail[out] - Filled with the number of frames available in the buffer.
161  *    tstamp[out] - Filled with the hardware timestamp for the available frames.
162  *                  This value is {0, 0} when the device hasn't actually started
163  *                  reading or writing frames.
164  * Returns:
165  *    0 on success, negative error on failure. -EPIPE if severe underrun
166  *    happens.
167  */
168 int cras_alsa_get_avail_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size,
169 			       snd_pcm_uframes_t severe_underrun_frames,
170 			       const char *dev_name,
171 			       snd_pcm_uframes_t *avail,
172 			       struct timespec *tstamp);
173 
174 /* Get the current alsa delay, make sure it's no bigger than the buffer size.
175  * Args:
176  *    handle - The open PCM to configure.
177  *    buf_size - Number of frames in the ALSA buffer.
178  *    delay - Filled with the number of delay frames.
179  * Returns:
180  *    0 on success, negative error on failure.
181  */
182 int cras_alsa_get_delay_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size,
183 			       snd_pcm_sframes_t *delay);
184 
185 /* Wrapper for snd_pcm_mmap_begin where only buffer is concerned.
186  * Offset and frames from cras_alsa_mmap_begin are neglected.
187  * Args:
188  *    handle - The open PCM to configure.
189  *    dst - Pointer set to the area for reading/writing the audio.
190  * Returns:
191  *    zero on success, negative error code for fatal errors.
192  */
193 int cras_alsa_mmap_get_whole_buffer(snd_pcm_t *handle, uint8_t **dst);
194 
195 /* Wrapper for snd_pcm_mmap_begin
196  * Args:
197  *    handle - The open PCM to configure.
198  *    format_bytes - Number of bytes in a single frame.
199  *    dst - Pointer set to the area for reading/writing the audio.
200  *    offset - Filled with the offset to pass back to commit.
201  *    frames - Passed with the max number of frames to request. Filled with the
202  *        max number to use.
203  * Returns:
204  *    zero on success, negative error code for fatal
205  *    errors.
206  */
207 int cras_alsa_mmap_begin(snd_pcm_t *handle, unsigned int format_bytes,
208 			 uint8_t **dst, snd_pcm_uframes_t *offset,
209 			 snd_pcm_uframes_t *frames);
210 
211 /* Wrapper for snd_pcm_mmap_commit
212  * Args:
213  *    handle - The open PCM to configure.
214  *    offset - offset from call to mmap_begin.
215  *    frames - # of frames written/read.
216  * Returns:
217  *    zero on success, negative error code for fatal
218  *    errors.
219  */
220 int cras_alsa_mmap_commit(snd_pcm_t *handle, snd_pcm_uframes_t offset,
221 			  snd_pcm_uframes_t frames);
222 
223 /* When the stream is suspended, due to a system suspend, loop until we can
224  * resume it. Won't actually loop very much because the system will be
225  * suspended.
226  * Args:
227  *    handle - The open PCM to configure.
228  * Returns:
229  *    zero on success, negative error code for fatal
230  *    errors.
231  */
232 int cras_alsa_attempt_resume(snd_pcm_t *handle);
233 
234 #endif /* _CRAS_ALSA_HELPERS_H */
235