• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  ALSA streaming support
3  *
4  *  Originally written by:
5  *      Copyright (c) by Devin Heitmueller <dheitmueller@kernellabs.com>
6  *	for usage at tvtime
7  *  Derived from the alsa-driver test tool latency.c:
8  *    Copyright (c) by Jaroslav Kysela <perex@perex.cz>
9  *
10  *  Copyright (c) 2011 - Mauro Carvalho Chehab
11  *	Ported to xawtv, with bug fixes and improvements
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with this program; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26  *
27  */
28 
29 #ifdef HAVE_ALSA
30 #include "alsa_stream.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sched.h>
36 #include <errno.h>
37 #include <getopt.h>
38 #include <pthread.h>
39 #include <alsa/asoundlib.h>
40 #include <sys/time.h>
41 #include <math.h>
42 
43 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
44 
45 /* Private vars to control alsa thread status */
46 static int stop_alsa = 0;
47 static snd_htimestamp_t timestamp;
48 
49 /* Error handlers */
50 snd_output_t *output = NULL;
51 FILE *error_fp;
52 int verbose = 0;
53 
54 struct final_params {
55     int bufsize;
56     int rate;
57     int latency;
58     int channels;
59 };
60 
setparams_stream(snd_pcm_t * handle,snd_pcm_hw_params_t * params,snd_pcm_format_t format,int * channels,const char * id)61 static int setparams_stream(snd_pcm_t *handle,
62 			    snd_pcm_hw_params_t *params,
63 			    snd_pcm_format_t format,
64 			    int *channels,
65 			    const char *id)
66 {
67     int err;
68 
69     err = snd_pcm_hw_params_any(handle, params);
70     if (err < 0) {
71 	fprintf(error_fp,
72 		"alsa: Broken configuration for %s PCM: no configurations available: %s\n",
73 		snd_strerror(err), id);
74 	return err;
75     }
76 
77     err = snd_pcm_hw_params_set_access(handle, params,
78 				       SND_PCM_ACCESS_RW_INTERLEAVED);
79     if (err < 0) {
80 	fprintf(error_fp, "alsa: Access type not available for %s: %s\n", id,
81 		snd_strerror(err));
82 	return err;
83     }
84 
85     err = snd_pcm_hw_params_set_format(handle, params, format);
86     if (err < 0) {
87 	fprintf(error_fp, "alsa: Sample format not available for %s: %s\n", id,
88 	       snd_strerror(err));
89 	return err;
90     }
91 
92 retry:
93     err = snd_pcm_hw_params_set_channels(handle, params, *channels);
94     if (err < 0) {
95 	if (strcmp(id, "capture") == 0 && *channels == 2) {
96 	    *channels = 1;
97 	    goto retry; /* Retry with mono capture */
98 	}
99 	fprintf(error_fp, "alsa: Channels count (%i) not available for %s: %s\n",
100 		*channels, id, snd_strerror(err));
101 	return err;
102     }
103 
104     return 0;
105 }
106 
getparams_periods(snd_pcm_t * handle,snd_pcm_hw_params_t * params,unsigned int * usecs,unsigned int * count,const char * id)107 static void getparams_periods(snd_pcm_t *handle,
108 		      snd_pcm_hw_params_t *params,
109 		      unsigned int *usecs,
110 		      unsigned int *count,
111 		      const char *id)
112 {
113     unsigned min = 0, max = 0;
114 
115     snd_pcm_hw_params_get_periods_min(params, &min, 0);
116     snd_pcm_hw_params_get_periods_max(params, &max, 0);
117     if (min && max) {
118 	if (verbose)
119 	    fprintf(error_fp, "alsa: %s periods range between %u and %u. Want: %u\n",
120 		    id, min, max, *count);
121 	if (*count < min)
122 	    *count = min;
123 	if (*count > max)
124 	    *count = max;
125     }
126 
127     min = max = 0;
128     snd_pcm_hw_params_get_period_time_min(params, &min, 0);
129     snd_pcm_hw_params_get_period_time_max(params, &max, 0);
130     if (min && max) {
131 	if (verbose)
132 	    fprintf(error_fp, "alsa: %s period time range between %u and %u. Want: %u\n",
133 		    id, min, max, *usecs);
134 	if (*usecs < min)
135 	    *usecs = min;
136 	if (*usecs > max)
137 	    *usecs = max;
138     }
139 }
140 
setparams_periods(snd_pcm_t * handle,snd_pcm_hw_params_t * params,unsigned int * usecs,unsigned int * count,const char * id)141 static int setparams_periods(snd_pcm_t *handle,
142 		      snd_pcm_hw_params_t *params,
143 		      unsigned int *usecs,
144 		      unsigned int *count,
145 		      const char *id)
146 {
147     int err;
148 
149     err = snd_pcm_hw_params_set_period_time_near(handle, params, usecs, 0);
150     if (err < 0) {
151 	    fprintf(error_fp, "alsa: Unable to set period time %u for %s: %s\n",
152 		    *usecs, id, snd_strerror(err));
153 	    return err;
154     }
155 
156     err = snd_pcm_hw_params_set_periods_near(handle, params, count, 0);
157     if (err < 0) {
158 	fprintf(error_fp, "alsa: Unable to set %u periods for %s: %s\n",
159 		*count, id, snd_strerror(err));
160 	return err;
161     }
162 
163     if (verbose)
164 	fprintf(error_fp, "alsa: %s period set to %u periods of %u time\n",
165 		id, *count, *usecs);
166 
167     return 0;
168 }
169 
setparams_set(snd_pcm_t * handle,snd_pcm_hw_params_t * params,snd_pcm_sw_params_t * swparams,snd_pcm_uframes_t start_treshold,const char * id)170 static int setparams_set(snd_pcm_t *handle,
171 			 snd_pcm_hw_params_t *params,
172 			 snd_pcm_sw_params_t *swparams,
173 			 snd_pcm_uframes_t start_treshold,
174 			 const char *id)
175 {
176     int err;
177 
178     err = snd_pcm_hw_params(handle, params);
179     if (err < 0) {
180 	fprintf(error_fp, "alsa: Unable to set hw params for %s: %s\n",
181 		id, snd_strerror(err));
182 	return err;
183     }
184     err = snd_pcm_sw_params_current(handle, swparams);
185     if (err < 0) {
186 	fprintf(error_fp, "alsa: Unable to determine current swparams for %s: %s\n",
187 		id, snd_strerror(err));
188 	return err;
189     }
190     err = snd_pcm_sw_params_set_start_threshold(handle, swparams,
191 						start_treshold);
192     if (err < 0) {
193 	fprintf(error_fp, "alsa: Unable to set start threshold mode for %s: %s\n",
194 		id, snd_strerror(err));
195 	return err;
196     }
197 
198     err = snd_pcm_sw_params_set_avail_min(handle, swparams, 4);
199     if (err < 0) {
200 	fprintf(error_fp, "alsa: Unable to set avail min for %s: %s\n",
201 		id, snd_strerror(err));
202 	return err;
203     }
204 
205     err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams, SND_PCM_TSTAMP_ENABLE);
206     if (err < 0) {
207 	fprintf(error_fp, "alsa: Unable to enable timestamps for %s: %s\n",
208 		id, snd_strerror(err));
209     }
210 
211     err = snd_pcm_sw_params(handle, swparams);
212     if (err < 0) {
213 	fprintf(error_fp, "alsa: Unable to set sw params for %s: %s\n",
214 		id, snd_strerror(err));
215 	return err;
216     }
217     return 0;
218 }
219 
alsa_try_rate(snd_pcm_t * phandle,snd_pcm_t * chandle,snd_pcm_hw_params_t * p_hwparams,snd_pcm_hw_params_t * c_hwparams,int allow_resample,unsigned * ratep,unsigned * ratec)220 static int alsa_try_rate(snd_pcm_t *phandle, snd_pcm_t *chandle,
221                         snd_pcm_hw_params_t *p_hwparams,
222                         snd_pcm_hw_params_t *c_hwparams,
223                         int allow_resample, unsigned *ratep, unsigned *ratec)
224 {
225     int err;
226 
227     err = snd_pcm_hw_params_set_rate_near(chandle, c_hwparams, ratec, 0);
228     if (err)
229         return err;
230 
231     *ratep = *ratec;
232     err = snd_pcm_hw_params_set_rate_near(phandle, p_hwparams, ratep, 0);
233     if (err)
234         return err;
235 
236     if (*ratep == *ratec)
237         return 0;
238 
239     if (verbose)
240         fprintf(error_fp,
241                 "alsa_try_rate: capture wanted %u, playback wanted %u%s\n",
242                 *ratec, *ratep, allow_resample ? " with resample enabled": "");
243 
244     return 1; /* No error, but also no match */
245 }
246 
setparams(snd_pcm_t * phandle,snd_pcm_t * chandle,snd_pcm_format_t format,int latency,int allow_resample,struct final_params * negotiated)247 static int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle,
248 		     snd_pcm_format_t format,
249 		     int latency, int allow_resample,
250 		     struct final_params *negotiated)
251 {
252     int i;
253     unsigned ratep, ratec = 0;
254     unsigned ratemin = 32000, ratemax = 96000, val;
255     int err, channels = 2;
256     snd_pcm_hw_params_t *p_hwparams, *c_hwparams;
257     snd_pcm_sw_params_t *p_swparams, *c_swparams;
258     snd_pcm_uframes_t c_size, p_psize, c_psize;
259     /* Our latency is 2 periods (in usecs) */
260     unsigned int c_periods = 2, p_periods;
261     unsigned int c_periodtime, p_periodtime;
262     const unsigned int prefered_rates[] = { 44100, 48000, 32000 };
263 
264     snd_pcm_hw_params_alloca(&p_hwparams);
265     snd_pcm_hw_params_alloca(&c_hwparams);
266     snd_pcm_sw_params_alloca(&p_swparams);
267     snd_pcm_sw_params_alloca(&c_swparams);
268 
269     if (setparams_stream(chandle, c_hwparams, format, &channels, "capture"))
270 	return 1;
271 
272     if (setparams_stream(phandle, p_hwparams, format, &channels, "playback"))
273 	return 1;
274 
275     if (allow_resample) {
276 	err = snd_pcm_hw_params_set_rate_resample(chandle, c_hwparams, 1);
277 	if (err < 0) {
278 	    fprintf(error_fp, "alsa: Resample setup failed: %s\n", snd_strerror(err));
279 	    return 1;
280 	} else if (verbose)
281 	   fprintf(error_fp, "alsa: Resample enabled.\n");
282     }
283 
284     err = snd_pcm_hw_params_get_rate_min(c_hwparams, &ratemin, 0);
285     if (err >= 0 && verbose)
286 	fprintf(error_fp, "alsa: Capture min rate is %d\n", ratemin);
287     err = snd_pcm_hw_params_get_rate_max(c_hwparams, &ratemax, 0);
288     if (err >= 0 && verbose)
289 	fprintf(error_fp, "alsa: Capture max rate is %u\n", ratemax);
290 
291     err = snd_pcm_hw_params_get_rate_min(p_hwparams, &val, 0);
292     if (err >= 0) {
293 	if (verbose)
294 	    fprintf(error_fp, "alsa: Playback min rate is %u\n", val);
295 	if (val > ratemin)
296 		ratemin = val;
297     }
298     err = snd_pcm_hw_params_get_rate_max(p_hwparams, &val, 0);
299     if (err >= 0) {
300 	if (verbose)
301 	    fprintf(error_fp, "alsa: Playback max rate is %u\n", val);
302 	if (val < ratemax)
303 		ratemax = val;
304     }
305 
306     if (verbose)
307 	fprintf(error_fp,
308 	        "alsa: Will search a common rate between %u and %u\n",
309 		ratemin, ratemax);
310 
311     /* First try a set of common rates */
312     err = -1;
313     for (i = 0; i < ARRAY_SIZE(prefered_rates); i++) {
314         if (prefered_rates[i] < ratemin || prefered_rates[i] > ratemax)
315             continue;
316         ratep = ratec = prefered_rates[i];
317         err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
318                             allow_resample, &ratep, &ratec);
319         if (err == 0)
320             break;
321     }
322 
323     if (err != 0) {
324         if (ratemin >= 44100) {
325             for (i = ratemin; i <= ratemax; i += 100) {
326                 ratep = ratec = i;
327                 err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
328                                     allow_resample, &ratep, &ratec);
329                 if (err == 0)
330                     break;
331             }
332         } else {
333             for (i = ratemax; i >= ratemin; i -= 100) {
334                 ratep = ratec = i;
335                 err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
336                                     allow_resample, &ratep, &ratec);
337                 if (err == 0)
338                     break;
339             }
340         }
341     }
342 
343     if (err < 0) {
344 	fprintf(error_fp, "alsa: Failed to set a supported rate: %s\n",
345 		snd_strerror(err));
346 	return 1;
347     }
348     if (ratep != ratec) {
349 	if (verbose || allow_resample)
350 	    fprintf(error_fp,
351 		    "alsa: Couldn't find a rate that it is supported by both playback and capture\n");
352 	return 2;
353     }
354     if (verbose)
355 	fprintf(error_fp, "alsa: Using Rate %d\n", ratec);
356 
357     /* Negotiate period parameters */
358 
359     c_periodtime = latency * 1000 / c_periods;
360     getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture");
361     p_periods = c_periods * 2;
362     p_periodtime = c_periodtime;
363     getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback");
364     c_periods = p_periods / 2;
365 
366     /*
367      * Some playback devices support a very limited periodtime range. If the user needs to
368      * use a higher latency to avoid overrun/underrun, use an alternate algorithm of incresing
369      * the number of periods, to archive the needed latency
370      */
371     if (p_periodtime < c_periodtime) {
372 	c_periodtime = p_periodtime;
373 	c_periods = round (latency * 1000.0 / c_periodtime + 0.5);
374 	getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture");
375 	p_periods = c_periods * 2;
376 	p_periodtime = c_periodtime;
377 	getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback");
378 	c_periods = p_periods / 2;
379     }
380 
381     if (setparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, "capture"))
382 	return 1;
383 
384     /* Note we use twice as much periods for the playback buffer, since we
385        will get a period size near the requested time and we don't want it to
386        end up smaller than the capture buffer as then we could end up blocking
387        on writing to it. Note we will configure the playback dev to start
388        playing as soon as it has 2 capture periods worth of data, so this
389        won't influence latency */
390     if (setparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, "playback"))
391 	return 1;
392 
393     snd_pcm_hw_params_get_period_size(p_hwparams, &p_psize, NULL);
394     snd_pcm_hw_params_get_period_size(c_hwparams, &c_psize, NULL);
395     snd_pcm_hw_params_get_buffer_size(c_hwparams, &c_size);
396 
397     latency = c_periods * c_psize;
398     if (setparams_set(phandle, p_hwparams, p_swparams, latency, "playback"))
399 	return 1;
400 
401     if (setparams_set(chandle, c_hwparams, c_swparams, c_psize, "capture"))
402 	return 1;
403 
404     if ((err = snd_pcm_prepare(phandle)) < 0) {
405 	fprintf(error_fp, "alsa: Prepare error: %s\n", snd_strerror(err));
406 	return 1;
407     }
408 
409     if (verbose) {
410 	fprintf(error_fp, "alsa: Negotiated configuration:\n");
411 	snd_pcm_dump_setup(phandle, output);
412 	snd_pcm_dump_setup(chandle, output);
413 	fprintf(error_fp, "alsa: Parameters are %iHz, %s, %i channels\n",
414 		ratep, snd_pcm_format_name(format), channels);
415 	fprintf(error_fp, "alsa: Set bitrate to %u%s, buffer size is %u\n", ratec,
416 		allow_resample ? " with resample enabled at playback": "",
417 		(unsigned int)c_size);
418     }
419 
420     negotiated->bufsize = c_size;
421     negotiated->rate = ratep;
422     negotiated->channels = channels;
423     negotiated->latency = latency;
424     return 0;
425 }
426 
427 /* Read up to len frames */
readbuf(snd_pcm_t * handle,char * buf,long len)428 static snd_pcm_sframes_t readbuf(snd_pcm_t *handle, char *buf, long len)
429 {
430     snd_pcm_sframes_t r;
431     snd_pcm_uframes_t frames;
432     snd_pcm_htimestamp(handle, &frames, &timestamp);
433     r = snd_pcm_readi(handle, buf, len);
434     if (r < 0 && !(r == -EAGAIN || r == -ENODEV)) {
435 	r = snd_pcm_recover(handle, r, 0);
436 	if (r < 0)
437 	    fprintf(error_fp, "alsa: overrun recover error: %s\n", snd_strerror(r));
438     }
439     return r;
440 }
441 
442 /* Write len frames (note not up to len, but all of len!) */
writebuf(snd_pcm_t * handle,char * buf,long len)443 static snd_pcm_sframes_t writebuf(snd_pcm_t *handle, char *buf, long len)
444 {
445     snd_pcm_sframes_t r;
446 
447     while (!stop_alsa) {
448 	r = snd_pcm_writei(handle, buf, len);
449 	if (r == len)
450 	    return 0;
451 	if (r < 0) {
452 	    r = snd_pcm_recover(handle, r, 0);
453 	    if (r < 0) {
454 		fprintf(error_fp, "alsa: underrun recover error: %s\n",
455 			snd_strerror(r));
456 		return r;
457 	    }
458 	}
459 	buf += r * 4;
460 	len -= r;
461 	snd_pcm_wait(handle, 100);
462     }
463     return -1;
464 }
465 
alsa_stream(const char * pdevice,const char * cdevice,int latency)466 static int alsa_stream(const char *pdevice, const char *cdevice, int latency)
467 {
468     snd_pcm_t *phandle, *chandle;
469     char *buffer;
470     int err;
471     ssize_t r;
472     struct final_params negotiated;
473     snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
474     char pdevice_new[32];
475 
476     err = snd_output_stdio_attach(&output, error_fp, 0);
477     if (err < 0) {
478 	fprintf(error_fp, "alsa: Output failed: %s\n", snd_strerror(err));
479 	return 0;
480     }
481 
482     /* Open the devices */
483     if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK,
484 			    0)) < 0) {
485 	fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n",
486 		pdevice, snd_strerror(err));
487 	return 0;
488     }
489     if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE,
490 			    SND_PCM_NONBLOCK)) < 0) {
491 	fprintf(error_fp, "alsa: Cannot open capture device %s: %s\n",
492 		cdevice, snd_strerror(err));
493 	snd_pcm_close(phandle);
494 	return 0;
495     }
496 
497     err = setparams(phandle, chandle, format, latency, 0, &negotiated);
498 
499     /* Try to use plughw instead, as it allows emulating speed */
500     if (err == 2 && strncmp(pdevice, "hw", 2) == 0) {
501 
502 	snd_pcm_close(phandle);
503 
504 	sprintf(pdevice_new, "plug%s", pdevice);
505 	pdevice = pdevice_new;
506 	if (verbose)
507 	    fprintf(error_fp, "alsa: Trying %s for playback\n", pdevice);
508 	if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK,
509 				0)) < 0) {
510 	    fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n",
511 		    pdevice, snd_strerror(err));
512 	    snd_pcm_close(chandle);
513 	    return 0;
514 	}
515 
516 	err = setparams(phandle, chandle, format, latency, 1, &negotiated);
517     }
518 
519     if (err != 0) {
520 	fprintf(error_fp, "alsa: setparams failed\n");
521 	snd_pcm_close(phandle);
522 	snd_pcm_close(chandle);
523 	return 1;
524     }
525 
526     buffer = malloc((negotiated.bufsize * snd_pcm_format_width(format) / 8)
527 		    * negotiated.channels);
528     if (buffer == NULL) {
529 	fprintf(error_fp, "alsa: Failed allocating buffer for audio\n");
530 	snd_pcm_close(phandle);
531 	snd_pcm_close(chandle);
532 	return 0;
533     }
534 
535     if (verbose)
536         fprintf(error_fp,
537 	    "alsa: stream started from %s to %s (%i Hz, buffer delay = %.2f ms)\n",
538 	    cdevice, pdevice, negotiated.rate,
539 	    negotiated.latency * 1000.0 / negotiated.rate);
540 
541     while (!stop_alsa) {
542 	/* We start with a read and not a wait to auto(re)start the capture */
543 	r = readbuf(chandle, buffer, negotiated.bufsize);
544 	if (r == 0)   /* Succesfully recovered from an overrun? */
545 	    continue; /* Force restart of capture stream */
546 	if (r > 0)
547 	    writebuf(phandle, buffer, r);
548 	/* use poll to wait for next event */
549 	while (!stop_alsa && !snd_pcm_wait(chandle, 50))
550 	    ;
551     }
552 
553     snd_pcm_drop(chandle);
554     snd_pcm_drop(phandle);
555 
556     snd_pcm_unlink(chandle);
557     snd_pcm_hw_free(phandle);
558     snd_pcm_hw_free(chandle);
559 
560     snd_pcm_close(phandle);
561     snd_pcm_close(chandle);
562 
563     return 0;
564 }
565 
566 struct input_params {
567     char *pdevice;
568     char *cdevice;
569     int latency;
570 };
571 
alsa_thread_entry(void * whatever)572 static void *alsa_thread_entry(void *whatever)
573 {
574     struct input_params *inputs = (struct input_params *) whatever;
575 
576     if (verbose)
577 	fprintf(error_fp, "alsa: starting copying alsa stream from %s to %s\n",
578 		inputs->cdevice, inputs->pdevice);
579     alsa_stream(inputs->pdevice, inputs->cdevice, inputs->latency);
580     if (verbose)
581         fprintf(error_fp, "alsa: stream stopped\n");
582 
583     free(inputs->pdevice);
584     free(inputs->cdevice);
585     free(inputs);
586 
587     return NULL;
588 }
589 
590 /*************************************************************************
591  Public functions
592  *************************************************************************/
593 
594 static int alsa_is_running = 0;
595 static pthread_t alsa_thread;
596 
alsa_thread_startup(const char * pdevice,const char * cdevice,int latency,FILE * __error_fp,int __verbose)597 int alsa_thread_startup(const char *pdevice, const char *cdevice, int latency,
598 			FILE *__error_fp, int __verbose)
599 {
600     int ret;
601     struct input_params *inputs;
602 
603     if ((strcasecmp(pdevice, "disabled") == 0) ||
604 	(strcasecmp(cdevice, "disabled") == 0))
605 	return 0;
606 
607     if (__error_fp)
608 	error_fp = __error_fp;
609     else
610 	error_fp = stderr;
611 
612     verbose = __verbose;
613 
614     if (alsa_is_running) {
615         fprintf(error_fp, "alsa: Already running\n");
616         return EBUSY;
617     }
618 
619     inputs = malloc(sizeof(struct input_params));
620     if (inputs == NULL) {
621 	fprintf(error_fp, "alsa: failed allocating memory for inputs\n");
622 	return ENOMEM;
623     }
624 
625     inputs->pdevice = strdup(pdevice);
626     inputs->cdevice = strdup(cdevice);
627     inputs->latency = latency;
628 
629     stop_alsa = 0;
630     ret = pthread_create(&alsa_thread, NULL,
631 			 &alsa_thread_entry, (void *) inputs);
632     if (ret == 0)
633         alsa_is_running = 1;
634 
635     return ret;
636 }
637 
alsa_thread_stop(void)638 void alsa_thread_stop(void)
639 {
640     if (!alsa_is_running)
641         return;
642 
643     stop_alsa = 1;
644     pthread_join(alsa_thread, NULL);
645     alsa_is_running = 0;
646 }
647 
alsa_thread_is_running(void)648 int alsa_thread_is_running(void)
649 {
650     return alsa_is_running;
651 }
652 
alsa_thread_timestamp(struct timeval * tv)653 void alsa_thread_timestamp(struct timeval *tv)
654 {
655 	if (alsa_thread_is_running()) {
656 		tv->tv_sec = timestamp.tv_sec;
657 		tv->tv_usec = timestamp.tv_nsec / 1000;
658 	} else {
659 		tv->tv_sec = 0;
660 		tv->tv_usec = 0;
661 	}
662 }
663 #endif
664