• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <alsa/asoundlib.h>
7 #include <limits.h>
8 #include <stdlib.h>
9 #include <syslog.h>
10 
11 #include "cras_alsa_helpers.h"
12 #include "cras_audio_format.h"
13 #include "cras_util.h"
14 
15 /* Macro to convert between snd_pcm_chmap_position(defined in
16  * alsa-lib since 1.0.27) and CRAS_CHANNEL, values of which are
17  * of the same order but shifted by 3.
18  */
19 #define CH_TO_ALSA(ch) ((ch) + 3)
20 #define CH_TO_CRAS(ch) ((ch) - 3)
21 
22 /* Assert the channel is defined in CRAS_CHANNELS. */
23 #define ALSA_CH_VALID(ch) ((ch >= SND_CHMAP_FL) && (ch <= SND_CHMAP_FRC))
24 
25 /* Time difference between two consecutive underrun logs. */
26 #define UNDERRUN_LOG_TIME_SECS 30
27 
28 /* Chances to give mmap_begin to work. */
29 static const size_t MAX_MMAP_BEGIN_ATTEMPTS = 3;
30 /* Time to sleep between resume attempts. */
31 static const size_t ALSA_SUSPENDED_SLEEP_TIME_US = 250000;
32 
33 /* What rates should we check for on this dev?
34  * Listed in order of preference. 0 terminalted. */
35 static const size_t test_sample_rates[] = {
36 	44100,
37 	48000,
38 	32000,
39 	96000,
40 	22050,
41 	16000,
42 	8000,
43 	4000,
44 	192000,
45 	0
46 };
47 
48 /* What channel counts shoud be checked on this dev?
49  * Listed in order of preference. 0 terminalted. */
50 static const size_t test_channel_counts[] = {
51 	10,
52 	6,
53 	4,
54 	2,
55 	1,
56 	8,
57 	0
58 };
59 
60 static const snd_pcm_format_t test_formats[] = {
61 	SND_PCM_FORMAT_S16_LE,
62 	SND_PCM_FORMAT_S24_LE,
63 	SND_PCM_FORMAT_S32_LE,
64 	SND_PCM_FORMAT_S24_3LE,
65 	(snd_pcm_format_t)0
66 };
67 
68 /* Looks up the list of channel map for the one can exactly matches
69  * the layout specified in fmt.
70  */
cras_chmap_caps_match(snd_pcm_chmap_query_t ** chmaps,struct cras_audio_format * fmt)71 static snd_pcm_chmap_query_t *cras_chmap_caps_match(
72 		snd_pcm_chmap_query_t **chmaps,
73 		struct cras_audio_format *fmt)
74 {
75 	size_t ch, i;
76 	int idx, matches;
77 	snd_pcm_chmap_query_t **chmap;
78 
79 	/* Search for channel map that already matches the order */
80 	for (chmap = chmaps; *chmap; chmap++) {
81 		if ((*chmap)->map.channels != fmt->num_channels)
82 			continue;
83 
84 		matches = 1;
85 		for (ch = 0; ch < CRAS_CH_MAX; ch++) {
86 			idx = fmt->channel_layout[ch];
87 			if (idx == -1)
88 				continue;
89 			if ((unsigned)idx >= (*chmap)->map.channels)
90 				continue;
91 			if ((*chmap)->map.pos[idx] != CH_TO_ALSA(ch)) {
92 				matches = 0;
93 				break;
94 			}
95 		}
96 		if (matches)
97 			return *chmap;
98 	}
99 
100 	/* Search for channel map that can arbitrarily swap order */
101 	for (chmap = chmaps; *chmap; chmap++) {
102 		if ((*chmap)->type == SND_CHMAP_TYPE_FIXED ||
103 		    (*chmap)->map.channels != fmt->num_channels)
104 			continue;
105 
106 		matches = 1;
107 		for (ch = 0; ch < CRAS_CH_MAX; ch++) {
108 			idx = fmt->channel_layout[ch];
109 			if (idx == -1)
110 				continue;
111 			int found = 0;
112 			for (i = 0; i < fmt->num_channels; i++) {
113 				if ((*chmap)->map.pos[i] == CH_TO_ALSA(ch)) {
114 					found = 1;
115 					break;
116 				}
117 			}
118 			if (found == 0) {
119 				matches = 0;
120 				break;
121 			}
122 		}
123 		if (matches && (*chmap)->type == SND_CHMAP_TYPE_VAR)
124 			return *chmap;
125 
126 		/* Check if channel map is a match by arbitrarily swap
127 		 * pair order */
128 		matches = 1;
129 		for (i = 0; i < fmt->num_channels; i += 2) {
130 			ch = CH_TO_CRAS((*chmap)->map.pos[i]);
131 			if (fmt->channel_layout[ch] & 0x01) {
132 				matches = 0;
133 				break;
134 			}
135 
136 			if (fmt->channel_layout[ch] + 1 !=
137 			    fmt->channel_layout[CH_TO_CRAS(
138 					    (*chmap)->map.pos[i + 1])]) {
139 				matches = 0;
140 				break;
141 			}
142 		}
143 		if (matches)
144 			return *chmap;
145 	}
146 
147 	return NULL;
148 }
149 
150 /* When the exact match does not exist, select the best valid
151  * channel map which can be supported by means of channel conversion
152  * matrix.
153  */
cras_chmap_caps_conv_matrix(snd_pcm_chmap_query_t ** chmaps,struct cras_audio_format * fmt)154 static snd_pcm_chmap_query_t *cras_chmap_caps_conv_matrix(
155 		snd_pcm_chmap_query_t **chmaps,
156 		struct cras_audio_format *fmt)
157 {
158 	float **conv_mtx;
159 	size_t i;
160 	snd_pcm_chmap_query_t **chmap;
161 	struct cras_audio_format *conv_fmt;
162 
163 	conv_fmt = cras_audio_format_create(fmt->format,
164 			fmt->frame_rate, fmt->num_channels);
165 
166 	for (chmap = chmaps; *chmap; chmap++) {
167 		if ((*chmap)->map.channels != fmt->num_channels)
168 			continue;
169 		for (i = 0; i < CRAS_CH_MAX; i++)
170 			conv_fmt->channel_layout[i] = -1;
171 		for (i = 0; i < conv_fmt->num_channels; i++) {
172 			if (!ALSA_CH_VALID((*chmap)->map.pos[i]))
173 				continue;
174 			conv_fmt->channel_layout[CH_TO_CRAS(
175 					(*chmap)->map.pos[i])] = i;
176 		}
177 
178 		/* Examine channel map by test creating a conversion matrix
179 		 * for each candidate. Once a non-null matrix is created,
180 		 * that channel map is considered supported and select it as
181 		 * the best match one.
182 		 */
183 		conv_mtx = cras_channel_conv_matrix_create(fmt, conv_fmt);
184 		if (conv_mtx) {
185 			cras_channel_conv_matrix_destroy(conv_mtx,
186 						 conv_fmt->num_channels);
187 			cras_audio_format_destroy(conv_fmt);
188 			return *chmap;
189 		}
190 	}
191 
192 	cras_audio_format_destroy(conv_fmt);
193 	return NULL;
194 }
195 
196 /* Finds the best channel map for given format and list of channel
197  * map capability.
198  */
cras_chmap_caps_best(snd_pcm_t * handle,snd_pcm_chmap_query_t ** chmaps,struct cras_audio_format * fmt)199 static snd_pcm_chmap_query_t *cras_chmap_caps_best(
200 		snd_pcm_t *handle,
201 		snd_pcm_chmap_query_t **chmaps,
202 		struct cras_audio_format *fmt)
203 {
204 	snd_pcm_chmap_query_t **chmap;
205 	snd_pcm_chmap_query_t *match;
206 
207 	match = cras_chmap_caps_match(chmaps, fmt);
208 	if (match)
209 		return match;
210 
211 	match = cras_chmap_caps_conv_matrix(chmaps, fmt);
212 	if (match)
213 		return match;
214 
215 	/* For capture stream, choose the first chmap matching channel
216 	 * count. Channel positions reported in this chmap will be used
217 	 * to fill correspond channels into client stream.
218 	 */
219 	if (snd_pcm_stream(handle) == SND_PCM_STREAM_CAPTURE)
220 		for (chmap = chmaps; *chmap; chmap++)
221 			if ((*chmap)->map.channels == fmt->num_channels)
222 				return *chmap;
223 	return NULL;
224 }
225 
cras_alsa_pcm_open(snd_pcm_t ** handle,const char * dev,snd_pcm_stream_t stream)226 int cras_alsa_pcm_open(snd_pcm_t **handle, const char *dev,
227 		       snd_pcm_stream_t stream)
228 {
229 	int rc;
230 	int retries = 3;
231 	static const unsigned int OPEN_RETRY_DELAY_US = 100000;
232 
233 retry_open:
234 	rc = snd_pcm_open(handle,
235 			  dev,
236 			  stream,
237 			  SND_PCM_NONBLOCK |
238 			  SND_PCM_NO_AUTO_RESAMPLE |
239 			  SND_PCM_NO_AUTO_CHANNELS |
240 			  SND_PCM_NO_AUTO_FORMAT);
241 	if (rc == -EBUSY && --retries) {
242 		usleep(OPEN_RETRY_DELAY_US);
243 		goto retry_open;
244 	}
245 
246 	return rc;
247 }
248 
cras_alsa_pcm_close(snd_pcm_t * handle)249 int cras_alsa_pcm_close(snd_pcm_t *handle)
250 {
251 	return snd_pcm_close(handle);
252 }
253 
cras_alsa_pcm_start(snd_pcm_t * handle)254 int cras_alsa_pcm_start(snd_pcm_t *handle)
255 {
256 	return snd_pcm_start(handle);
257 }
258 
cras_alsa_pcm_drain(snd_pcm_t * handle)259 int cras_alsa_pcm_drain(snd_pcm_t *handle)
260 {
261 	return snd_pcm_drain(handle);
262 }
263 
cras_alsa_resume_appl_ptr(snd_pcm_t * handle,snd_pcm_uframes_t ahead)264 int cras_alsa_resume_appl_ptr(snd_pcm_t *handle, snd_pcm_uframes_t ahead)
265 {
266 	int rc;
267 	snd_pcm_uframes_t period_frames, buffer_frames;
268 	snd_pcm_sframes_t to_move, avail_frames;
269 	rc = snd_pcm_avail(handle);
270 	if (rc == -EPIPE || rc == -ESTRPIPE) {
271 		cras_alsa_attempt_resume(handle);
272 		avail_frames = 0;
273 	} else if (rc < 0) {
274 		syslog(LOG_ERR, "Fail to get avail frames: %s",
275 		       snd_strerror(rc));
276 		return rc;
277 	} else {
278 		avail_frames = rc;
279 	}
280 
281 	rc = snd_pcm_get_params(handle, &buffer_frames, &period_frames);
282 	if (rc < 0) {
283 		syslog(LOG_ERR, "Fail to get buffer size: %s",
284 		       snd_strerror(rc));
285 		return rc;
286 	}
287 
288 	to_move = avail_frames - buffer_frames + ahead;
289 	if (to_move > 0) {
290 		rc = snd_pcm_forward(handle, to_move);
291 	} else if (to_move < 0) {
292 		rc = snd_pcm_rewind(handle, -to_move);
293 	} else {
294 		return 0;
295 	}
296 
297 	if (rc < 0) {
298 		syslog(LOG_ERR, "Fail to resume appl_ptr: %s",
299 		       snd_strerror(rc));
300 		return rc;
301 	}
302 	return 0;
303 }
304 
cras_alsa_set_channel_map(snd_pcm_t * handle,struct cras_audio_format * fmt)305 int cras_alsa_set_channel_map(snd_pcm_t *handle,
306 			      struct cras_audio_format *fmt)
307 {
308 	size_t i, ch;
309 	snd_pcm_chmap_query_t **chmaps;
310 	snd_pcm_chmap_query_t *match;
311 
312 	if (fmt->num_channels <= 2)
313 		return 0;
314 
315 	chmaps = snd_pcm_query_chmaps(handle);
316 	if (chmaps == NULL) {
317 		syslog(LOG_WARNING, "No chmap queried! Skip chmap set");
318 		goto done;
319 	}
320 
321 	match = cras_chmap_caps_best(handle, chmaps, fmt);
322 	if (!match) {
323 		syslog(LOG_ERR, "Unable to find the best channel map");
324 		goto done;
325 	}
326 
327 	/* A channel map could match the layout after channels
328 	 * pair/arbitrary swapped. Modified the channel positions
329 	 * before set to HW.
330 	 */
331 	for (i = 0; i < fmt->num_channels; i++) {
332 		for (ch = 0; ch < CRAS_CH_MAX; ch++)
333 			if (fmt->channel_layout[ch] == (int)i)
334 				break;
335 		if (ch != CRAS_CH_MAX)
336 			match->map.pos[i] = CH_TO_ALSA(ch);
337 	}
338 	if (snd_pcm_set_chmap(handle, &match->map) != 0)
339 		syslog(LOG_ERR, "Unable to set channel map");
340 
341 done:
342 	snd_pcm_free_chmaps(chmaps);
343 	return 0;
344 }
345 
cras_alsa_get_channel_map(snd_pcm_t * handle,struct cras_audio_format * fmt)346 int cras_alsa_get_channel_map(snd_pcm_t *handle,
347 			      struct cras_audio_format *fmt)
348 {
349 	snd_pcm_chmap_query_t **chmaps;
350 	snd_pcm_chmap_query_t *match;
351 	int rc = 0;
352 	size_t i;
353 
354 	chmaps = snd_pcm_query_chmaps(handle);
355 	if (chmaps == NULL) {
356 		rc = -EINVAL;
357 		goto done;
358 	}
359 
360 	match = cras_chmap_caps_best(handle, chmaps, fmt);
361 	if (!match) {
362 		syslog(LOG_ERR, "Unable to find the best channel map");
363 		rc = -1;
364 		goto done;
365 	}
366 
367 	/* Fill back the selected channel map so channel converter can
368 	 * handle it. */
369 	for (i = 0; i < CRAS_CH_MAX; i++)
370 		fmt->channel_layout[i] = -1;
371 	for (i = 0; i < fmt->num_channels; i++) {
372 		if (!ALSA_CH_VALID(match->map.pos[i]))
373 			continue;
374 		fmt->channel_layout[CH_TO_CRAS(match->map.pos[i])] = i;
375 	}
376 
377 	/* Handle the special channel map {SND_CHMAP_MONO} */
378 	if (match->map.channels == 1 && match->map.pos[0] == SND_CHMAP_MONO)
379 		fmt->channel_layout[CRAS_CH_FC] = 0;
380 
381 done:
382 	snd_pcm_free_chmaps(chmaps);
383 	return rc;
384 }
385 
cras_alsa_fill_properties(snd_pcm_t * handle,size_t ** rates,size_t ** channel_counts,snd_pcm_format_t ** formats)386 int cras_alsa_fill_properties(snd_pcm_t *handle,
387 			      size_t **rates, size_t **channel_counts,
388 			      snd_pcm_format_t **formats)
389 {
390 	int rc;
391 	size_t i, num_found;
392 	snd_pcm_hw_params_t *params;
393 
394 	snd_pcm_hw_params_alloca(&params);
395 
396 	rc = snd_pcm_hw_params_any(handle, params);
397 	if (rc < 0) {
398 		syslog(LOG_ERR, "snd_pcm_hw_params_any: %s", snd_strerror(rc));
399 		return rc;
400 	}
401 
402 	*rates = (size_t *)malloc(sizeof(test_sample_rates));
403 	if (*rates == NULL)
404 		return -ENOMEM;
405 	*channel_counts = (size_t *)malloc(sizeof(test_channel_counts));
406 	if (*channel_counts == NULL) {
407 		free(*rates);
408 		return -ENOMEM;
409 	}
410 	*formats = (snd_pcm_format_t *)malloc(sizeof(test_formats));
411 	if (*formats == NULL) {
412 		free(*channel_counts);
413 		free(*rates);
414 		return -ENOMEM;
415 	}
416 
417 	num_found = 0;
418 	for (i = 0; test_sample_rates[i] != 0; i++) {
419 		rc = snd_pcm_hw_params_test_rate(handle, params,
420 						 test_sample_rates[i], 0);
421 		if (rc == 0)
422 			(*rates)[num_found++] = test_sample_rates[i];
423 	}
424 	(*rates)[num_found] = 0;
425 	if (num_found == 0) {
426 		syslog(LOG_WARNING, "No valid sample rates.");
427 		return -EINVAL;
428 	}
429 
430 	num_found = 0;
431 	for (i = 0; test_channel_counts[i] != 0; i++) {
432 		rc = snd_pcm_hw_params_test_channels(handle, params,
433 						     test_channel_counts[i]);
434 		if (rc == 0)
435 			(*channel_counts)[num_found++] = test_channel_counts[i];
436 	}
437 	(*channel_counts)[num_found] = 0;
438 	if (num_found == 0) {
439 		syslog(LOG_WARNING, "No valid channel counts found.");
440 		return -EINVAL;
441 	}
442 
443 	num_found = 0;
444 	for (i = 0; test_formats[i] != 0; i++) {
445 		rc = snd_pcm_hw_params_test_format(handle, params,
446 						   test_formats[i]);
447 		if (rc == 0)
448 			(*formats)[num_found++] = test_formats[i];
449 	}
450 	(*formats)[num_found] = (snd_pcm_format_t)0;
451 	if (num_found == 0) {
452 		syslog(LOG_WARNING, "No valid sample formats.");
453 		return -EINVAL;
454 	}
455 
456 	return 0;
457 }
458 
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)459 int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
460 			   snd_pcm_uframes_t *buffer_frames, int period_wakeup,
461 			   unsigned int dma_period_time)
462 {
463 	unsigned int rate, ret_rate;
464 	int err;
465 	snd_pcm_hw_params_t *hwparams;
466 
467 	rate = format->frame_rate;
468 	snd_pcm_hw_params_alloca(&hwparams);
469 
470 	err = snd_pcm_hw_params_any(handle, hwparams);
471 	if (err < 0) {
472 		syslog(LOG_ERR, "hw_params_any failed %s\n", snd_strerror(err));
473 		return err;
474 	}
475 	/* Disable hardware resampling. */
476 	err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 0);
477 	if (err < 0) {
478 		syslog(LOG_ERR, "Disabling resampling %s\n", snd_strerror(err));
479 		return err;
480 	}
481 	/* Always interleaved. */
482 	err = snd_pcm_hw_params_set_access(handle, hwparams,
483 					   SND_PCM_ACCESS_MMAP_INTERLEAVED);
484 	if (err < 0) {
485 		syslog(LOG_ERR, "Setting interleaved %s\n", snd_strerror(err));
486 		return err;
487 	}
488 	/* If period_wakeup flag is not set, try to disable ALSA wakeups,
489 	 * we'll keep a timer. */
490 	if (!period_wakeup &&
491 	    snd_pcm_hw_params_can_disable_period_wakeup(hwparams)) {
492 		err = snd_pcm_hw_params_set_period_wakeup(handle, hwparams, 0);
493 		if (err < 0)
494 			syslog(LOG_WARNING, "disabling wakeups %s\n",
495 			       snd_strerror(err));
496 	}
497 	/* Setup the period time so that the hardware pulls the right amount
498 	 * of data at the right time. */
499 	if (dma_period_time) {
500 		int dir = 0;
501 		unsigned int original = dma_period_time;
502 
503 		err = snd_pcm_hw_params_set_period_time_near(
504 				handle, hwparams, &dma_period_time, &dir);
505 		if (err < 0) {
506 			syslog(LOG_ERR, "could not set period time: %s",
507 			       snd_strerror(err));
508 			return err;
509 		} else if (original != dma_period_time) {
510 			syslog(LOG_DEBUG, "period time set to: %u",
511 			       dma_period_time);
512 		}
513 	}
514 	/* Set the sample format. */
515 	err = snd_pcm_hw_params_set_format(handle, hwparams,
516 					   format->format);
517 	if (err < 0) {
518 		syslog(LOG_ERR, "set format %s\n", snd_strerror(err));
519 		return err;
520 	}
521 	/* Set the stream rate. */
522 	ret_rate = rate;
523 	err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &ret_rate, 0);
524 	if (err < 0) {
525 		syslog(LOG_ERR, "set_rate_near %iHz %s\n", rate,
526 		       snd_strerror(err));
527 		return err;
528 	}
529 	if (ret_rate != rate) {
530 		syslog(LOG_ERR, "tried for %iHz, settled for %iHz)\n", rate,
531 		       ret_rate);
532 		return -EINVAL;
533 	}
534 	/* Set the count of channels. */
535 	err = snd_pcm_hw_params_set_channels(handle, hwparams,
536 					     format->num_channels);
537 	if (err < 0) {
538 		syslog(LOG_ERR, "set_channels %s\n", snd_strerror(err));
539 		return err;
540 	}
541 
542 	/* Make sure buffer frames is even, or snd_pcm_hw_params will
543 	 * return invalid argument error. */
544 	err = snd_pcm_hw_params_get_buffer_size_max(hwparams,
545 						    buffer_frames);
546 	if (err < 0)
547 		syslog(LOG_WARNING, "get buffer max %s\n", snd_strerror(err));
548 
549 	*buffer_frames &= ~0x01;
550 	err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams,
551 						    buffer_frames);
552 	if (err < 0) {
553 		syslog(LOG_ERR, "set_buffer_size_max %s", snd_strerror(err));
554 		return err;
555 	}
556 
557 	syslog(LOG_DEBUG, "buffer size set to %u\n",
558 	       (unsigned int)*buffer_frames);
559 
560 	/* Finally, write the parameters to the device. */
561 	err = snd_pcm_hw_params(handle, hwparams);
562 	if (err < 0) {
563 		syslog(LOG_ERR, "hw_params: %s: rate: %u, ret_rate: %u, "
564 		       "channel: %zu, format: %u\n", snd_strerror(err), rate,
565 		       ret_rate, format->num_channels, format->format);
566 		return err;
567 	}
568 	return 0;
569 }
570 
cras_alsa_set_swparams(snd_pcm_t * handle,int * enable_htimestamp)571 int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp)
572 {
573 	int err;
574 	snd_pcm_sw_params_t *swparams;
575 	snd_pcm_uframes_t boundary;
576 
577 	snd_pcm_sw_params_alloca(&swparams);
578 
579 	err = snd_pcm_sw_params_current(handle, swparams);
580 	if (err < 0) {
581 		syslog(LOG_ERR, "sw_params_current: %s\n", snd_strerror(err));
582 		return err;
583 	}
584 	err = snd_pcm_sw_params_get_boundary(swparams, &boundary);
585 	if (err < 0) {
586 		syslog(LOG_ERR, "get_boundary: %s\n", snd_strerror(err));
587 		return err;
588 	}
589 	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, boundary);
590 	if (err < 0) {
591 		syslog(LOG_ERR, "set_stop_threshold: %s\n", snd_strerror(err));
592 		return err;
593 	}
594 	/* Don't auto start. */
595 	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, LONG_MAX);
596 	if (err < 0) {
597 		syslog(LOG_ERR, "set_stop_threshold: %s\n", snd_strerror(err));
598 		return err;
599 	}
600 
601 	/* Disable period events. */
602 	err = snd_pcm_sw_params_set_period_event(handle, swparams, 0);
603 	if (err < 0) {
604 		syslog(LOG_ERR, "set_period_event: %s\n", snd_strerror(err));
605 		return err;
606 	}
607 
608 	if (*enable_htimestamp) {
609 		/* Use MONOTONIC_RAW time-stamps. */
610 		err = snd_pcm_sw_params_set_tstamp_type(
611 				handle, swparams,
612 				SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW);
613 		if (err < 0) {
614 			syslog(LOG_ERR, "set_tstamp_type: %s\n",
615 			       snd_strerror(err));
616 			return err;
617 		}
618 		err = snd_pcm_sw_params_set_tstamp_mode(
619 				handle, swparams, SND_PCM_TSTAMP_ENABLE);
620 		if (err < 0) {
621 			syslog(LOG_ERR, "set_tstamp_mode: %s\n",
622 			       snd_strerror(err));
623 			return err;
624 		}
625 	}
626 
627 	/* This hack is required because ALSA-LIB does not provide any way to
628 	 * detect whether MONOTONIC_RAW timestamps are supported by the kernel.
629 	 * In ALSA-LIB, the code checks the hardware protocol version. */
630 	err = snd_pcm_sw_params(handle, swparams);
631 	if (err == -EINVAL && *enable_htimestamp) {
632 		*enable_htimestamp = 0;
633 		syslog(LOG_WARNING,
634 		       "MONOTONIC_RAW timestamps are not supported.");
635 
636 		err = snd_pcm_sw_params_set_tstamp_type(
637 				handle, swparams,
638 				SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY);
639 		if (err < 0) {
640 			syslog(LOG_ERR, "set_tstamp_type: %s\n",
641 			       snd_strerror(err));
642 			return err;
643 		}
644 		err = snd_pcm_sw_params_set_tstamp_mode(
645 				handle, swparams, SND_PCM_TSTAMP_NONE);
646 		if (err < 0) {
647 			syslog(LOG_ERR, "set_tstamp_mode: %s\n",
648 			       snd_strerror(err));
649 			return err;
650 		}
651 
652 		err = snd_pcm_sw_params(handle, swparams);
653 	}
654 
655 	if (err < 0) {
656 		syslog(LOG_ERR, "sw_params: %s\n", snd_strerror(err));
657 		return err;
658 	}
659 	return 0;
660 }
661 
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)662 int cras_alsa_get_avail_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size,
663 			       snd_pcm_uframes_t severe_underrun_frames,
664 			       const char *dev_name,
665 			       snd_pcm_uframes_t *avail,
666 			       struct timespec *tstamp)
667 {
668 	snd_pcm_sframes_t frames;
669 	int rc = 0;
670 	static struct timespec tstamp_last_underrun_log =
671 			{.tv_sec = 0, .tv_nsec = 0};
672 
673 	/* Use snd_pcm_avail still to ensure that the hardware pointer is
674 	 * up to date. Otherwise, we could use the deprecated snd_pcm_hwsync().
675 	 * IMO this is a deficiency in the ALSA API.
676 	 */
677 	frames = snd_pcm_avail(handle);
678 	if (frames >= 0)
679 		rc = snd_pcm_htimestamp(handle, avail, tstamp);
680 	else
681 		rc = frames;
682 	if (rc == -EPIPE || rc == -ESTRPIPE) {
683 		cras_alsa_attempt_resume(handle);
684 		rc = 0;
685 		goto error;
686 	} else if (rc < 0) {
687 		syslog(LOG_ERR, "pcm_avail error %s, %s\n",
688 		       dev_name, snd_strerror(rc));
689 		goto error;
690 	} else if (frames > (snd_pcm_sframes_t)buf_size) {
691 		struct timespec tstamp_now;
692 		clock_gettime(CLOCK_MONOTONIC_RAW, &tstamp_now);
693 		/* Limit the log rate. */
694 		if ((tstamp_now.tv_sec - tstamp_last_underrun_log.tv_sec) >
695 		    UNDERRUN_LOG_TIME_SECS) {
696 			syslog(LOG_ERR,
697 			       "pcm_avail returned frames larger than buf_size: "
698 			       "%s: %ld > %lu\n",
699 			       dev_name, frames, buf_size);
700 			tstamp_last_underrun_log.tv_sec = tstamp_now.tv_sec;
701 			tstamp_last_underrun_log.tv_nsec = tstamp_now.tv_nsec;
702 		}
703 		if ((frames - (snd_pcm_sframes_t)buf_size) >
704 		    (snd_pcm_sframes_t)severe_underrun_frames) {
705 			rc = -EPIPE;
706 			goto error;
707 		} else {
708 			frames = buf_size;
709 		}
710 	}
711 	*avail = frames;
712 	return 0;
713 
714 error:
715 	*avail = 0;
716 	tstamp->tv_sec = 0;
717 	tstamp->tv_nsec = 0;
718 	return rc;
719 }
720 
cras_alsa_get_delay_frames(snd_pcm_t * handle,snd_pcm_uframes_t buf_size,snd_pcm_sframes_t * delay)721 int cras_alsa_get_delay_frames(snd_pcm_t *handle, snd_pcm_uframes_t buf_size,
722 			       snd_pcm_sframes_t *delay)
723 {
724 	int rc;
725 
726 	rc = snd_pcm_delay(handle, delay);
727 	if (rc < 0)
728 		return rc;
729 	if (*delay > (snd_pcm_sframes_t)buf_size)
730 		*delay = buf_size;
731 	if (*delay < 0)
732 		*delay = 0;
733 	return 0;
734 }
735 
736 /*
737  * Attempts to resume a PCM.
738  * Note that this path does not get executed for default playback/capture
739  * stream. Default playback/capture stream are removed from the device
740  * upon suspend, and re-attached to the device after resume.
741  * The only stream that lives across suspend resume is hotword stream.
742  */
cras_alsa_attempt_resume(snd_pcm_t * handle)743 int cras_alsa_attempt_resume(snd_pcm_t *handle)
744 {
745 	int rc;
746 
747 	syslog(LOG_INFO, "System suspended.");
748 	while ((rc = snd_pcm_resume(handle)) == -EAGAIN)
749 		usleep(ALSA_SUSPENDED_SLEEP_TIME_US);
750 	if (rc < 0) {
751 		/*
752 		 * Some devices do not support snd_pcm_resume, that is
753 		 * acceptable.
754 		 */
755 		syslog(LOG_INFO, "System suspended, failed to resume %s.",
756 		       snd_strerror(rc));
757 		rc = snd_pcm_prepare(handle);
758 		if (rc < 0) {
759 			syslog(LOG_ERR, "Suspended, failed to prepare: %s.",
760 			       snd_strerror(rc));
761 		}
762 		/*
763 		 * CRAS does not use auto-start (start_threshold = 0), so start
764 		 * PCM after it is prepared. This is only for hotword stream.
765 		 */
766 		rc = snd_pcm_start(handle);
767 		if (rc < 0) {
768 			syslog(LOG_ERR, "Suspended, failed to start: %s.",
769 			       snd_strerror(rc));
770 		}
771 	}
772 	return rc;
773 }
774 
cras_alsa_mmap_get_whole_buffer(snd_pcm_t * handle,uint8_t ** dst)775 int cras_alsa_mmap_get_whole_buffer(snd_pcm_t *handle, uint8_t **dst)
776 {
777 	snd_pcm_uframes_t offset;
778 	/* The purpose of calling cras_alsa_mmap_begin is to get the base
779 	 * address of the buffer. The requested and retrieved frames are not
780 	 * meaningful here.
781 	 * However, we need to set a non-zero requested frames to get a
782 	 * non-zero retrieved frames. This is to avoid the error checking in
783 	 * snd_pcm_mmap_begin, where it judges retrieved frames being 0 as a
784 	 * failure.
785 	 */
786 	snd_pcm_uframes_t frames = 1;
787 
788 	return cras_alsa_mmap_begin(handle, 0, dst, &offset, &frames);
789 }
790 
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)791 int cras_alsa_mmap_begin(snd_pcm_t *handle, unsigned int format_bytes,
792 			 uint8_t **dst, snd_pcm_uframes_t *offset,
793 			 snd_pcm_uframes_t *frames)
794 {
795 	int rc;
796 	unsigned int attempts = 0;
797 	const snd_pcm_channel_area_t *my_areas;
798 
799 	while (attempts++ < MAX_MMAP_BEGIN_ATTEMPTS) {
800 		rc = snd_pcm_mmap_begin(handle, &my_areas, offset, frames);
801 		if (rc == -ESTRPIPE) {
802 			/* First handle suspend/resume. */
803 			rc = cras_alsa_attempt_resume(handle);
804 			if (rc < 0)
805 				return rc;
806 			continue; /* Recovered from suspend, try again. */
807 		} else if (rc < 0) {
808 			/* If we can recover, continue and try again. */
809 			if (snd_pcm_recover(handle, rc, 0) == 0)
810 				continue;
811 			syslog(LOG_INFO, "recover failed begin: %s\n",
812 			       snd_strerror(rc));
813 			return rc;
814 		}
815 		/* Available frames could be zero right after input pcm handle
816 		 * resumed. As for output pcm handle, some error has occurred
817 		 * when mmap_begin return zero frames, return -EIO for that
818 		 * case.
819 		 */
820 		if (snd_pcm_stream(handle) == SND_PCM_STREAM_PLAYBACK &&
821 				*frames == 0) {
822 			syslog(LOG_INFO, "mmap_begin set frames to 0.");
823 			return -EIO;
824 		}
825 		*dst = (uint8_t *)my_areas[0].addr + (*offset) * format_bytes;
826 		return 0;
827 	}
828 	return -EIO;
829 }
830 
cras_alsa_mmap_commit(snd_pcm_t * handle,snd_pcm_uframes_t offset,snd_pcm_uframes_t frames)831 int cras_alsa_mmap_commit(snd_pcm_t *handle, snd_pcm_uframes_t offset,
832 			  snd_pcm_uframes_t frames)
833 {
834 	int rc;
835 	snd_pcm_sframes_t res;
836 
837 	res = snd_pcm_mmap_commit(handle, offset, frames);
838 	if (res != (snd_pcm_sframes_t)frames) {
839 		res = res >= 0 ? (int)-EPIPE : res;
840 		if (res == -ESTRPIPE) {
841 			/* First handle suspend/resume. */
842 			rc = cras_alsa_attempt_resume(handle);
843 			if (rc < 0)
844 				return rc;
845 		} else {
846 			/* If we can recover, continue and try again. */
847 			rc = snd_pcm_recover(handle, res, 0);
848 			if (rc < 0) {
849 				syslog(LOG_ERR,
850 				       "mmap_commit: pcm_recover failed: %s\n",
851 				       snd_strerror(rc));
852 				return rc;
853 			}
854 		}
855 	}
856 	return 0;
857 }
858