1 /*
2  * Copyright © 2017 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
25  */
26 
27 #include "config.h"
28 
29 #include <limits.h>
30 
31 #include "igt_alsa.h"
32 #include "igt_aux.h"
33 #include "igt_core.h"
34 
35 #define HANDLES_MAX	8
36 
37 /**
38  * SECTION:igt_alsa
39  * @short_description: Library with ALSA helpers
40  * @title: ALSA
41  * @include: igt_alsa.h
42  *
43  * This library contains helpers for ALSA playback and capture.
44  */
45 
46 struct alsa {
47 	snd_pcm_t *output_handles[HANDLES_MAX];
48 	int output_handles_count;
49 	snd_pcm_format_t output_format;
50 	int output_sampling_rate;
51 	int output_channels;
52 
53 	int (*output_callback)(void *data, void *buffer, int samples);
54 	void *output_callback_data;
55 	int output_samples_trigger;
56 };
57 
58 /**
59  * alsa_has_exclusive_access:
60  * Check whether ALSA has exclusive access to audio devices. Fails if
61  * PulseAudio is running.
62  */
alsa_has_exclusive_access(void)63 bool alsa_has_exclusive_access(void)
64 {
65 	if (igt_is_process_running("pulseaudio")) {
66 		igt_warn("alsa doesn't have exclusive access to audio devices\n");
67 		igt_warn("It seems that PulseAudio is running. Audio tests "
68 			 "need direct access to audio devices, so PulseAudio "
69 			 "needs to be stopped. You can do so by running "
70 			 "`pulseaudio --kill`. Also make sure to add "
71 			 "autospawn=no to /etc/pulse/client.conf\n");
72 		return false;
73 	}
74 
75 	return true;
76 }
77 
alsa_error_handler(const char * file,int line,const char * function,int err,const char * fmt,...)78 static void alsa_error_handler(const char *file, int line, const char *function,
79 			       int err, const char *fmt, ...)
80 {
81 	if (err)
82 		igt_debug("[ALSA] %s: %s\n", function, snd_strerror(err));
83 }
84 
85 /**
86  * alsa_init:
87  * Allocate and initialize an alsa structure and configure the error handler.
88  *
89  * Returns: A newly-allocated alsa structure
90  */
alsa_init(void)91 struct alsa *alsa_init(void)
92 {
93 	struct alsa *alsa;
94 
95 	if (!alsa_has_exclusive_access()) {
96 		return NULL;
97 	}
98 
99 	alsa = malloc(sizeof(struct alsa));
100 	memset(alsa, 0, sizeof(struct alsa));
101 
102 	/* Redirect errors to igt_debug instead of stderr. */
103 	snd_lib_error_set_handler(alsa_error_handler);
104 
105 	return alsa;
106 }
107 
alsa_resolve_indentifier(const char * device_name,int skip)108 static char *alsa_resolve_indentifier(const char *device_name, int skip)
109 {
110 	snd_ctl_card_info_t *card_info;
111 	snd_pcm_info_t *pcm_info;
112 	snd_ctl_t *handle = NULL;
113 	const char *pcm_name;
114 	char *identifier = NULL;
115 	char name[32];
116 	int card = -1;
117 	int dev;
118 	int ret;
119 
120 	snd_ctl_card_info_alloca(&card_info);
121 	snd_pcm_info_alloca(&pcm_info);
122 
123 	/* First try to open the device as-is. */
124 	if (!skip) {
125 		ret = snd_ctl_open(&handle, device_name, 0);
126 		if (!ret) {
127 			identifier = strdup(device_name);
128 			goto resolved;
129 		}
130 	}
131 
132 	do {
133 		ret = snd_card_next(&card);
134 		if (ret < 0 || card < 0)
135 			break;
136 
137 		snprintf(name, sizeof(name), "hw:%d", card);
138 
139 		ret = snd_ctl_open(&handle, name, 0);
140 		if (ret < 0)
141 			continue;
142 
143 		ret = snd_ctl_card_info(handle, card_info);
144 		if (ret < 0) {
145 			snd_ctl_close(handle);
146 			handle = NULL;
147 			continue;
148 		}
149 
150 		dev = -1;
151 
152 		do {
153 			ret = snd_ctl_pcm_next_device(handle, &dev);
154 			if (ret < 0 || dev < 0)
155 				break;
156 
157 			snd_pcm_info_set_device(pcm_info, dev);
158 			snd_pcm_info_set_subdevice(pcm_info, 0);
159 
160 			ret = snd_ctl_pcm_info(handle, pcm_info);
161 			if (ret < 0)
162 				continue;
163 
164 			pcm_name = snd_pcm_info_get_name(pcm_info);
165 			if (!pcm_name)
166 				continue;
167 
168 			ret = strncmp(device_name, pcm_name,
169 				      strlen(device_name));
170 
171 			if (ret == 0) {
172 				if (skip > 0) {
173 					skip--;
174 					continue;
175 				}
176 
177 				igt_debug("Matched device \"%s\"\n", pcm_name);
178 
179 				snprintf(name, sizeof(name), "hw:%d,%d", card,
180 					 dev);
181 
182 				identifier = strdup(name);
183 				goto resolved;
184 			}
185 		} while (dev >= 0);
186 
187 		snd_ctl_close(handle);
188 		handle = NULL;
189 	} while (card >= 0);
190 
191 resolved:
192 	if (handle)
193 		snd_ctl_close(handle);
194 
195 	return identifier;
196 }
197 
198 /**
199  * alsa_open_output:
200  * @alsa: The target alsa structure
201  * @device_name: The name prefix of the output device(s) to open
202  *
203  * Open ALSA output devices whose name prefixes match the provided name prefix.
204  *
205  * Returns: An integer equal to zero for success and negative for failure
206  */
alsa_open_output(struct alsa * alsa,const char * device_name)207 int alsa_open_output(struct alsa *alsa, const char *device_name)
208 {
209 	snd_pcm_t *handle;
210 	char *identifier;
211 	int skip;
212 	int index;
213 	int ret;
214 
215 	skip = alsa->output_handles_count;
216 	index = alsa->output_handles_count;
217 
218 	while (index < HANDLES_MAX) {
219 		identifier = alsa_resolve_indentifier(device_name, skip++);
220 		if (!identifier)
221 			break;
222 
223 		ret = snd_pcm_open(&handle, identifier, SND_PCM_STREAM_PLAYBACK,
224 				   SND_PCM_NONBLOCK);
225 		if (ret < 0) {
226 			free(identifier);
227 			continue;
228 		}
229 
230 		igt_debug("Opened output %s\n", identifier);
231 
232 		alsa->output_handles[index++] = handle;
233 		free(identifier);
234 	}
235 
236 	if (index == 0)
237 		return -1;
238 
239 	alsa->output_handles_count = index;
240 
241 	return 0;
242 }
243 
244 /**
245  * alsa_close_output:
246  * @alsa: The target alsa structure
247  *
248  * Close all the open ALSA outputs.
249  */
alsa_close_output(struct alsa * alsa)250 void alsa_close_output(struct alsa *alsa)
251 {
252 	snd_pcm_t *handle;
253 	int i;
254 
255 	for (i = 0; i < alsa->output_handles_count; i++) {
256 		handle = alsa->output_handles[i];
257 		if (!handle)
258 			continue;
259 
260 		snd_pcm_close(handle);
261 		alsa->output_handles[i] = NULL;
262 	}
263 
264 	alsa->output_handles_count = 0;
265 
266 	alsa->output_callback = NULL;
267 }
268 
alsa_test_configuration(snd_pcm_t * handle,snd_pcm_format_t fmt,int channels,int sampling_rate)269 static bool alsa_test_configuration(snd_pcm_t *handle, snd_pcm_format_t fmt,
270 				    int channels, int sampling_rate)
271 {
272 	snd_pcm_hw_params_t *params;
273 	int ret;
274 	unsigned int min_channels, max_channels;
275 	unsigned int min_rate, max_rate;
276 	int min_rate_dir, max_rate_dir;
277 
278 	snd_pcm_hw_params_alloca(&params);
279 
280 	ret = snd_pcm_hw_params_any(handle, params);
281 	if (ret < 0)
282 		return false;
283 
284 	ret = snd_pcm_hw_params_test_format(handle, params, fmt);
285 	if (ret < 0) {
286 		igt_debug("Output device doesn't support the format %s\n",
287 			  snd_pcm_format_name(fmt));
288 		return false;
289 	}
290 
291 	ret = snd_pcm_hw_params_test_rate(handle, params, sampling_rate, 0);
292 	if (ret < 0) {
293 		snd_pcm_hw_params_get_rate_min(params, &min_rate, &min_rate_dir);
294 		snd_pcm_hw_params_get_rate_max(params, &max_rate, &max_rate_dir);
295 		igt_debug("Output device supports rates between %u and %u, "
296 			  "requested %d\n",
297 			  min_rate, max_rate, sampling_rate);
298 		return false;
299 	}
300 
301 	ret = snd_pcm_hw_params_test_channels(handle, params, channels);
302 	if (ret < 0) {
303 		snd_pcm_hw_params_get_channels_min(params, &min_channels);
304 		snd_pcm_hw_params_get_channels_max(params, &max_channels);
305 		igt_debug("Output device supports between %u and "
306 			  "%u channels, requested %d\n",
307 			  min_channels, max_channels, channels);
308 		return false;
309 	}
310 
311 	return true;
312 }
313 
314 /**
315  * alsa_test_output_configuration:
316  * @alsa: The target alsa structure
317  * @fmt: The format to test
318  * @channels: The number of channels to test
319  * @sampling_rate: The sampling rate to test
320  *
321  * Test the output configuration specified by @channels and @sampling_rate
322  * for the output devices.
323  *
324  * Returns: A boolean indicating whether the test succeeded
325  */
alsa_test_output_configuration(struct alsa * alsa,snd_pcm_format_t fmt,int channels,int sampling_rate)326 bool alsa_test_output_configuration(struct alsa *alsa, snd_pcm_format_t fmt,
327 				    int channels, int sampling_rate)
328 {
329 	snd_pcm_t *handle;
330 	bool ret;
331 	int i;
332 
333 	for (i = 0; i < alsa->output_handles_count; i++) {
334 		handle = alsa->output_handles[i];
335 
336 		ret = alsa_test_configuration(handle, fmt, channels, sampling_rate);
337 		if (!ret)
338 			return false;
339 	}
340 
341 	return true;
342 }
343 
344 /**
345  * alsa_configure_output:
346  * @alsa: The target alsa structure
347  * @channels: The number of channels to test
348  * @sampling_rate: The sampling rate to test
349  *
350  * Configure the output devices with the configuration specified by @channels
351  * and @sampling_rate.
352  */
alsa_configure_output(struct alsa * alsa,snd_pcm_format_t fmt,int channels,int sampling_rate)353 void alsa_configure_output(struct alsa *alsa, snd_pcm_format_t fmt,
354 			   int channels, int sampling_rate)
355 {
356 	snd_pcm_t *handle;
357 	int ret;
358 	int i;
359 	int soft_resample = 0; /* Don't allow ALSA to resample */
360 	unsigned int latency = 0;
361 
362 	for (i = 0; i < alsa->output_handles_count; i++) {
363 		handle = alsa->output_handles[i];
364 
365 		ret = snd_pcm_set_params(handle, fmt,
366 					 SND_PCM_ACCESS_RW_INTERLEAVED,
367 					 channels, sampling_rate,
368 					 soft_resample, latency);
369 		igt_assert(ret >= 0);
370 	}
371 
372 	alsa->output_format = fmt;
373 	alsa->output_channels = channels;
374 	alsa->output_sampling_rate = sampling_rate;
375 }
376 
377 /**
378  * alsa_register_output_callback:
379  * @alsa: The target alsa structure
380  * @callback: The callback function to call to fill output data
381  * @callback_data: The data pointer to pass to the callback function
382  * @samples_trigger: The required number of samples to trigger the callback
383  *
384  * Register a callback function to be called to fill output data during a run.
385  * The callback is called when @samples_trigger samples are required.
386  *
387  * The callback should return an integer equal to zero for success and negative
388  * for failure.
389  */
alsa_register_output_callback(struct alsa * alsa,int (* callback)(void * data,void * buffer,int samples),void * callback_data,int samples_trigger)390 void alsa_register_output_callback(struct alsa *alsa,
391 				   int (*callback)(void *data, void *buffer, int samples),
392 				   void *callback_data, int samples_trigger)
393 {
394 	alsa->output_callback = callback;
395 	alsa->output_callback_data = callback_data;
396 	alsa->output_samples_trigger = samples_trigger;
397 }
398 
399 /**
400  * alsa_run:
401  * @alsa: The target alsa structure
402  * @duration_ms: The maximum duration of the run in milliseconds, or -1 for an
403  * infinite duration.
404  *
405  * Run ALSA playback and capture on the input and output devices for at
406  * most @duration_ms milliseconds, calling the registered callbacks when needed.
407  *
408  * Returns: An integer equal to zero for success, positive for a stop caused
409  * by the input callback and negative for failure
410  */
alsa_run(struct alsa * alsa,int duration_ms)411 int alsa_run(struct alsa *alsa, int duration_ms)
412 {
413 	snd_pcm_t *handle;
414 	char *output_buffer = NULL;
415 	int output_limit;
416 	int output_total = 0;
417 	int output_counts[alsa->output_handles_count];
418 	bool output_ready = false;
419 	int output_channels;
420 	int bytes_per_sample;
421 	int output_trigger;
422 	bool reached;
423 	int index;
424 	int count;
425 	int avail;
426 	int i;
427 	int ret;
428 
429 	output_limit = alsa->output_sampling_rate * duration_ms / 1000;
430 	output_channels = alsa->output_channels;
431 	bytes_per_sample = snd_pcm_format_physical_width(alsa->output_format) / 8;
432 	output_trigger = alsa->output_samples_trigger;
433 	output_buffer = malloc(output_channels * output_trigger *
434 			       bytes_per_sample);
435 
436 	do {
437 		reached = true;
438 
439 		if (output_limit < 0 || output_total < output_limit) {
440 			reached = false;
441 
442 			if (!output_ready) {
443 				for (i = 0; i < alsa->output_handles_count; i++)
444 					output_counts[i] = 0;
445 
446 				ret = alsa->output_callback(alsa->output_callback_data,
447 							    output_buffer,
448 							    output_trigger);
449 				if (ret < 0)
450 					goto complete;
451 			}
452 
453 			for (i = 0; i < alsa->output_handles_count; i++) {
454 				handle = alsa->output_handles[i];
455 
456 				ret = snd_pcm_avail(handle);
457 				if (output_counts[i] < output_trigger &&
458 				    ret > 0) {
459 					index = output_counts[i] *
460 						output_channels;
461 					count = output_trigger -
462 						output_counts[i];
463 					avail = snd_pcm_avail(handle);
464 
465 					count = avail < count ? avail : count;
466 
467 					ret = snd_pcm_writei(handle,
468 							     &output_buffer[index * bytes_per_sample],
469 							     count);
470 					if (ret < 0) {
471 						ret = snd_pcm_recover(handle,
472 								      ret, 0);
473 						if (ret < 0) {
474 							igt_debug("snd_pcm_recover after snd_pcm_writei failed");
475 							goto complete;
476 						}
477 					}
478 
479 					output_counts[i] += ret;
480 				} else if (output_counts[i] < output_trigger &&
481 					   ret < 0) {
482 					ret = snd_pcm_recover(handle, ret, 0);
483 					if (ret < 0) {
484 						igt_debug("snd_pcm_recover failed");
485 						goto complete;
486 					}
487 				}
488 			}
489 
490 			output_ready = false;
491 
492 			for (i = 0; i < alsa->output_handles_count; i++)
493 				if (output_counts[i] < output_trigger)
494 					output_ready = true;
495 
496 			if (!output_ready)
497 				output_total += output_trigger;
498 
499 		}
500 	} while (!reached);
501 
502 	ret = 0;
503 
504 complete:
505 	free(output_buffer);
506 
507 	return ret;
508 }
509