summaryrefslogtreecommitdiff
path: root/cras/src/server/cras_alsa_helpers.h
blob: 01a42aea5dcd3878b5493a03fa978aeeab533fde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* 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:
 *    handle - The open PCM to configure.
 *    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(snd_pcm_t *handle, 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.
 * Returns:
 *    0 on success, negative error on failure.
 */
int cras_alsa_set_swparams(snd_pcm_t *handle);

/* 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.
 * 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);

/* 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.
 * Returns:
 *    zero on success, negative error code for fatal errors.
 */
int cras_alsa_mmap_get_whole_buffer(snd_pcm_t *handle, uint8_t **dst);

/* 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.
 * 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);

/* 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.
 * 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);

/* 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 */