1 /*
2 * Copyright (C) 2013-2015 Intel Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 */
15
16 #include "aconfig.h"
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <pthread.h>
23 #include <errno.h>
24
25 #include <alsa/asoundlib.h>
26
27 #include "gettext.h"
28
29 #include "common.h"
30 #include "alsa.h"
31 #include "latencytest.h"
32 #include "os_compat.h"
33
34 struct pcm_container {
35 snd_pcm_t *handle;
36 snd_pcm_uframes_t period_size;
37 snd_pcm_uframes_t buffer_size;
38 snd_pcm_format_t format;
39 unsigned short channels;
40 size_t period_bytes;
41 size_t sample_bits;
42 size_t frame_bits;
43 char *buffer;
44 };
45
46 struct format_map_table {
47 enum _bat_pcm_format format_bat;
48 snd_pcm_format_t format_alsa;
49 };
50
51 static struct format_map_table map_tables[] = {
52 { BAT_PCM_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN },
53 { BAT_PCM_FORMAT_U8, SND_PCM_FORMAT_U8 },
54 { BAT_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_LE },
55 { BAT_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3LE },
56 { BAT_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_LE },
57 { BAT_PCM_FORMAT_MAX, 0 },
58 };
59
format_convert(struct bat *bat, snd_pcm_format_t *fmt)60 static int format_convert(struct bat *bat, snd_pcm_format_t *fmt)
61 {
62 struct format_map_table *t = map_tables;
63
64 for (; t->format_bat != BAT_PCM_FORMAT_MAX; t++) {
65 if (t->format_bat == bat->format) {
66 *fmt = t->format_alsa;
67 return 0;
68 }
69 }
70 fprintf(bat->err, _("Invalid format!\n"));
71 return -EINVAL;
72 }
73
set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)74 static int set_snd_pcm_params(struct bat *bat, struct pcm_container *sndpcm)
75 {
76 snd_pcm_hw_params_t *params;
77 snd_pcm_format_t format;
78 unsigned int buffer_time = 0;
79 unsigned int period_time = 0;
80 snd_pcm_uframes_t buffer_size = 0;
81 snd_pcm_uframes_t period_size = 0;
82 unsigned int rate;
83 int err;
84 const char *device_name = snd_pcm_name(sndpcm->handle);
85
86 /* Convert common format to ALSA format */
87 err = format_convert(bat, &format);
88 if (err != 0)
89 return err;
90
91 /* Allocate a hardware parameters object. */
92 snd_pcm_hw_params_alloca(¶ms);
93
94 /* Fill it in with default values. */
95 err = snd_pcm_hw_params_any(sndpcm->handle, params);
96 if (err < 0) {
97 fprintf(bat->err, _("Set parameter to device error: "));
98 fprintf(bat->err, _("default params: %s: %s(%d)\n"),
99 device_name, snd_strerror(err), err);
100 return err;
101 }
102
103 /* Set access mode */
104 err = snd_pcm_hw_params_set_access(sndpcm->handle, params,
105 SND_PCM_ACCESS_RW_INTERLEAVED);
106 if (err < 0) {
107 fprintf(bat->err, _("Set parameter to device error: "));
108 fprintf(bat->err, _("access type: %s: %s(%d)\n"),
109 device_name, snd_strerror(err), err);
110 return err;
111 }
112
113 /* Set format */
114 err = snd_pcm_hw_params_set_format(sndpcm->handle, params, format);
115 if (err < 0) {
116 fprintf(bat->err, _("Set parameter to device error: "));
117 fprintf(bat->err, _("PCM format: %d %s: %s(%d)\n"), format,
118 device_name, snd_strerror(err), err);
119 return err;
120 }
121
122 /* Set channels */
123 err = snd_pcm_hw_params_set_channels(sndpcm->handle,
124 params, bat->channels);
125 if (err < 0) {
126 fprintf(bat->err, _("Set parameter to device error: "));
127 fprintf(bat->err, _("channel number: %d %s: %s(%d)\n"),
128 bat->channels,
129 device_name, snd_strerror(err), err);
130 return err;
131 }
132
133 /* Set sampling rate */
134 rate = bat->rate;
135 err = snd_pcm_hw_params_set_rate_near(sndpcm->handle,
136 params, &bat->rate,
137 0);
138 if (err < 0) {
139 fprintf(bat->err, _("Set parameter to device error: "));
140 fprintf(bat->err, _("sample rate: %d %s: %s(%d)\n"),
141 bat->rate,
142 device_name, snd_strerror(err), err);
143 return err;
144 }
145 if ((float) rate * (1 + RATE_RANGE) < bat->rate
146 || (float) rate * (1 - RATE_RANGE) > bat->rate) {
147 fprintf(bat->err, _("Invalid parameters: sample rate: "));
148 fprintf(bat->err, _("requested %dHz, got %dHz\n"),
149 rate, bat->rate);
150 return -EINVAL;
151 }
152
153 if (bat->buffer_size > 0 && bat->period_size == 0)
154 bat->period_size = bat->buffer_size / DIV_BUFFERSIZE;
155
156 if (bat->roundtriplatency && bat->buffer_size == 0) {
157 /* Set to minimum buffer size and period size
158 for latency test */
159 if (snd_pcm_hw_params_get_buffer_size_min(params,
160 &buffer_size) < 0) {
161 fprintf(bat->err,
162 _("Get parameter from device error: "));
163 fprintf(bat->err, _("buffer size min: %d %s: %s(%d)\n"),
164 (int) buffer_size,
165 device_name, snd_strerror(err), err);
166 return -EINVAL;
167 }
168
169 if (snd_pcm_hw_params_get_period_size_min(params,
170 &period_size, 0) < 0) {
171 fprintf(bat->err,
172 _("Get parameter from device error: "));
173 fprintf(bat->err, _("period size min: %d %s: %s(%d)\n"),
174 (int) period_size,
175 device_name, snd_strerror(err), err);
176 return -EINVAL;
177 }
178 bat->buffer_size = (int) buffer_size;
179 bat->period_size = (int) period_size;
180 }
181
182 if (bat->buffer_size > 0) {
183 buffer_size = bat->buffer_size;
184 period_size = bat->period_size;
185
186 fprintf(bat->log, _("Set period size: %d buffer size: %d\n"),
187 (int) period_size, (int) buffer_size);
188
189 err = snd_pcm_hw_params_set_buffer_size_near(sndpcm->handle,
190 params, &buffer_size);
191 if (err < 0) {
192 fprintf(bat->err, _("Set parameter to device error: "));
193 fprintf(bat->err, _("buffer size: %d %s: %s(%d)\n"),
194 (int) buffer_size,
195 device_name, snd_strerror(err), err);
196 return err;
197 }
198
199 err = snd_pcm_hw_params_set_period_size_near(sndpcm->handle,
200 params, &period_size, 0);
201 if (err < 0) {
202 fprintf(bat->err, _("Set parameter to device error: "));
203 fprintf(bat->err, _("period size: %d %s: %s(%d)\n"),
204 (int) period_size,
205 device_name, snd_strerror(err), err);
206 return err;
207 }
208 } else {
209 if (snd_pcm_hw_params_get_buffer_time_max(params,
210 &buffer_time, 0) < 0) {
211 fprintf(bat->err,
212 _("Get parameter from device error: "));
213 fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
214 buffer_time,
215 device_name, snd_strerror(err), err);
216 return -EINVAL;
217 }
218
219 if (buffer_time > MAX_BUFFERTIME)
220 buffer_time = MAX_BUFFERTIME;
221
222 period_time = buffer_time / DIV_BUFFERTIME;
223
224 /* Set buffer time and period time */
225 err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle,
226 params, &buffer_time, 0);
227 if (err < 0) {
228 fprintf(bat->err, _("Set parameter to device error: "));
229 fprintf(bat->err, _("buffer time: %d %s: %s(%d)\n"),
230 buffer_time,
231 device_name, snd_strerror(err), err);
232 return err;
233 }
234
235 err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle,
236 params, &period_time, 0);
237 if (err < 0) {
238 fprintf(bat->err, _("Set parameter to device error: "));
239 fprintf(bat->err, _("period time: %d %s: %s(%d)\n"),
240 period_time,
241 device_name, snd_strerror(err), err);
242 return err;
243 }
244 }
245
246 /* Write the parameters to the driver */
247 if (snd_pcm_hw_params(sndpcm->handle, params) < 0) {
248 fprintf(bat->err, _("Set parameter to device error: "));
249 fprintf(bat->err, _("hw params: %s: %s(%d)\n"),
250 device_name, snd_strerror(err), err);
251 return -EINVAL;
252 }
253
254 err = snd_pcm_hw_params_get_period_size(params,
255 &sndpcm->period_size, 0);
256 if (err < 0) {
257 fprintf(bat->err, _("Get parameter from device error: "));
258 fprintf(bat->err, _("period size: %zd %s: %s(%d)\n"),
259 sndpcm->period_size,
260 device_name, snd_strerror(err), err);
261 return err;
262 }
263
264 err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size);
265 if (err < 0) {
266 fprintf(bat->err, _("Get parameter from device error: "));
267 fprintf(bat->err, _("buffer size: %zd %s: %s(%d)\n"),
268 sndpcm->buffer_size,
269 device_name, snd_strerror(err), err);
270 return err;
271 }
272
273 if (sndpcm->period_size == sndpcm->buffer_size) {
274 fprintf(bat->err, _("Invalid parameters: can't use period "));
275 fprintf(bat->err, _("equal to buffer size (%zd)\n"),
276 sndpcm->period_size);
277 return -EINVAL;
278 }
279
280 fprintf(bat->log, _("Get period size: %d buffer size: %d\n"),
281 (int) sndpcm->period_size, (int) sndpcm->buffer_size);
282
283 err = snd_pcm_format_physical_width(format);
284 if (err < 0) {
285 fprintf(bat->err, _("Invalid parameters: "));
286 fprintf(bat->err, _("snd_pcm_format_physical_width: %d\n"),
287 err);
288 return err;
289 }
290 sndpcm->sample_bits = err;
291
292 sndpcm->frame_bits = sndpcm->sample_bits * bat->channels;
293
294 /* Calculate the period bytes */
295 sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8;
296 sndpcm->buffer = (char *) malloc(sndpcm->period_bytes);
297 if (sndpcm->buffer == NULL) {
298 fprintf(bat->err, _("Not enough memory: size=%zd\n"),
299 sndpcm->period_bytes);
300 return -ENOMEM;
301 }
302
303 return 0;
304 }
305
write_to_pcm(const struct pcm_container *sndpcm, int frames, struct bat *bat)306 static int write_to_pcm(const struct pcm_container *sndpcm,
307 int frames, struct bat *bat)
308 {
309 int err;
310 int offset = 0;
311 int remain = frames;
312
313 while (remain > 0) {
314 err = snd_pcm_writei(sndpcm->handle, sndpcm->buffer + offset,
315 remain);
316 if (err == -EAGAIN || (err >= 0 && err < frames)) {
317 snd_pcm_wait(sndpcm->handle, 500);
318 } else if (err == -EPIPE) {
319 fprintf(bat->err, _("Underrun: %s(%d)\n"),
320 snd_strerror(err), err);
321 if (bat->roundtriplatency)
322 bat->latency.xrun_error = true;
323 snd_pcm_prepare(sndpcm->handle);
324 } else if (err == -ESTRPIPE) {
325 while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN)
326 sleep(1); /* wait until resume flag is released */
327 if (err < 0)
328 snd_pcm_prepare(sndpcm->handle);
329 } else if (err < 0) {
330 fprintf(bat->err, _("Write PCM device error: %s(%d)\n"),
331 snd_strerror(err), err);
332 return err;
333 }
334
335 if (err > 0) {
336 remain -= err;
337 offset += err * sndpcm->frame_bits / 8;
338 }
339 }
340
341 return 0;
342 }
343
344 /**
345 * Process output data for latency test
346 */
latencytest_process_output(struct pcm_container *sndpcm, struct bat *bat)347 static int latencytest_process_output(struct pcm_container *sndpcm,
348 struct bat *bat)
349 {
350 int err = 0;
351 int bytes = sndpcm->period_bytes; /* playback buffer size */
352 int frames = sndpcm->period_size; /* frame count */
353
354 bat->latency.is_playing = true;
355
356 while (1) {
357 /* generate output data */
358 err = handleoutput(bat, sndpcm->buffer, bytes, frames);
359 if (err != 0)
360 break;
361
362 err = write_to_pcm(sndpcm, frames, bat);
363 if (err != 0)
364 break;
365
366 /* Xrun error, terminate the playback thread*/
367 if (bat->latency.xrun_error == true)
368 break;
369
370 if (bat->latency.state == LATENCY_STATE_COMPLETE_SUCCESS)
371 break;
372
373 bat->periods_played++;
374 }
375
376 bat->latency.is_playing = false;
377
378 return err;
379 }
380
write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)381 static int write_to_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)
382 {
383 int err = 0;
384 int bytes = sndpcm->period_bytes; /* playback buffer size */
385 int frames = bytes * 8 / sndpcm->frame_bits; /* frame count */
386 FILE *fp = NULL;
387 int bytes_total = 0;
388
389 if (bat->debugplay) {
390 fp = fopen(bat->debugplay, "wb");
391 err = -errno;
392 if (fp == NULL) {
393 fprintf(bat->err, _("Cannot open file: %s %d\n"),
394 bat->debugplay, err);
395 return err;
396 }
397 /* leave space for wav header */
398 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) {
399 err = -errno;
400 fclose(fp);
401 return err;
402 }
403 }
404
405 while (1) {
406 err = generate_input_data(bat, sndpcm->buffer, bytes, frames);
407 if (err != 0)
408 break;
409
410 if (bat->debugplay) {
411 if (fwrite(sndpcm->buffer, 1, bytes, fp) != (size_t)bytes) {
412 err = -EIO;
413 break;
414 }
415 bytes_total += bytes;
416 }
417
418 bat->periods_played++;
419 if (bat->period_is_limited
420 && bat->periods_played >= bat->periods_total)
421 break;
422
423 err = write_to_pcm(sndpcm, frames, bat);
424 if (err != 0)
425 break;
426 }
427
428 if (bat->debugplay) {
429 update_wav_header(bat, fp, bytes_total);
430 fclose(fp);
431 }
432
433 snd_pcm_drain(sndpcm->handle);
434
435 return err;
436 }
437
438 /**
439 * Play
440 */
playback_alsa(struct bat *bat)441 void *playback_alsa(struct bat *bat)
442 {
443 int err = 0;
444 struct pcm_container sndpcm;
445
446 fprintf(bat->log, _("Entering playback thread (ALSA).\n"));
447
448 retval_play = 0;
449 memset(&sndpcm, 0, sizeof(sndpcm));
450
451 err = snd_pcm_open(&sndpcm.handle, bat->playback.device,
452 SND_PCM_STREAM_PLAYBACK, 0);
453 if (err != 0) {
454 fprintf(bat->err, _("Cannot open PCM playback device: "));
455 fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
456 retval_play = err;
457 goto exit1;
458 }
459
460 err = set_snd_pcm_params(bat, &sndpcm);
461 if (err != 0) {
462 retval_play = err;
463 goto exit2;
464 }
465
466 if (bat->playback.file == NULL) {
467 fprintf(bat->log, _("Playing generated audio sine wave"));
468 bat->sinus_duration == 0 ?
469 fprintf(bat->log, _(" endlessly\n")) :
470 fprintf(bat->log, _("\n"));
471 } else {
472 fprintf(bat->log, _("Playing input audio file: %s\n"),
473 bat->playback.file);
474 bat->fp = fopen(bat->playback.file, "rb");
475 err = -errno;
476 if (bat->fp == NULL) {
477 fprintf(bat->err, _("Cannot open file: %s %d\n"),
478 bat->playback.file, err);
479 retval_play = err;
480 goto exit3;
481 }
482 /* Skip header */
483 err = read_wav_header(bat, bat->playback.file, bat->fp, true);
484 if (err != 0) {
485 retval_play = err;
486 goto exit4;
487 }
488 }
489
490 if (bat->roundtriplatency)
491 err = latencytest_process_output(&sndpcm, bat);
492 else
493 err = write_to_pcm_loop(&sndpcm, bat);
494 if (err < 0) {
495 retval_play = err;
496 goto exit4;
497 }
498
499 exit4:
500 if (bat->playback.file)
501 fclose(bat->fp);
502 exit3:
503 free(sndpcm.buffer);
504 exit2:
505 snd_pcm_close(sndpcm.handle);
506 exit1:
507 pthread_exit(&retval_play);
508 }
509
read_from_pcm(struct pcm_container *sndpcm, int frames, struct bat *bat)510 static int read_from_pcm(struct pcm_container *sndpcm,
511 int frames, struct bat *bat)
512 {
513 int err = 0;
514 int offset = 0;
515 int remain = frames;
516
517 while (remain > 0) {
518 err = snd_pcm_readi(sndpcm->handle,
519 sndpcm->buffer + offset, remain);
520 if (err == -EAGAIN || (err >= 0 && err < remain)) {
521 snd_pcm_wait(sndpcm->handle, 500);
522 } else if (err == -EPIPE) {
523 snd_pcm_prepare(sndpcm->handle);
524 fprintf(bat->err, _("Overrun: %s(%d)\n"),
525 snd_strerror(err), err);
526 if (bat->roundtriplatency)
527 bat->latency.xrun_error = true;
528 } else if (err == -ESTRPIPE) {
529 while ((err = snd_pcm_resume(sndpcm->handle)) == -EAGAIN)
530 sleep(1); /* wait until resume flag is released */
531 if (err < 0)
532 snd_pcm_prepare(sndpcm->handle);
533 } else if (err < 0) {
534 fprintf(bat->err, _("Read PCM device error: %s(%d)\n"),
535 snd_strerror(err), err);
536 return err;
537 }
538
539 if (err > 0) {
540 remain -= err;
541 offset += err * sndpcm->frame_bits / 8;
542 }
543 }
544
545 return 0;
546 }
547
read_from_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)548 static int read_from_pcm_loop(struct pcm_container *sndpcm, struct bat *bat)
549 {
550 int err = 0;
551 FILE *fp = NULL;
552 int size, frames;
553 int bytes_read = 0;
554 int bytes_count = bat->frames * bat->frame_size;
555 unsigned int remain = bytes_count;
556
557 remove(bat->capture.file);
558 fp = fopen(bat->capture.file, "wb");
559 err = -errno;
560 if (fp == NULL) {
561 fprintf(bat->err, _("Cannot open file: %s %d\n"),
562 bat->capture.file, err);
563 return err;
564 }
565 /* leave space for file header */
566 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) {
567 err = -errno;
568 fclose(fp);
569 return err;
570 }
571
572 while (remain > 0) {
573 size = (remain <= sndpcm->period_bytes) ?
574 remain : sndpcm->period_bytes;
575 frames = size * 8 / sndpcm->frame_bits;
576
577 /* read a chunk from pcm device */
578 err = read_from_pcm(sndpcm, frames, bat);
579 if (err != 0)
580 break;
581
582 /* write the chunk to file */
583 if (fwrite(sndpcm->buffer, 1, size, fp) != (size_t)size) {
584 err = -EIO;
585 break;
586 }
587
588 bytes_read += size;
589 remain -= size;
590 bat->periods_played++;
591
592 if (bat->period_is_limited
593 && bat->periods_played >= bat->periods_total)
594 break;
595 }
596
597 update_wav_header(bat, fp, bytes_read);
598
599 fclose(fp);
600 return err;
601 }
602
603 /**
604 * Process input data for latency test
605 */
latencytest_process_input(struct pcm_container *sndpcm, struct bat *bat)606 static int latencytest_process_input(struct pcm_container *sndpcm,
607 struct bat *bat)
608 {
609 int err = 0;
610 FILE *fp = NULL;
611 int bytes_read = 0;
612 int frames = sndpcm->period_size;
613 int size = sndpcm->period_bytes;
614 int bytes_count = bat->frames * bat->frame_size;
615
616 remove(bat->capture.file);
617 fp = fopen(bat->capture.file, "wb");
618 err = -errno;
619 if (fp == NULL) {
620 fprintf(bat->err, _("Cannot open file: %s %d\n"),
621 bat->capture.file, err);
622 return err;
623 }
624 /* leave space for file header */
625 if (fseek(fp, sizeof(struct wav_container), SEEK_SET) != 0) {
626 fclose(fp);
627 return err;
628 }
629
630 bat->latency.is_capturing = true;
631
632 while (bytes_read < bytes_count) {
633 /* read a chunk from pcm device */
634 err = read_from_pcm(sndpcm, frames, bat);
635 if (err != 0)
636 break;
637
638 /* Xrun error, terminate the capture thread*/
639 if (bat->latency.xrun_error == true)
640 break;
641
642 err = handleinput(bat, sndpcm->buffer, frames);
643 if (err != 0)
644 break;
645
646 if (bat->latency.is_playing == false)
647 break;
648
649 /* write the chunk to file */
650 if (fwrite(sndpcm->buffer, 1, size, fp) != (size_t)size) {
651 err = -EIO;
652 break;
653 }
654
655 bytes_read += size;
656 }
657
658 bat->latency.is_capturing = false;
659
660 update_wav_header(bat, fp, bytes_read);
661
662 fclose(fp);
663 return err;
664 }
665
666
pcm_cleanup(void *p)667 static void pcm_cleanup(void *p)
668 {
669 snd_pcm_close(p);
670 }
671
672 /**
673 * Record
674 */
record_alsa(struct bat *bat)675 void *record_alsa(struct bat *bat)
676 {
677 int err = 0;
678 struct pcm_container sndpcm;
679
680 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
681
682 fprintf(bat->log, _("Entering capture thread (ALSA).\n"));
683
684 retval_record = 0;
685 memset(&sndpcm, 0, sizeof(sndpcm));
686
687 err = snd_pcm_open(&sndpcm.handle, bat->capture.device,
688 SND_PCM_STREAM_CAPTURE, 0);
689 if (err != 0) {
690 fprintf(bat->err, _("Cannot open PCM capture device: "));
691 fprintf(bat->err, _("%s(%d)\n"), snd_strerror(err), err);
692 retval_record = err;
693 goto exit1;
694 }
695
696 err = set_snd_pcm_params(bat, &sndpcm);
697 if (err != 0) {
698 retval_record = err;
699 goto exit2;
700 }
701
702 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
703 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
704 pthread_cleanup_push(pcm_cleanup, sndpcm.handle);
705 pthread_cleanup_push(free, sndpcm.buffer);
706
707 fprintf(bat->log, _("Recording ...\n"));
708 if (bat->roundtriplatency)
709 err = latencytest_process_input(&sndpcm, bat);
710 else
711 err = read_from_pcm_loop(&sndpcm, bat);
712
713 pthread_cleanup_pop(0);
714 pthread_cleanup_pop(0);
715
716 if (err != 0) {
717 retval_record = err;
718 goto exit3;
719 }
720
721 /* Normally we will never reach this part of code (unless error in
722 * previous call) (before exit3) as this thread will be cancelled
723 * by end of play thread. Except in single line mode. */
724 snd_pcm_drain(sndpcm.handle);
725 pthread_exit(&retval_record);
726
727 exit3:
728 free(sndpcm.buffer);
729 exit2:
730 snd_pcm_close(sndpcm.handle);
731 exit1:
732 pthread_exit(&retval_record);
733 }
734