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