OSDN Git Service

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