• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // xfer-libasound.c - receive/transmit frames by alsa-lib.
4 //
5 // Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6 //
7 // Licensed under the terms of the GNU General Public License, version 2.
8 
9 #include "xfer-libasound.h"
10 #include "misc.h"
11 
12 static const char *const sched_model_labels [] = {
13 	[SCHED_MODEL_IRQ] = "irq",
14 	[SCHED_MODEL_TIMER] = "timer",
15 };
16 
17 enum no_short_opts {
18         // 200 or later belong to non us-ascii character set.
19 	OPT_PERIOD_SIZE = 200,
20 	OPT_BUFFER_SIZE,
21 	OPT_WAITER_TYPE,
22 	OPT_SCHED_MODEL,
23 	OPT_DISABLE_RESAMPLE,
24 	OPT_DISABLE_CHANNELS,
25 	OPT_DISABLE_FORMAT,
26 	OPT_DISABLE_SOFTVOL,
27 	OPT_FATAL_ERRORS,
28 	OPT_TEST_NOWAIT,
29 	// Obsoleted.
30 	OPT_TEST_POSITION,
31 	OPT_TEST_COEF,
32 };
33 
34 #define S_OPTS	"D:NMF:B:A:R:T:m:"
35 static const struct option l_opts[] = {
36 	{"device",		1, 0, 'D'},
37 	{"nonblock",		0, 0, 'N'},
38 	{"mmap",		0, 0, 'M'},
39 	{"period-time",		1, 0, 'F'},
40 	{"buffer-time",		1, 0, 'B'},
41 	{"period-size",		1, 0, OPT_PERIOD_SIZE},
42 	{"buffer-size",		1, 0, OPT_BUFFER_SIZE},
43 	{"avail-min",		1, 0, 'A'},
44 	{"start-delay",		1, 0, 'R'},
45 	{"stop-delay",		1, 0, 'T'},
46 	{"waiter-type",		1, 0, OPT_WAITER_TYPE},
47 	{"sched-model",		1, 0, OPT_SCHED_MODEL},
48 	// For plugins in alsa-lib.
49 	{"disable-resample",	0, 0, OPT_DISABLE_RESAMPLE},
50 	{"disable-channels",	0, 0, OPT_DISABLE_CHANNELS},
51 	{"disable-format",	0, 0, OPT_DISABLE_FORMAT},
52 	{"disable-softvol",	0, 0, OPT_DISABLE_SOFTVOL},
53 	// For debugging.
54 	{"fatal-errors",	0, 0, OPT_FATAL_ERRORS},
55 	{"test-nowait",		0, 0, OPT_TEST_NOWAIT},
56 	// Obsoleted.
57 	{"chmap",		1, 0, 'm'},
58 	{"test-position",	0, 0, OPT_TEST_POSITION},
59 	{"test-coef",		1, 0, OPT_TEST_COEF},
60 };
61 
xfer_libasound_init(struct xfer_context * xfer,snd_pcm_stream_t direction)62 static int xfer_libasound_init(struct xfer_context *xfer,
63 			       snd_pcm_stream_t direction)
64 {
65 	struct libasound_state *state = xfer->private_data;
66 	int err;
67 
68 	err = snd_output_stdio_attach(&state->log, stderr, 0);
69 	if (err < 0)
70 		return err;
71 
72 	err = snd_pcm_hw_params_malloc(&state->hw_params);
73 	if (err < 0)
74 		return err;
75 
76 	return snd_pcm_sw_params_malloc(&state->sw_params);
77 }
78 
xfer_libasound_parse_opt(struct xfer_context * xfer,int key,const char * optarg)79 static int xfer_libasound_parse_opt(struct xfer_context *xfer, int key,
80 				    const char *optarg)
81 {
82 	struct libasound_state *state = xfer->private_data;
83 	int err = 0;
84 
85 	if (key == 'D')
86 		state->node_literal = arg_duplicate_string(optarg, &err);
87 	else if (key == 'N')
88 		state->nonblock = true;
89 	else if (key == 'M')
90 		state->mmap = true;
91 	else if (key == 'F')
92 		state->msec_per_period = arg_parse_decimal_num(optarg, &err);
93 	else if (key == 'B')
94 		state->msec_per_buffer = arg_parse_decimal_num(optarg, &err);
95 	else if (key == OPT_PERIOD_SIZE)
96 		state->frames_per_period = arg_parse_decimal_num(optarg, &err);
97 	else if (key == OPT_BUFFER_SIZE)
98 		state->frames_per_buffer = arg_parse_decimal_num(optarg, &err);
99 	else if (key == 'A')
100 		state->msec_for_avail_min = arg_parse_decimal_num(optarg, &err);
101 	else if (key == 'R')
102 		state->msec_for_start_threshold = arg_parse_decimal_num(optarg, &err);
103 	else if (key == 'T')
104 		state->msec_for_stop_threshold = arg_parse_decimal_num(optarg, &err);
105 	else if (key == OPT_WAITER_TYPE)
106 		state->waiter_type_literal = arg_duplicate_string(optarg, &err);
107 	else if (key == OPT_SCHED_MODEL)
108 		state->sched_model_literal = arg_duplicate_string(optarg, &err);
109 	else if (key == OPT_DISABLE_RESAMPLE)
110 		state->no_auto_resample = true;
111 	else if (key == OPT_DISABLE_CHANNELS)
112 		state->no_auto_channels = true;
113 	else if (key == OPT_DISABLE_FORMAT)
114 		state->no_auto_format = true;
115 	else if (key == OPT_DISABLE_SOFTVOL)
116 		state->no_softvol = true;
117 	else if (key == 'm' ||
118 		 key == OPT_TEST_POSITION ||
119 		 key == OPT_TEST_COEF)
120 		err = -EINVAL;
121 	else if (key == OPT_FATAL_ERRORS)
122 		state->finish_at_xrun = true;
123 	else if (key == OPT_TEST_NOWAIT)
124 		state->test_nowait = true;
125 	else
126 		err = -ENXIO;
127 
128 	return err;
129 }
130 
xfer_libasound_validate_opts(struct xfer_context * xfer)131 int xfer_libasound_validate_opts(struct xfer_context *xfer)
132 {
133 	struct libasound_state *state = xfer->private_data;
134 	int err = 0;
135 
136 	state->verbose = xfer->verbose > 1;
137 
138 	if (state->node_literal == NULL) {
139 		state->node_literal = strdup("default");
140 		if (state->node_literal == NULL)
141 			return -ENOMEM;
142 	}
143 
144 	if (state->mmap && state->nonblock) {
145 		fprintf(stderr,
146 			"An option for mmap operation should not be used with "
147 			"nonblocking option.\n");
148 		return -EINVAL;
149 	}
150 
151 	if (state->test_nowait) {
152 		if (!state->nonblock && !state->mmap) {
153 			fprintf(stderr,
154 				"An option for nowait test should be used with "
155 				"nonblock or mmap options.\n");
156 			return -EINVAL;
157 		}
158 	}
159 
160 	if (state->msec_per_period > 0 && state->msec_per_buffer > 0) {
161 		if (state->msec_per_period > state->msec_per_buffer) {
162 			state->msec_per_period = state->msec_per_buffer;
163 			state->msec_per_buffer = 0;
164 		}
165 	}
166 
167 	if (state->frames_per_period > 0 && state->frames_per_buffer > 0) {
168 		if (state->frames_per_period > state->frames_per_buffer) {
169 			state->frames_per_period = state->frames_per_buffer;
170 			state->frames_per_buffer = 0;
171 		}
172 	}
173 
174 	state->sched_model = SCHED_MODEL_IRQ;
175 	if (state->sched_model_literal != NULL) {
176 		if (!strcmp(state->sched_model_literal, "timer")) {
177 			state->sched_model = SCHED_MODEL_TIMER;
178 			state->mmap = true;
179 			state->nonblock = true;
180 		}
181 	}
182 
183 	if (state->waiter_type_literal != NULL) {
184 		if (state->test_nowait) {
185 			fprintf(stderr,
186 				"An option for waiter type should not be "
187 				"used with nowait test option.\n");
188 			return -EINVAL;
189 		}
190 		if (!state->nonblock && !state->mmap) {
191 			fprintf(stderr,
192 				"An option for waiter type should be used "
193 				"with nonblock or mmap or timer-based "
194 				"scheduling options.\n");
195 			return -EINVAL;
196 		}
197 		state->waiter_type =
198 			waiter_type_from_label(state->waiter_type_literal);
199 	} else {
200 		state->waiter_type = WAITER_TYPE_DEFAULT;
201 	}
202 
203 	return err;
204 }
205 
set_access_hw_param(struct libasound_state * state)206 static int set_access_hw_param(struct libasound_state *state)
207 {
208 	snd_pcm_access_mask_t *mask;
209 	int err;
210 
211 	err = snd_pcm_access_mask_malloc(&mask);
212 	if (err < 0)
213 		return err;
214 	snd_pcm_access_mask_none(mask);
215 	if (state->mmap) {
216 		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
217 		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
218 	} else {
219 		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_RW_INTERLEAVED);
220 		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
221 	}
222 	err = snd_pcm_hw_params_set_access_mask(state->handle, state->hw_params,
223 						mask);
224 	snd_pcm_access_mask_free(mask);
225 
226 	return err;
227 }
228 
disable_period_wakeup(struct libasound_state * state)229 static int disable_period_wakeup(struct libasound_state *state)
230 {
231 	int err;
232 
233 	if (snd_pcm_type(state->handle) != SND_PCM_TYPE_HW) {
234 		logging(state,
235 			"Timer-based scheduling is only available for 'hw' "
236 			"PCM plugin.\n");
237 		return -ENXIO;
238 	}
239 
240 	if (!snd_pcm_hw_params_can_disable_period_wakeup(state->hw_params)) {
241 		logging(state,
242 			"This hardware doesn't support the mode of no-period-"
243 			"wakeup. In this case, timer-based scheduling is not "
244 			"available.\n");
245 		return -EIO;
246 	}
247 
248 	err = snd_pcm_hw_params_set_period_wakeup(state->handle,
249 						  state->hw_params, 0);
250 	if (err < 0) {
251 		logging(state,
252 			"Fail to disable period wakeup so that the hardware "
253 			"generates no IRQs during transmission of data "
254 			"frames.\n");
255 	}
256 
257 	return err;
258 }
259 
open_handle(struct xfer_context * xfer)260 static int open_handle(struct xfer_context *xfer)
261 {
262 	struct libasound_state *state = xfer->private_data;
263 	int mode = 0;
264 	int err;
265 
266 	if (state->nonblock)
267 		mode |= SND_PCM_NONBLOCK;
268 	if (state->no_auto_resample)
269 		mode |= SND_PCM_NO_AUTO_RESAMPLE;
270 	if (state->no_auto_channels)
271 		mode |= SND_PCM_NO_AUTO_CHANNELS;
272 	if (state->no_auto_format)
273 		mode |= SND_PCM_NO_AUTO_FORMAT;
274 	if (state->no_softvol)
275 		mode |= SND_PCM_NO_SOFTVOL;
276 
277 	err = snd_pcm_open(&state->handle, state->node_literal, xfer->direction,
278 			   mode);
279 	if (err < 0) {
280 		logging(state, "Fail to open libasound PCM node for %s: %s\n",
281 			snd_pcm_stream_name(xfer->direction),
282 			state->node_literal);
283 		return err;
284 	}
285 
286 	if ((state->nonblock || state->mmap) && !state->test_nowait)
287 		state->use_waiter = true;
288 
289 	err = snd_pcm_hw_params_any(state->handle, state->hw_params);
290 	if (err < 0)
291 		return err;
292 
293 	if (state->sched_model == SCHED_MODEL_TIMER) {
294 		err = disable_period_wakeup(state);
295 		if (err < 0)
296 			return err;
297 	}
298 
299 	if (xfer->dump_hw_params) {
300 		logging(state, "Available HW Params of node: %s\n",
301 			snd_pcm_name(state->handle));
302 		snd_pcm_hw_params_dump(state->hw_params, state->log);
303 		// TODO: there're more parameters which are not dumped by
304 		// alsa-lib.
305 		return 0;
306 	}
307 
308 	return set_access_hw_param(state);
309 }
310 
prepare_waiter(struct libasound_state * state)311 static int prepare_waiter(struct libasound_state *state)
312 {
313 	unsigned int pfd_count;
314 	int err;
315 
316 	// Nothing to do for dafault waiter (=snd_pcm_wait()).
317 	if (state->waiter_type == WAITER_TYPE_DEFAULT)
318 		return 0;
319 
320 	err = snd_pcm_poll_descriptors_count(state->handle);
321 	if (err < 0)
322 		return err;
323 	if (err == 0)
324 		return -ENXIO;
325 	pfd_count = (unsigned int)err;
326 
327 	state->waiter = malloc(sizeof(*state->waiter));
328 	if (state->waiter == NULL)
329 		return -ENOMEM;
330 
331 	err = waiter_context_init(state->waiter, state->waiter_type, pfd_count);
332 	if (err < 0)
333 		return err;
334 
335 	err = snd_pcm_poll_descriptors(state->handle, state->waiter->pfds,
336 				       pfd_count);
337 	if (err < 0)
338 		return err;
339 
340 	return waiter_context_prepare(state->waiter);
341 }
342 
xfer_libasound_wait_event(struct libasound_state * state,int timeout_msec,unsigned short * revents)343 int xfer_libasound_wait_event(struct libasound_state *state, int timeout_msec,
344 			      unsigned short *revents)
345 {
346 	int count;
347 
348 	if (state->waiter_type != WAITER_TYPE_DEFAULT) {
349 		struct waiter_context *waiter = state->waiter;
350 		int err;
351 
352 		count = waiter_context_wait_event(waiter, timeout_msec);
353 		if (count < 0)
354 			return count;
355 		if (count == 0 && timeout_msec > 0)
356 			return -ETIMEDOUT;
357 
358 		err = snd_pcm_poll_descriptors_revents(state->handle,
359 				waiter->pfds, waiter->pfd_count, revents);
360 		if (err < 0)
361 			return err;
362 	} else {
363 		count = snd_pcm_wait(state->handle, timeout_msec);
364 		if (count < 0)
365 			return count;
366 		if (count == 0 && timeout_msec > 0)
367 			return -ETIMEDOUT;
368 
369 		if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_PLAYBACK)
370 			*revents = POLLOUT;
371 		else
372 			*revents = POLLIN;
373 	}
374 
375 	return 0;
376 }
377 
configure_hw_params(struct libasound_state * state,snd_pcm_format_t format,unsigned int samples_per_frame,unsigned int frames_per_second,unsigned int msec_per_period,unsigned int msec_per_buffer,snd_pcm_uframes_t frames_per_period,snd_pcm_uframes_t frames_per_buffer)378 static int configure_hw_params(struct libasound_state *state,
379 			       snd_pcm_format_t format,
380 			       unsigned int samples_per_frame,
381 			       unsigned int frames_per_second,
382 			       unsigned int msec_per_period,
383 			       unsigned int msec_per_buffer,
384 			       snd_pcm_uframes_t frames_per_period,
385 			       snd_pcm_uframes_t frames_per_buffer)
386 {
387 	int err;
388 
389 	// Configure sample format.
390 	if (format == SND_PCM_FORMAT_UNKNOWN) {
391 		snd_pcm_format_mask_t *mask;
392 
393 		err = snd_pcm_format_mask_malloc(&mask);
394 		if (err < 0)
395 			return err;
396 		snd_pcm_hw_params_get_format_mask(state->hw_params, mask);
397 		for (format = 0; format <= SND_PCM_FORMAT_LAST; ++format) {
398 			if (snd_pcm_format_mask_test(mask, format))
399 				break;
400 		}
401 		snd_pcm_format_mask_free(mask);
402 		if (format > SND_PCM_FORMAT_LAST) {
403 			logging(state,
404 				"Any sample format is not available.\n");
405 			return -EINVAL;
406 		}
407 	}
408 	err = snd_pcm_hw_params_set_format(state->handle, state->hw_params,
409 					   format);
410 	if (err < 0) {
411 		logging(state,
412 			"Sample format '%s' is not available: %s\n",
413 			snd_pcm_format_name(format), snd_strerror(err));
414 		return err;
415 	}
416 
417 	// Configure channels.
418 	if (samples_per_frame == 0) {
419 		err = snd_pcm_hw_params_get_channels_min(state->hw_params,
420 							 &samples_per_frame);
421 		if (err < 0) {
422 			logging(state,
423 				"Any channel number is not available.\n");
424 			return err;
425 		}
426 	}
427 	err = snd_pcm_hw_params_set_channels(state->handle, state->hw_params,
428 					     samples_per_frame);
429 	if (err < 0) {
430 		logging(state,
431 			"Channels count '%u' is not available: %s\n",
432 			samples_per_frame, snd_strerror(err));
433 		return err;
434 	}
435 
436 	// Configure rate.
437 	if (frames_per_second == 0) {
438 		err = snd_pcm_hw_params_get_rate_min(state->hw_params,
439 						     &frames_per_second, NULL);
440 		if (err < 0) {
441 			logging(state,
442 				"Any rate is not available.\n");
443 			return err;
444 		}
445 
446 	}
447 	err = snd_pcm_hw_params_set_rate(state->handle, state->hw_params,
448 					 frames_per_second, 0);
449 	if (err < 0) {
450 		logging(state,
451 			"Sampling rate '%u' is not available: %s\n",
452 			frames_per_second, snd_strerror(err));
453 		return err;
454 	}
455 
456 	// Keep one of 'frames_per_buffer' and 'msec_per_buffer'.
457 	if (frames_per_buffer == 0) {
458 		if (msec_per_buffer == 0) {
459 			err = snd_pcm_hw_params_get_buffer_time_max(
460 				state->hw_params, &msec_per_buffer, NULL);
461 			if (err < 0) {
462 				logging(state,
463 					"The maximum msec per buffer is not "
464 					"available.\n");
465 				return err;
466 			}
467 			if (msec_per_buffer > 500000)
468 				msec_per_buffer = 500000;
469 		}
470 	} else if (msec_per_buffer > 0) {
471 		uint64_t msec;
472 
473 		msec = 1000000 * frames_per_buffer / frames_per_second;
474 		if (msec < msec_per_buffer)
475 			msec_per_buffer = 0;
476 	}
477 
478 	// Keep one of 'frames_per_period' and 'msec_per_period'.
479 	if (frames_per_period == 0) {
480 		if (msec_per_period == 0) {
481 			if (msec_per_buffer > 0)
482 				msec_per_period = msec_per_buffer / 4;
483 			else
484 				frames_per_period = frames_per_buffer / 4;
485 		}
486 	} else if (msec_per_period > 0) {
487 		uint64_t msec;
488 
489 		msec = 1000000 * frames_per_period / frames_per_second;
490 		if (msec < msec_per_period)
491 			msec_per_period = 0;
492 	}
493 
494 	if (msec_per_period) {
495 		err = snd_pcm_hw_params_set_period_time_near(state->handle,
496 				state->hw_params, &msec_per_period, NULL);
497 		if (err < 0) {
498 			logging(state,
499 				"Fail to configure period time: %u msec\n",
500 				msec_per_period);
501 			return err;
502 		}
503 	} else {
504 		err = snd_pcm_hw_params_set_period_size_near(state->handle,
505 				state->hw_params, &frames_per_period, NULL);
506 		if (err < 0) {
507 			logging(state,
508 				"Fail to configure period size: %lu frames\n",
509 				frames_per_period);
510 			return err;
511 		}
512 	}
513 
514 	if (msec_per_buffer) {
515 		err = snd_pcm_hw_params_set_buffer_time_near(state->handle,
516 				state->hw_params, &msec_per_buffer, NULL);
517 		if (err < 0) {
518 			logging(state,
519 				"Fail to configure buffer time: %u msec\n",
520 				msec_per_buffer);
521 			return err;
522 		}
523 	} else {
524 		err = snd_pcm_hw_params_set_buffer_size_near(state->handle,
525 					state->hw_params, &frames_per_buffer);
526 		if (err < 0) {
527 			logging(state,
528 				"Fail to configure buffer size: %lu frames\n",
529 				frames_per_buffer);
530 			return err;
531 		}
532 	}
533 
534 	return snd_pcm_hw_params(state->handle, state->hw_params);
535 }
536 
retrieve_actual_hw_params(snd_pcm_hw_params_t * hw_params,snd_pcm_format_t * format,unsigned int * samples_per_frame,unsigned int * frames_per_second,snd_pcm_access_t * access,snd_pcm_uframes_t * frames_per_buffer)537 static int retrieve_actual_hw_params(snd_pcm_hw_params_t *hw_params,
538 				     snd_pcm_format_t *format,
539 				     unsigned int *samples_per_frame,
540 				     unsigned int *frames_per_second,
541 				     snd_pcm_access_t *access,
542 				     snd_pcm_uframes_t *frames_per_buffer)
543 {
544 	int err;
545 
546 	err = snd_pcm_hw_params_get_format(hw_params, format);
547 	if (err < 0)
548 		return err;
549 
550 	err = snd_pcm_hw_params_get_channels(hw_params,
551 					     samples_per_frame);
552 	if (err < 0)
553 		return err;
554 
555 	err = snd_pcm_hw_params_get_rate(hw_params, frames_per_second,
556 					 NULL);
557 	if (err < 0)
558 		return err;
559 
560 	err = snd_pcm_hw_params_get_access(hw_params, access);
561 	if (err < 0)
562 		return err;
563 
564 	return snd_pcm_hw_params_get_buffer_size(hw_params, frames_per_buffer);
565 }
566 
configure_sw_params(struct libasound_state * state,unsigned int frames_per_second,unsigned int frames_per_buffer,unsigned int msec_for_avail_min,unsigned int msec_for_start_threshold,unsigned int msec_for_stop_threshold)567 static int configure_sw_params(struct libasound_state *state,
568 			       unsigned int frames_per_second,
569 			       unsigned int frames_per_buffer,
570 			       unsigned int msec_for_avail_min,
571 			       unsigned int msec_for_start_threshold,
572 			       unsigned int msec_for_stop_threshold)
573 {
574 	snd_pcm_uframes_t frame_count;
575 	int err;
576 
577 	if (msec_for_avail_min > 0) {
578 		frame_count = msec_for_avail_min * frames_per_second / 1000000;
579 		if (frame_count == 0 || frame_count > frames_per_buffer) {
580 			logging(state,
581 				"The msec for 'avail_min' is too %s: %u "
582 				"msec (%lu frames at %u).\n",
583 				frame_count == 0 ? "small" : "large",
584 				msec_for_avail_min, frame_count,
585 				frames_per_second);
586 			return -EINVAL;
587 		}
588 		err = snd_pcm_sw_params_set_avail_min(state->handle,
589 						state->sw_params, frame_count);
590 		if (err < 0) {
591 			logging(state,
592 				"Fail to configure 'avail-min'.\n");
593 			return -EINVAL;
594 		}
595 	}
596 
597 	if (msec_for_start_threshold > 0) {
598 		frame_count = msec_for_start_threshold * frames_per_second /
599 			      1000000;
600 		if (frame_count == 0 || frame_count > frames_per_buffer) {
601 			logging(state,
602 				"The msec for 'start-delay' is too %s: %u "
603 				"msec (%lu frames at %u).\n",
604 				frame_count == 0 ? "small" : "large",
605 				msec_for_start_threshold, frame_count,
606 				frames_per_second);
607 			return -EINVAL;
608 		}
609 		err = snd_pcm_sw_params_set_start_threshold(state->handle,
610 						state->sw_params, frame_count);
611 		if (err < 0) {
612 			logging(state,
613 				"Fail to configure 'start-delay'.\n");
614 			return -EINVAL;
615 		}
616 	}
617 
618 	if (msec_for_stop_threshold > 0) {
619 		frame_count = msec_for_stop_threshold * frames_per_second /
620 			      1000000;
621 		if (frame_count == 0 || frame_count > frames_per_buffer) {
622 			logging(state,
623 				"The msec for 'stop-delay' is too %s: %u "
624 				"msec (%lu frames at %u).\n",
625 				frame_count == 0 ? "small" : "large",
626 				msec_for_stop_threshold, frame_count,
627 				frames_per_second);
628 			return -EINVAL;
629 		}
630 		err = snd_pcm_sw_params_set_stop_threshold(state->handle,
631 						state->sw_params, frame_count);
632 		if (err < 0) {
633 			logging(state,
634 				"Fail to configure 'stop-delay'.\n");
635 			return -EINVAL;
636 		}
637 	}
638 
639 	return snd_pcm_sw_params(state->handle, state->sw_params);
640 }
641 
xfer_libasound_pre_process(struct xfer_context * xfer,snd_pcm_format_t * format,unsigned int * samples_per_frame,unsigned int * frames_per_second,snd_pcm_access_t * access,snd_pcm_uframes_t * frames_per_buffer)642 static int xfer_libasound_pre_process(struct xfer_context *xfer,
643 				      snd_pcm_format_t *format,
644 				      unsigned int *samples_per_frame,
645 				      unsigned int *frames_per_second,
646 				      snd_pcm_access_t *access,
647 				      snd_pcm_uframes_t *frames_per_buffer)
648 {
649 	struct libasound_state *state = xfer->private_data;
650 	unsigned int flag;
651 	int err;
652 
653 	err = open_handle(xfer);
654 	if (err < 0)
655 		return -ENXIO;
656 
657 	err = configure_hw_params(state, *format, *samples_per_frame,
658 				  *frames_per_second,
659 				  state->msec_per_period,
660 				  state->msec_per_buffer,
661 				  state->frames_per_period,
662 				  state->frames_per_buffer);
663 	if (err < 0) {
664 		logging(state, "Current hardware parameters:\n");
665 		snd_pcm_hw_params_dump(state->hw_params, state->log);
666 		return err;
667 	}
668 
669 	// Retrieve actual parameters.
670 	err = retrieve_actual_hw_params(state->hw_params, format,
671 					samples_per_frame, frames_per_second,
672 					access, frames_per_buffer);
673 	if (err < 0)
674 		return err;
675 
676 	// Query software parameters.
677 	err = snd_pcm_sw_params_current(state->handle, state->sw_params);
678 	if (err < 0)
679 		return err;
680 
681 	// Assign I/O operation.
682 	err = snd_pcm_hw_params_get_period_wakeup(state->handle,
683 						  state->hw_params, &flag);
684 	if (err < 0)
685 		return err;
686 
687 	if (flag) {
688 		if (*access == SND_PCM_ACCESS_RW_INTERLEAVED ||
689 		    *access == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
690 			state->ops = &xfer_libasound_irq_rw_ops;
691 		} else if (*access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
692 			   *access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) {
693 			if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE)
694 				state->ops = &xfer_libasound_irq_mmap_r_ops;
695 			else
696 				state->ops = &xfer_libasound_irq_mmap_w_ops;
697 		} else {
698 			return -ENXIO;
699 		}
700 	} else {
701 		if (*access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
702 		    *access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) {
703 			if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE)
704 				state->ops = &xfer_libasound_timer_mmap_r_ops;
705 			else
706 				state->ops = &xfer_libasound_timer_mmap_w_ops;
707 		} else {
708 			return -ENXIO;
709 		}
710 	}
711 
712 	if (state->ops->private_size > 0) {
713 		state->private_data = malloc(state->ops->private_size);
714 		if (state->private_data == NULL)
715 			return -ENOMEM;
716 		memset(state->private_data, 0, state->ops->private_size);
717 	}
718 
719 	err = state->ops->pre_process(state);
720 	if (err < 0)
721 		return err;
722 
723 	err = configure_sw_params(state, *frames_per_second,
724 				  *frames_per_buffer,
725 				  state->msec_for_avail_min,
726 				  state->msec_for_start_threshold,
727 				  state->msec_for_stop_threshold);
728 	if (err < 0) {
729 		logging(state, "Current software parameters:\n");
730 		snd_pcm_sw_params_dump(state->sw_params, state->log);
731 		return err;
732 	}
733 
734 	if (xfer->verbose > 0) {
735 		snd_pcm_dump(state->handle, state->log);
736 		logging(state, "Scheduling model:\n");
737 		logging(state, "  %s\n", sched_model_labels[state->sched_model]);
738 	}
739 
740 	if (state->use_waiter) {
741 		// NOTE: This should be after configuring sw_params due to
742 		// timer descriptor for time-based scheduling model.
743 		err = prepare_waiter(state);
744 		if (err < 0)
745 			return err;
746 
747 		if (xfer->verbose > 0) {
748 			logging(state, "Waiter type:\n");
749 			logging(state,
750 				"  %s\n",
751 				waiter_label_from_type(state->waiter_type));
752 		}
753 	}
754 
755 	return 0;
756 }
757 
xfer_libasound_process_frames(struct xfer_context * xfer,unsigned int * frame_count,struct mapper_context * mapper,struct container_context * cntrs)758 static int xfer_libasound_process_frames(struct xfer_context *xfer,
759 					 unsigned int *frame_count,
760 					 struct mapper_context *mapper,
761 					 struct container_context *cntrs)
762 {
763 	struct libasound_state *state = xfer->private_data;
764 	int err;
765 
766 	if (state->handle == NULL)
767 		return -ENXIO;
768 
769 	err = state->ops->process_frames(state, frame_count, mapper, cntrs);
770 	if (err < 0) {
771 		if (err == -EAGAIN)
772 			return err;
773 		if (err == -EPIPE && !state->finish_at_xrun) {
774 			// Recover the stream and continue processing
775 			// immediately. In this program -EPIPE comes from
776 			// libasound implementation instead of file I/O.
777 			err = snd_pcm_prepare(state->handle);
778 		}
779 
780 		if (err < 0) {
781 			// TODO: -EIO from libasound for hw PCM node means
782 			// that IRQ disorder. This should be reported to help
783 			// developers for drivers.
784 			logging(state, "Fail to process frames: %s\n",
785 				snd_strerror(err));
786 		}
787 	}
788 
789 	return err;
790 }
791 
xfer_libasound_pause(struct xfer_context * xfer,bool enable)792 static void xfer_libasound_pause(struct xfer_context *xfer, bool enable)
793 {
794 	struct libasound_state *state = xfer->private_data;
795 	snd_pcm_state_t s = snd_pcm_state(state->handle);
796 	int err;
797 
798 	if (state->handle == NULL)
799 		return;
800 
801 	if (enable) {
802 		if (s != SND_PCM_STATE_RUNNING)
803 			return;
804 	} else {
805 		if (s != SND_PCM_STATE_PAUSED)
806 			return;
807 	}
808 
809 	// Not supported. Leave the substream to enter XRUN state.
810 	if (!snd_pcm_hw_params_can_pause(state->hw_params))
811 		return;
812 
813 	err = snd_pcm_pause(state->handle, enable);
814 	if (err < 0 && state->verbose) {
815 		logging(state, "snd_pcm_pause(): %s\n", snd_strerror(err));
816 	}
817 }
818 
xfer_libasound_post_process(struct xfer_context * xfer)819 static void xfer_libasound_post_process(struct xfer_context *xfer)
820 {
821 	struct libasound_state *state = xfer->private_data;
822 	snd_pcm_state_t pcm_state;
823 	int err;
824 
825 	if (state->handle == NULL)
826 		return;
827 
828 	pcm_state = snd_pcm_state(state->handle);
829 	if (pcm_state != SND_PCM_STATE_OPEN &&
830 	    pcm_state != SND_PCM_STATE_DISCONNECTED) {
831 		if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE ||
832 		    state->ops == &xfer_libasound_timer_mmap_w_ops) {
833 			err = snd_pcm_drop(state->handle);
834 			if (err < 0)
835 				logging(state, "snd_pcm_drop(): %s\n",
836 				       snd_strerror(err));
837 		} else {
838 			// TODO: this is a bug in kernel land.
839 			if (state->nonblock)
840 				snd_pcm_nonblock(state->handle, 0);
841 			err = snd_pcm_drain(state->handle);
842 			if (state->nonblock)
843 				snd_pcm_nonblock(state->handle, 1);
844 			if (err < 0)
845 				logging(state, "snd_pcm_drain(): %s\n",
846 				       snd_strerror(err));
847 		}
848 	}
849 
850 	err = snd_pcm_hw_free(state->handle);
851 	if (err < 0)
852 		logging(state, "snd_pcm_hw_free(): %s\n", snd_strerror(err));
853 
854 	snd_pcm_close(state->handle);
855 	state->handle = NULL;
856 
857 	if (state->ops && state->ops->post_process)
858 		state->ops->post_process(state);
859 	free(state->private_data);
860 	state->private_data = NULL;
861 
862 	// Free cache of content for configuration files so that memory leaks
863 	// are not detected.
864 	snd_config_update_free_global();
865 }
866 
xfer_libasound_destroy(struct xfer_context * xfer)867 static void xfer_libasound_destroy(struct xfer_context *xfer)
868 {
869 	struct libasound_state *state = xfer->private_data;
870 
871 	free(state->node_literal);
872 	free(state->waiter_type_literal);
873 	free(state->sched_model_literal);
874 	state->node_literal = NULL;
875 	state->waiter_type_literal = NULL;
876 	state->sched_model_literal = NULL;
877 
878 	if (state->hw_params)
879 		snd_pcm_hw_params_free(state->hw_params);
880 	if (state->sw_params)
881 		snd_pcm_sw_params_free(state->sw_params);
882 	state->hw_params = NULL;
883 	state->sw_params = NULL;
884 
885 	if (state->log)
886 		snd_output_close(state->log);
887 	state->log = NULL;
888 }
889 
xfer_libasound_help(struct xfer_context * xfer)890 static void xfer_libasound_help(struct xfer_context *xfer)
891 {
892 	printf(
893 "      [BASICS]\n"
894 "        -D, --device          select node by name in coniguration space\n"
895 "        -N, --nonblock        nonblocking mode\n"
896 "        -M, --mmap            use mmap(2) for zero copying technique\n"
897 "        -F, --period-time     interval between interrupts (msec unit)\n"
898 "        --period-size         interval between interrupts (frame unit)\n"
899 "        -B, --buffer-time     size of buffer for frame(msec unit)\n"
900 "        --buffer-size         size of buffer for frame(frame unit)\n"
901 "        --waiter-type         type of waiter to handle available frames\n"
902 "        --sched-model         model of process scheduling\n"
903 "      [SOFTWARE FEATURES]\n"
904 "        -A, --avail-min       threshold of frames to wake up process\n"
905 "        -R, --start-delay     threshold of frames to start PCM substream\n"
906 "        -T, --stop-delay      threshold of frames to stop PCM substream\n"
907 "      [LIBASOUND PLUGIN OPTIONS]\n"
908 "        --disable-resample    disable rate conversion for plug plugin\n"
909 "        --disable-channels    disable channel conversion for plug plugin\n"
910 "        --disable-format      disable format conversion for plug plugin\n"
911 "        --disable-softvol     disable software volume for sofvol plugin\n"
912 "      [DEBUG ASSISTANT]\n"
913 "        --fatal-errors        finish at XRUN\n"
914 "        --test-nowait         busy poll without any waiter\n"
915 	);
916 }
917 
918 const struct xfer_data xfer_libasound = {
919 	.s_opts = S_OPTS,
920 	.l_opts = l_opts,
921 	.l_opts_count = ARRAY_SIZE(l_opts),
922 	.ops = {
923 		.init		= xfer_libasound_init,
924 		.parse_opt	= xfer_libasound_parse_opt,
925 		.validate_opts	= xfer_libasound_validate_opts,
926 		.pre_process	= xfer_libasound_pre_process,
927 		.process_frames	= xfer_libasound_process_frames,
928 		.pause		= xfer_libasound_pause,
929 		.post_process	= xfer_libasound_post_process,
930 		.destroy	= xfer_libasound_destroy,
931 		.help		= xfer_libasound_help,
932 	},
933 	.private_size = sizeof(struct libasound_state),
934 };
935