UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
alsa.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2011-2024 CESNET
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Changes should use Safe ALSA API (http://0pointer.de/blog/projects/guide-to-sound-apis).
40 *
41 * Please, report all differencies from it here:
42 * - used format SND_PCM_FORMAT_S24_LE
43 * - used "default" device for arbitrary number of channels
44 */
45
46#include <alloca.h> // for alloca
47#include <alsa/asoundlib.h>
48#include <assert.h> // for assert
49#include <errno.h> // for ENODEV, ENOENT, EPIPE, errno
50#include <fcntl.h> // for open, O_RDONLY
51#include <pthread.h> // for pthread_mutex_t, pthread_t
52#include <stdbool.h> // for false, bool, true
53#include <stdint.h> // for uint32_t
54#include <stdio.h> // for printf
55#include <stdlib.h>
56#include <string.h>
57#include <sys/time.h> // for gettimeofday, timeval
58#include <sys/types.h> // for ssize_t
59#include <unistd.h> // for close, read
60
61#include "alsa_common.h"
63#include "audio/types.h"
64#include "audio/utils.h"
65#include "debug.h"
66#include "host.h" // for get_commandline_param, ADD_TO_PARAM
67#include "lib_common.h"
68#include "tv.h"
69#include "types.h" // for device_info
70#include "utils/color_out.h"
71
72#define BUF_LEN_DEFAULT_MS 60
73#define BUF_LEN_DEFAULT_SYNC_MS 200 // default buffer len for sync API
74#define MOD_NAME "[ALSA play.] "
75#define SCRATCHPAD_SIZE (1024*1024)
76
81//#define USE_SPEEX_JITTER_BUFFER 1
82
83#ifdef USE_SPEEX_JITTER_BUFFER
84#include <speex/speex_jitter.h>
85#else
86#include "utils/audio_buffer.h"
87#endif
88
89#define EXIT_IF_FAILED(cmd, name) \
90 do {\
91 int rc = cmd;\
92 if (rc < 0) {;\
93 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s: %s\n", name, snd_strerror(rc));\
94 goto error;\
95 }\
96 } while (0)
97
98#define CHECK_OK(cmd) \
99 do {\
100 int rc = cmd;\
101 if (rc < 0) {;\
102 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s: %s\n", #cmd, snd_strerror(rc));\
103 }\
104 } while (0)
105
106typedef enum {
109 ASYNC
111
113 snd_pcm_t *handle;
115
116 /* Local configuration with handle_underrun workaround set for PulseAudio
117 ALSA plugin. Will be NULL if the PA ALSA plugin is not in use or the
118 workaround is not required. */
119 snd_config_t * local_config;
120
123
124 snd_pcm_uframes_t period_size;
125 snd_pcm_uframes_t buffer_size;
126
127 // following variables are used only if playback_mode == THREAD
128 pthread_t thread_id;
129#ifdef USE_SPEEX_JITTER_BUFFER
130 JitterBuffer *buf;
131#else
134#endif
135 pthread_mutex_t lock;
138 uint32_t timestamp;
139 struct timeval last_audio_read;
140
141 // following variables are used only if playback_mode == ASYNC
142 snd_async_handler_t *pcm_callback;
143
145
147};
148
149static void audio_play_alsa_write_frame(void *state, const struct audio_frame *frame);
150
156static long get_sched_latency_ns(void)
157{
158 const char *proc_file = "/proc/sys/kernel/sched_latency_ns";
159
160 int fd = open(proc_file, O_RDONLY);
161 if (fd == -1) {
162 return -1;
163 }
164
165 char buf[11] = ""; // 9 digits + LF + zero
166 unsigned int idx = 0;
167 while (idx < sizeof buf - 1) {
168 ssize_t bytes = read(fd, buf + idx, sizeof buf - 1 - idx);
169 if (bytes < 0) {
170 log_msg(LOG_LEVEL_INFO, "read %s: %s\n", proc_file, strerror(errno));
171 close(fd);
172 return -1;
173 }
174 if (bytes == 0) {
175 break;
176 }
177 idx += bytes;
178 }
179
180 close(fd);
181
182 // more than 9 digits (is unlikely)
183 if (idx == sizeof buf - 1) {
184 return -1;
185 }
186
187 return atol(buf);
188}
189
190static void *worker(void *args) {
191 struct state_alsa_playback *s = args;
192
193 struct audio_frame f = { .bps = s->desc.bps,
194 .sample_rate = s->desc.sample_rate,
195 .ch_count = s->desc.ch_count };
196
197 size_t len = f.bps * f.ch_count * (f.sample_rate * s->sched_latency_ms / 1000);
198 char *data = alloca(len);
199
200#ifdef USE_SPEEX_JITTER_BUFFER
201 const int pkt_max_len = s->desc.sample_rate / 10;
202 JitterBufferPacket pkt;
203 pkt.len = pkt_max_len;
204 pkt.data = alloca(pkt_max_len);
205#endif
206 while (1) {
207 pthread_mutex_lock(&s->lock);
208 if (s->should_exit_thread) {
209 pthread_mutex_unlock(&s->lock);
210 return NULL;
211 }
212
213#ifdef USE_SPEEX_JITTER_BUFFER
214 int start_offset;
215 int err = jitter_buffer_get(s->buf, &pkt, len, &start_offset);
216 jitter_buffer_tick(s->buf);
217#else
218 int ret = audio_buffer_read(s->buf, data, len);
219#endif
220 pthread_mutex_unlock(&s->lock);
221
222#ifdef USE_SPEEX_JITTER_BUFFER
223 if (err == JITTER_BUFFER_OK) {
224 f.data_len = pkt.len;
225 f.data = pkt.data;
226 } else {
227 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "empty buffer\n");
228 if (err < 0) {
229 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Jitter buffer: %s\n",
230 JITTER_BUFFER_INTERNAL_ERROR ? "internal error" :
231 "invalid argument\n");
232 }
233 memset(data, 0, len);
234 f.data_len = len;
235 f.data = data;
236 }
237 pkt.len = pkt_max_len;
238#else
239 struct timeval now;
240 gettimeofday(&now, NULL);
241
242 if (ret > 0) {
243 f.data_len = ret;
244 f.data = data;
245 s->last_audio_read = now;
246 } else {
247 memset(data, 0, len);
248 f.data_len = len;
249 f.data = data;
250
251 if (tv_diff(now, s->last_audio_read) < 2.0) {
252 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "empty buffer\n");
253 }
254 }
255#endif
256
258 }
259}
260
261static bool audio_play_alsa_query_format(struct state_alsa_playback *s, void *data, size_t *len)
262{
263 struct audio_desc desc;
264 if (*len < sizeof desc) {
265 return false;
266 } else {
267 memcpy(&desc, data, sizeof desc);
268 }
269
270 int rc;
271 unsigned int val;
272 int dir;
273 snd_pcm_hw_params_t *params;
274 struct audio_desc ret;
275
276 memset(&ret, 0, sizeof ret);
277
278 ret.codec = AC_PCM;
279
280 snd_pcm_hw_params_alloca(&params);
281
282 /* Fill it in with default values. */
283 rc = snd_pcm_hw_params_any(s->handle, params);
284 if (rc < 0) {
285 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to set default parameters: %s\n",
286 snd_strerror(rc));
287 return false;
288 }
289
290 assert (desc.bps > 0 && desc.bps <= 4);
291 int bps = desc.bps;
292 for ( ; ; ) {
293 if (!snd_pcm_hw_params_test_format(s->handle, params, bps_to_snd_fmts[bps])) {
294 break;
295 }
296 // We try to find nearest higher
297 if (bps >= desc.bps) {
298 bps++;
299 } else { // or nearest lower
300 bps--;
301 }
302 if (bps > 4) {
303 bps = desc.bps - 1;
304 }
305 if (bps == 0) {
306 break;
307 }
308 }
309
310 ret.bps = bps;
311
312 rc = snd_pcm_hw_params_set_format(s->handle, params, bps_to_snd_fmts[bps]);
313 if (rc < 0) {
314 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to set capture format: %s\n",
315 snd_strerror(rc));
316 return false;
317 }
318
319 ret.sample_rate = get_rate_near(s->handle, params, desc.sample_rate);
320 if (!ret.sample_rate) {
321 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to find sample rate:\n");
322 return false;
323 }
324
325 /* set sampling rate */
326 val = ret.sample_rate;
327 dir = 0;
328 rc = snd_pcm_hw_params_set_rate_near(s->handle, params,
329 &val, &dir);
330 if (rc < 0) {
331 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to set sampling rate (%s %d): %s\n",
332 dir == 0 ? "=" : (dir == -1 ? "<" : ">"),
333 val, snd_strerror(rc));
334 return false;
335 }
336
337 unsigned int max_channels;
338 rc = snd_pcm_hw_params_get_channels_max(params, &max_channels);
339 if (rc < 0) {
340 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to get max number of channels!\n");
341 return false;
342 }
343 int channels = desc.ch_count;
344 // We try to find nearest higher
345 for ( ; channels <= (int) max_channels; ++channels) {
346 if (!snd_pcm_hw_params_test_channels(s->handle, params, channels)) {
347 break;
348 }
349 }
350 if (channels > (int) max_channels) { // or nearest lower
351 for (channels = desc.ch_count - 1; channels > 0; --channels) {
352 if (!snd_pcm_hw_params_test_channels(s->handle, params, channels)) {
353 break;
354 }
355 }
356 }
357
358 if (channels == 0) {
359 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to get usable channel configuration (max channels: %u)!\n", max_channels);
360 return false;
361 }
362
363 rc = snd_pcm_hw_params_set_channels(s->handle, params, channels);
364 if (rc < 0) {
365 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to set channels!\n");
366 return false;
367 }
368
369 ret.ch_count = channels;
370
371 if (snd_pcm_hw_params_test_access(s->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)
372 && snd_pcm_hw_params_test_access(s->handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
373
374 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot find supported access mode!\n");
375 return false;
376 }
377
378 memcpy(data, &ret, sizeof ret);
379 *len = sizeof ret;
380 return true;
381}
382
383static bool audio_play_alsa_ctl(void *state, int request, void *data, size_t *len)
384{
385 struct state_alsa_playback *s = (struct state_alsa_playback *) state;
386
387 switch (request) {
389 return audio_play_alsa_query_format(s, data, len);
390 default:
391 return false;
392 }
393
394}
395
396static void alsa_play_async_callback(snd_async_handler_t *handler) {
397 struct state_alsa_playback *s =
398 snd_async_handler_get_callback_private(handler);
399
400 struct audio_frame f = { .bps = s->desc.bps,
401 .sample_rate = s->desc.sample_rate,
402 .ch_count = s->desc.ch_count };
403
404 size_t len = f.bps * f.ch_count * s->period_size;
405
406 char *data = malloc(len);
407
408 pthread_mutex_lock(&s->lock);
409
410 snd_pcm_sframes_t avail;
411 avail = snd_pcm_avail_update(s->handle);
412 while (avail >= (snd_pcm_sframes_t) s->period_size)
413 {
414 int ret;
415 ret = audio_buffer_read(s->buf, data, len);
416 memset(data + ret, 0, len - ret);
417 f.data = data;
418 f.data_len = len;
420 avail = snd_pcm_avail_update(s->handle);
421 }
422
423 free(data);
424
425 pthread_mutex_unlock(&s->lock);
426}
427
428static void write_fill(struct state_alsa_playback *s) {
429 struct audio_frame f = { .bps = s->desc.bps,
430 .sample_rate = s->desc.sample_rate,
431 .ch_count = s->desc.ch_count };
432
433 size_t len = f.bps * f.ch_count * s->buffer_size;
434 f.data = calloc(1, len);
435 f.data_len = len;
436
438
439 free(f.data);
440}
441
442ADD_TO_PARAM("alsa-playback-buffer", "* alsa-playback-buffer=<len>\n"
443 " Buffer length. Can be used to balance robustness and latency, in microseconds.\n");
444static void
445set_device_buffer(snd_pcm_t *handle, playback_mode_t playback_mode,
446 snd_pcm_hw_params_t *params)
447{
448 enum {
449 REC_MIN_BUF_US = 5000,
450 };
451 unsigned int buf_len_us = 0;
452 int buf_dir = -1;
453 const char *buff_param = get_commandline_param("alsa-playback-buffer");
454
455 if (get_commandline_param("low-latency-audio") != NULL &&
456 buff_param == NULL) {
457 // set minimal value from the configuration space
458 CHECK_OK(snd_pcm_hw_params_set_buffer_time_first(
459 handle, params, &buf_len_us, &buf_dir));
460 MSG(INFO, "ALSA driver buffer len set to: %lf ms\n",
461 US_TO_MS((double) buf_len_us));
462 if (buf_len_us <= REC_MIN_BUF_US) {
463 MSG(WARNING,
464 "ALSA driver buffer len less than %d usec seem to "
465 "be too loow, consider using alsa-playback-buffer "
466 "instead of low-latency-audio.",
467 REC_MIN_BUF_US);
468 }
469 return;
470 }
471
472 buf_len_us = buff_param != NULL ? atoi(buff_param)
473 : MS_TO_US(playback_mode == SYNC
476
477 const int rc = snd_pcm_hw_params_set_buffer_time_near(
478 handle, params, &buf_len_us, &buf_dir);
479 if (rc < 0) {
480 MSG(WARNING,
481 "Warning - unable to set buffer to its size %u us: %s\n",
482 buf_len_us, snd_strerror(rc));
483 }
484 MSG(INFO, "ALSA driver buffer len set to: %lf ms\n",
485 US_TO_MS((double) buf_len_us));
486}
487
488ADD_TO_PARAM("alsa-play-period-size", "* alsa-play-period-size=<frames>\n"
489 " ALSA playback period size in frames (default is device minimum) .\n");
497{
498 struct state_alsa_playback *s = (struct state_alsa_playback *) state;
499 snd_pcm_hw_params_t *params;
500 snd_pcm_format_t format;
501 unsigned int val;
502 int dir;
503 int rc;
504
505 if (s->playback_mode == THREAD && s->thread_started) {
506 pthread_mutex_lock(&s->lock);
507 s->should_exit_thread = true;
508 pthread_mutex_unlock(&s->lock);
509 pthread_join(s->thread_id, NULL);
510 s->should_exit_thread = false;
511 s->thread_started = false;
512 }
513 if (s->playback_mode == ASYNC && s->pcm_callback) {
514 snd_async_del_handler(s->pcm_callback);
515 s->pcm_callback = NULL;
516 }
517
518 s->desc.bps = desc.bps;
519 s->desc.ch_count = desc.ch_count;
520 s->desc.sample_rate = desc.sample_rate;
521
522 if (snd_pcm_state(s->handle) == SND_PCM_STATE_RUNNING) {
523 CHECK_OK(snd_pcm_drop(s->handle)); // stop the stream
524 }
525 snd_pcm_state_t current_state = snd_pcm_state(s->handle);
526 if (current_state != SND_PCM_STATE_OPEN &&
527 current_state != SND_PCM_STATE_SETUP) {
528 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Unexpected state: %s\n",
529 alsa_get_pcm_state_name(current_state));
530 }
531
532 /* Allocate a hardware parameters object. */
533 snd_pcm_hw_params_alloca(&params);
534
535 /* Fill it in with default values. */
536 rc = snd_pcm_hw_params_any(s->handle, params);
537 if (rc < 0) {
538 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot obtain default hw parameters: %s\n",
539 snd_strerror(rc));
540 return false;
541 }
542
543 /* Set the desired hardware parameters. */
544
545 /* Interleaved mode */
546 rc = snd_pcm_hw_params_set_access(s->handle, params,
547 SND_PCM_ACCESS_RW_INTERLEAVED);
548 if (rc < 0) {
549 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot set interleaved hw access: %s\n",
550 snd_strerror(rc));
551 rc = snd_pcm_hw_params_set_access(s->handle, params,
552 SND_PCM_ACCESS_RW_NONINTERLEAVED);
553 if (rc < 0) {
554 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot set non-interleaved hw access: %s\n",
555 snd_strerror(rc));
556 return false;
557 }
558 s->non_interleaved = true;
559 } else {
560 s->non_interleaved = false;
561 }
562
563 if (desc.bps > 4 || desc.bps < 1) {
564 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unsupported BPS for audio (%d).\n",
565 desc.bps * 8);
566 return false;
567
568 }
569 format = bps_to_snd_fmts[desc.bps];
570
571 /* Signed 16-bit little-endian format */
572 rc = snd_pcm_hw_params_set_format(s->handle, params,
573 format);
574 if (rc < 0) {
575 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot set format: %s\n",
576 snd_strerror(rc));
577 return false;
578 }
579
580 /* Two channels (stereo) */
581 rc = snd_pcm_hw_params_set_channels(s->handle, params, desc.ch_count);
582 if (rc < 0) {
583 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot set requested channel count: %s\n",
584 snd_strerror(rc));
585 return false;
586 }
587
588 /* we want to resample if device doesn't support default sample rate */
589 val = 1;
590 rc = snd_pcm_hw_params_set_rate_resample(s->handle,
591 params, val);
592 if(rc < 0) {
593 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: Unable to set resampling: %s\n",
594 snd_strerror(rc));
595 }
596
597
598 /* 44100 bits/second sampling rate (CD quality) */
599 val = desc.sample_rate;
600 dir = 0;
601 rc = snd_pcm_hw_params_set_rate_near(s->handle, params,
602 &val, &dir);
603 if (rc < 0) {
604 log_msg(LOG_LEVEL_ERROR, MOD_NAME "cannot set requested sample rate: %s\n",
605 snd_strerror(rc));
606 return false;
607 }
608
609 /* Set period to its minimal size.
610 *
611 * Do not use snd_pcm_hw_params_set_period_time_near(), since it
612 * allows to set also unsupported value without notifying. Using
613 * snd_pcm_hw_params_set_period_time_first() with Pulseaudio
614 * returns invalid argument.
615 *
616 * See also http://www.alsa-project.org/main/index.php/FramesPeriods */
617 s->period_size = 1;
618 if (get_commandline_param("alsa-play-period-size")) {
619 s->period_size = atoi(get_commandline_param("alsa-play-period-size"));
620 }
621 dir = 1;
622 rc = snd_pcm_hw_params_set_period_size_min(s->handle,
623 params, &s->period_size, &dir);
624 if (rc < 0) {
625 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: cannot set period time: %s\n",
626 snd_strerror(rc));
627 } else {
628 log_msg(LOG_LEVEL_INFO, MOD_NAME "Period size: %lu frames (%lf ms)\n", s->period_size, (double) s->period_size / desc.sample_rate * 1000);
629 }
630
632
633 /* Write the parameters to the driver */
634 rc = snd_pcm_hw_params(s->handle, params);
635 if (rc < 0) {
636 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to set hw parameters: %s\n",
637 snd_strerror(rc));
638 return false;
639 }
640
641 snd_pcm_hw_params_current(s->handle, params);
642 snd_pcm_hw_params_get_buffer_size(params, &s->buffer_size);
643
644 if (s->playback_mode == THREAD || s->playback_mode == ASYNC) {
645#ifdef USE_SPEEX_JITTER_BUFFER
646 jitter_buffer_reset(s->buf);
647#else
649 s->audio_buf_len_ms = get_commandline_param("low-latency-audio") ? 5 : s->sched_latency_ms * 2;
650 if (get_commandline_param("audio-buffer-len")) {
651 s->audio_buf_len_ms = atoi(get_commandline_param("audio-buffer-len"));
652 }
653 log_msg(LOG_LEVEL_INFO, "[ALSA play.] Setting audio buffer length: %ld ms\n", s->audio_buf_len_ms);
655#endif
656 }
657
658 if (s->playback_mode == THREAD) {
659 s->timestamp = 0;
660 pthread_create(&s->thread_id, NULL, worker, s);
661 s->thread_started = true;
662 }
663
664 if (s->playback_mode == ASYNC) {
665 snd_pcm_sw_params_t *sw_params;
666 CHECK_OK(snd_pcm_sw_params_malloc(&sw_params));
667 CHECK_OK(snd_pcm_sw_params_current (s->handle, sw_params));
668 CHECK_OK(snd_pcm_sw_params_set_start_threshold(s->handle, sw_params, s->buffer_size - s->period_size));
669 CHECK_OK(snd_pcm_sw_params_set_stop_threshold(s->handle, sw_params, s->buffer_size));
670 CHECK_OK(snd_pcm_sw_params_set_avail_min(s->handle, sw_params, s->period_size));
671 CHECK_OK(snd_pcm_sw_params(s->handle, sw_params));
672 snd_pcm_sw_params_free (sw_params);
673
674 EXIT_IF_FAILED(snd_async_add_pcm_handler(&s->pcm_callback, s->handle, alsa_play_async_callback, s), "Add async handler");
675
676 write_fill(s);
677
678 if (snd_pcm_state(s->handle) == SND_PCM_STATE_PREPARED) {
679 int err = snd_pcm_start(s->handle);
680 if (err < 0) {
681 printf("Start error: %s\n", snd_strerror(err));
682 goto error;
683 }
684 }
685 if (snd_pcm_state(s->handle) != SND_PCM_STATE_RUNNING) {
686 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Device was not running: %s!\n",
687 alsa_get_pcm_state_name(snd_pcm_state(s->handle)));
688 goto error;
689 }
690 }
691
692 return true;
693error:
694 return false;
695}
696
697static void audio_play_alsa_probe(struct device_info **available_devices, int *count, void (**deleter)(void *))
698{
699 *deleter = free;
700 const char *whitelist[] = {"pulse", "dmix"};
701 audio_alsa_probe(available_devices, count, whitelist, sizeof(whitelist) / sizeof(*whitelist));
702 strcpy((*available_devices)[0].dev, "");
703 strcpy((*available_devices)[0].name, "Default Linux audio output");
704}
705
706static void audio_play_alsa_help(void) {
707 printf("Usage\n");
708 color_printf(TERM_BOLD TERM_FG_RED "\t-r alsa" TERM_FG_RESET "[:<device>] --param alsa-playback-api={thread|async|sync}[,alsa-playback-buffer=[<us>-]<us>][,audio-buffer-len=<ablen>]\n" TERM_RESET);
709 color_printf("where\n");
710 color_printf(TERM_BOLD "\talsa-playback-api={thread|async|sync}\n" TERM_RESET);
711 color_printf("\t\tuse selected API ('thread' is default)\n");
712 color_printf(TERM_BOLD "\talsa-playback-buffer=[<us>-]<us>\n" TERM_RESET);
713 color_printf("\t\tset buffer max and optionally max (thread and async API only)\n");
714 color_printf(TERM_BOLD "\taudio-buffer-len=<ablen>\n" TERM_RESET);
715 color_printf("\t\tlength of UG internal ALSA buffer (in milliseconds)\n");
716 printf("\n");
717
718 printf("Available ALSA playback devices:\n");
720}
721
722static bool is_default_pulse(void)
723{
724 void **hints;
725 bool default_pulse = false;
726 bool pulse_present = false;
727
728 snd_device_name_hint(-1, "pcm", &hints);
729 while(*hints != NULL) {
730 char *tmp = strdup(*(char **) hints);
731 assert(tmp != NULL);
732 char *save_ptr = NULL;
733 char *name_part = NULL;
734 char *desc = NULL;
735
736 assert(strlen(tmp) >= 4);
737 name_part = strtok_r(tmp + 4, "|", &save_ptr);
738 if (name_part == NULL) {
739 free(tmp);
740 continue;
741 }
742 desc = strtok_r(NULL, "|", &save_ptr);
743
744 if (strcmp(name_part, "default") == 0) {
745 if (desc && strstr(desc, "PulseAudio")) {
746 default_pulse = true;
747 }
748 }
749
750 if (strcmp(name_part, "pulse") == 0) {
751 pulse_present = true;
752 }
753
754 hints++;
755 free(tmp);
756 }
757
758 return default_pulse && pulse_present;
759}
760
761/* Work around PulseAudio ALSA plugin bug where the PA server forces a
762 higher than requested latency, but the plugin does not update its (and
763 ALSA's) internal state to reflect that, leading to an immediate underrun
764 situation. Inspired by WINE's make_handle_underrun_config.
765 Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-July/053391.html
766 https://github.com/kinetiknz/cubeb/commit/1aa0058d0729eb85505df104cd1ac072432c6d24
767 http://en.it-usenet.org/thread/17996/19923/
768*/
769static snd_config_t *
770init_local_config_with_workaround(char const * pcm_node_name)
771{
772 int r;
773 snd_config_t * lconf;
774 snd_config_t * device_node;
775 snd_config_t * type_node;
776 snd_config_t * node;
777 char const * type_string;
778
779 lconf = NULL;
780
781 if (snd_config == NULL) {
782 snd_config_update();
783 }
784
785 r = snd_config_copy(&lconf, snd_config);
786 assert(r >= 0);
787
788 r = snd_config_search(lconf, pcm_node_name, &device_node);
789 if (r != 0) {
790 snd_config_delete(lconf);
791 return NULL;
792 }
793
794 /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */
795 r = snd_config_search(device_node, "type", &type_node);
796 if (r != 0) {
797 snd_config_delete(lconf);
798 return NULL;
799 }
800
801 r = snd_config_get_string(type_node, &type_string);
802 if (r != 0) {
803 snd_config_delete(lconf);
804 return NULL;
805 }
806
807 if (strcmp(type_string, "pulse") != 0) {
808 snd_config_delete(lconf);
809 return NULL;
810 }
811
812 /* Don't clobber an explicit existing handle_underrun value, set it only
813 if it doesn't already exist. */
814 r = snd_config_search(device_node, "handle_underrun", &node);
815 if (r != -ENOENT) {
816 snd_config_delete(lconf);
817 return NULL;
818 }
819
820 r = snd_config_imake_integer(&node, "handle_underrun", 0);
821 if (r != 0) {
822 snd_config_delete(lconf);
823 return NULL;
824 }
825
826 r = snd_config_add(device_node, node);
827 if (r != 0) {
828 snd_config_delete(lconf);
829 return NULL;
830 }
831
832 return lconf;
833}
834
835ADD_TO_PARAM("alsa-playback-api", "* alsa-playback-api={thread|sync|async}\n"
836 " ALSA API.\n");
837static void * audio_play_alsa_init(const char *cfg)
838{
839 int rc;
840 const char *name;
841
842 struct state_alsa_playback *s = calloc(1, sizeof(struct state_alsa_playback));
843
844 long latency_ns = get_sched_latency_ns();
845 if (latency_ns > 0) {
846 s->sched_latency_ms = latency_ns / 1000 / 1000;
847 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Sched latency: %ld ms.\n", s->sched_latency_ms);
848 } else {
849 s->sched_latency_ms = 24;
850 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Unable to get latency, assuming %ld.\n", s->sched_latency_ms);
851 }
852
853 const char *use_api;
854 use_api = get_commandline_param("alsa-playback-api");
855 if (use_api) {
856 if (strcmp(use_api, "thread") == 0 || strcmp(use_api, "new") == 0) {
858 } else if (strcmp(use_api, "sync") == 0 || strcmp(use_api, "old") == 0) {
859 s->playback_mode = SYNC;
860 } else if (strcmp(use_api, "async") == 0) {
861 s->playback_mode = ASYNC;
862 } else {
863 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown API string \"%s\"!\n", use_api);
864 free(s);
865 return NULL;
866 }
867 }
868
869 if (s->playback_mode == THREAD) {
870 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Using new API. In case of problems, you may try to use '--param alsa-playback-api=sync'.\n");
871 }
872
873 if (s->playback_mode == ASYNC) {
874 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Async API is experimental, in case of problems use either \"thread\" or \"sync\" API\n");
875 }
876
877 if (strlen(cfg) > 0) {
878 if(strcmp(cfg, "help") == 0) {
880 free(s);
881 return INIT_NOERR;
882 }
883 name = cfg;
884 } else {
885 if (is_default_pulse()) {
886 name = "pulse";
887 } else {
888 name = "default";
889 }
890 }
891
892 char device[1024] = "pcm.";
893
894 strncat(device, name, sizeof(device) - strlen(device) - 1);
895
896 if (s->playback_mode == SYNC) {
898 }
899
900 if (s->playback_mode == SYNC && s->local_config) {
901 rc = snd_pcm_open_lconf(&s->handle, name,
902 SND_PCM_STREAM_PLAYBACK, 0, s->local_config);
903 } else {
904 rc = snd_pcm_open(&s->handle, name,
905 SND_PCM_STREAM_PLAYBACK, 0);
906 }
907
908 if (rc < 0) {
909 log_msg(LOG_LEVEL_ERROR, MOD_NAME "unable to open pcm device: %s\n",
910 snd_strerror(rc));
911 goto error;
912 }
914
915 pthread_mutex_init(&s->lock, NULL);
916 if (s->playback_mode == THREAD) {
917#ifdef USE_SPEEX_JITTER_BUFFER
918 s->buf = jitter_buffer_init(1);
919#endif
920 } else if (s->playback_mode == SYNC) {
921 rc = snd_pcm_nonblock(s->handle, 1);
922 if(rc < 0) {
923 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: Unable to set nonblock mode.\n");
924 }
925 }
926
927 /* CC3000e playback needs to be initialized prior to capture
928 * (to arbitrary value) in order to work. This hack ensures
929 * that. */
930 if (snd_pcm_name(s->handle) && strstr(snd_pcm_name(s->handle), "CARD=Speakerph")) {
931 struct audio_desc desc = {2, 48000, 1, AC_PCM};
932 size_t len = sizeof desc;
935 }
936 }
937
938 s->scratchpad = malloc(SCRATCHPAD_SIZE);
939 return s;
940
941error:
942 free(s);
943 return NULL;
944}
945
946static int write_samples(snd_pcm_t *handle, const char *data, int bps, int ch_count, int frames, bool noninterleaved, playback_mode_t playback_mode, char *tmp_buffer) {
947 char *write_ptr[ch_count]; // for non-interleaved
948 long data_len = bps * ch_count * frames;
949 if (noninterleaved) {
950 assert(frames * bps * ch_count < SCRATCHPAD_SIZE);
951 interleaved2noninterleaved(tmp_buffer, data, bps, data_len, ch_count);
952 data = tmp_buffer;
953 }
954 if (bps == 1) { // convert to unsigned
955 assert(frames * bps * ch_count < SCRATCHPAD_SIZE);
956 signed2unsigned(tmp_buffer, data, data_len); // data may already equal tmp_buffer if noninterleaved, but np, s2u can work in situ
957 data = tmp_buffer;
958 }
959
960 int written = 0;
961 while (written < frames) {
962 int rc;
963 if (noninterleaved) {
964 for (int i = 0; i < ch_count; ++i) {
965 write_ptr[i] = tmp_buffer + frames * bps * i + written * bps;
966 }
967 rc = snd_pcm_writen(handle, (void **) &write_ptr, frames);
968 } else {
969 rc = snd_pcm_writei(handle, data, frames - written);
970 }
971
972 if (rc < 0) {
973 return rc;
974 }
975 if (playback_mode == SYNC) { // overrun (in non-blocking mode) or signal
976 return rc;
977 }
978 written += rc;
979 data += written * bps * ch_count;
980 }
981 return written;
982}
983
984static void audio_play_alsa_write_frame(void *state, const struct audio_frame *frame)
985{
986 struct state_alsa_playback *s = (struct state_alsa_playback *) state;
987 int rc;
988
990 snd_pcm_sframes_t delay = 0;
991 snd_pcm_delay(s->handle, &delay);
992 fprintf(stderr, "Alsa delay: %d samples (%u Hz)\n", (int) delay,
993 (unsigned int) frame->sample_rate);
994 }
995
996 int frames = frame->data_len / (frame->bps * frame->ch_count);
997 rc = write_samples(s->handle, frame->data, frame->bps, frame->ch_count, frames, s->non_interleaved, s->playback_mode, s->scratchpad);
998 if (rc == -EPIPE) {
999 /* EPIPE means underrun */
1000 log_msg(LOG_LEVEL_WARNING, MOD_NAME "underrun occurred\n");
1001 snd_pcm_prepare(s->handle);
1002 /* fill the stream with some sasmples */
1003 for (snd_pcm_uframes_t f = 0; f < s->buffer_size; f += frames) {
1004 int frames_to_write = frames;
1005 if (f + frames > s->buffer_size) {
1006 frames_to_write = s->buffer_size - frames;
1007 }
1008 int rc = write_samples(s->handle, frame->data, frame->bps, frame->ch_count, frames_to_write, s->non_interleaved, s->playback_mode, s->scratchpad);
1009 if(rc < 0) {
1010 log_msg(LOG_LEVEL_WARNING, MOD_NAME "error from writei: %s\n",
1011 snd_strerror(rc));
1012 break;
1013 }
1014 }
1015 } else if (rc < 0) {
1016 log_msg(LOG_LEVEL_WARNING, MOD_NAME "error from writei: %s\n",
1017 snd_strerror(rc));
1018 if (rc == -ENODEV) { // someone pulled the device (eg. videoconferencing
1019 // microphone) out - taking that as a fatal error
1020 log_msg(LOG_LEVEL_FATAL, MOD_NAME "Device removed, exiting!\n");
1022 }
1023 snd_pcm_recover(s->handle, rc, 0);
1024 } else if (rc != (int)frames) {
1025 log_msg(LOG_LEVEL_WARNING, MOD_NAME "short write, written %d frames (overrun)\n", rc);
1026 }
1027}
1028
1029static void audio_play_alsa_put_frame(void *state, const struct audio_frame *frame)
1030{
1031 struct state_alsa_playback *s = state;
1032
1033 // first repair asyn stream if needed
1034 if (s->playback_mode == ASYNC && snd_pcm_state(s->handle) != SND_PCM_STATE_RUNNING) {
1035 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s\n", alsa_get_pcm_state_name(snd_pcm_state(s->handle)));
1036 snd_pcm_prepare(s->handle);
1037 write_fill(s);
1038 int err = snd_pcm_start(s->handle);
1039 if (err < 0) {
1040 printf("Start error: %s\n", snd_strerror(err));
1041 }
1042 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "%s\n", alsa_get_pcm_state_name(snd_pcm_state(s->handle)));
1043 }
1044
1045 if (s->playback_mode == THREAD || s->playback_mode == ASYNC) {
1046 pthread_mutex_lock(&s->lock);
1047#ifdef USE_SPEEX_JITTER_BUFFER
1048 JitterBufferPacket pkt;
1049 pkt.data = frame->data;
1050 pkt.len = frame->data_len;
1051 pkt.timestamp = s->timestamp;
1052 pkt.span = frame->data_len / s->desc.bps / s->desc.ch_count;
1053 s->timestamp += pkt.span;
1054 jitter_buffer_put(s->buf, &pkt);
1055#else
1056 audio_buffer_write(s->buf, frame->data, frame->data_len);
1057#endif
1058 pthread_mutex_unlock(&s->lock);
1059 } else {
1061 }
1062}
1063
1064static void audio_play_alsa_done(void *state)
1065{
1066 struct state_alsa_playback *s = (struct state_alsa_playback *) state;
1067
1068 if (s->playback_mode == THREAD && s->thread_started) {
1069 pthread_mutex_lock(&s->lock);
1070 s->should_exit_thread = true;
1071 pthread_mutex_unlock(&s->lock);
1072 pthread_join(s->thread_id, NULL);
1073 }
1074
1075 if (s->playback_mode == ASYNC && s->pcm_callback) {
1076 snd_async_del_handler(s->pcm_callback);
1077 }
1078
1079 snd_pcm_drain(s->handle);
1080 snd_pcm_close(s->handle);
1081 if (s->local_config) {
1082 snd_config_delete(s->local_config);
1083 }
1084 if (s->buf != NULL) {
1085#ifdef USE_SPEEX_JITTER_BUFFER
1086 jitter_buffer_destroy(s->buf);
1087#else
1089#endif
1090 }
1091
1092 pthread_mutex_destroy(&s->lock);
1093
1094 free(s->scratchpad);
1095 free(s);
1096}
1097
1106
1108
void ** state
int void * val
struct video_desc desc
int int channels
struct video_frame * frame
int void size_t * len
int void(** deleter)(void *))
static const snd_pcm_format_t bps_to_snd_fmts[]
static const char * alsa_get_pcm_state_name(snd_pcm_state_t state) __attribute__((unused))
static int get_rate_near(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int approx_val)
static void audio_alsa_list_devices(void)
static void audio_alsa_probe(struct device_info **available_devices, int *count, const char **whitelist, size_t whitelist_size)
Definition alsa_common.h:50
static void print_alsa_device_info(snd_pcm_t *handle, const char *module_name)
This file contains definition of some common audio types.
@ AC_PCM
Definition types.h:53
void audio_buffer_destroy(struct audio_buffer *buf)
struct audio_buffer * audio_buffer_init(int sample_rate, int bps, int ch_count, int suggested_latency_ms)
int audio_buffer_read(struct audio_buffer *buf, char *out, int max_len)
void audio_buffer_write(struct audio_buffer *buf, const char *in, int len)
#define AUDIO_PLAYBACK_CTL_QUERY_FORMAT
#define AUDIO_PLAYBACK_ABI_VERSION
#define MOD_NAME
Definition alsa.c:67
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
#define TERM_FG_RESET
Definition color_out.h:59
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_DEBUG2
Definition debug.h:67
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
int count
Definition hd-rum.c:44
void exit_uv(int status)
Definition host.cpp:625
const char * get_commandline_param(const char *key)
Definition host.cpp:894
static struct @19 params[100]
#define EXIT_FAIL_AUDIO
Definition host.h:70
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
#define INIT_NOERR
Definition host.h:73
volatile int log_level
Definition debug.cpp:65
@ LIBRARY_CLASS_AUDIO_PLAYBACK
Definition lib_common.h:77
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
static bool audio_play_alsa_query_format(struct state_alsa_playback *s, void *data, size_t *len)
Definition alsa.c:261
static void alsa_play_async_callback(snd_async_handler_t *handler)
Definition alsa.c:396
static long get_sched_latency_ns(void)
Definition alsa.c:156
#define CHECK_OK(cmd)
Definition alsa.c:98
static void audio_play_alsa_done(void *state)
Definition alsa.c:1064
static bool is_default_pulse(void)
Definition alsa.c:722
static int write_samples(snd_pcm_t *handle, const char *data, int bps, int ch_count, int frames, bool noninterleaved, playback_mode_t playback_mode, char *tmp_buffer)
Definition alsa.c:946
static void * audio_play_alsa_init(const char *cfg)
Definition alsa.c:837
#define BUF_LEN_DEFAULT_MS
Definition alsa.c:72
static void set_device_buffer(snd_pcm_t *handle, playback_mode_t playback_mode, snd_pcm_hw_params_t *params)
Definition alsa.c:445
static bool audio_play_alsa_ctl(void *state, int request, void *data, size_t *len)
Definition alsa.c:383
#define SCRATCHPAD_SIZE
Definition alsa.c:75
#define BUF_LEN_DEFAULT_SYNC_MS
Definition alsa.c:73
static void audio_play_alsa_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
Definition alsa.c:697
static bool audio_play_alsa_reconfigure(void *state, struct audio_desc desc)
Definition alsa.c:496
static void audio_play_alsa_write_frame(void *state, const struct audio_frame *frame)
Definition alsa.c:984
static void audio_play_alsa_put_frame(void *state, const struct audio_frame *frame)
Definition alsa.c:1029
static void write_fill(struct state_alsa_playback *s)
Definition alsa.c:428
playback_mode_t
Definition alsa.c:106
@ SYNC
Definition alsa.c:108
@ ASYNC
Definition alsa.c:109
@ THREAD
Definition alsa.c:107
#define EXIT_IF_FAILED(cmd, name)
Definition alsa.c:89
static void audio_play_alsa_help(void)
Definition alsa.c:706
static void * worker(void *args)
Definition alsa.c:190
static snd_config_t * init_local_config_with_workaround(char const *pcm_node_name)
Definition alsa.c:770
static const struct audio_playback_info aplay_alsa_info
Definition alsa.c:1098
const char * name
Definition settings.cpp:193
int sample_rate
Definition types.h:78
int ch_count
Definition types.h:79
int bps
Definition types.h:77
audio_codec_t codec
Definition types.h:80
struct used to comunicate with audio capture/playback device
Definition types.h:99
int sample_rate
Definition types.h:101
char * data
Definition types.h:102
int ch_count
Definition types.h:104
int data_len
Definition types.h:103
int bps
Definition types.h:100
pthread_mutex_t lock
Definition alsa.c:135
snd_pcm_uframes_t buffer_size
Definition alsa.c:125
bool should_exit_thread
Definition alsa.c:136
playback_mode_t playback_mode
Definition alsa.c:122
uint32_t timestamp
Definition alsa.c:138
snd_async_handler_t * pcm_callback
Definition alsa.c:142
bool thread_started
Definition alsa.c:137
pthread_t thread_id
Definition alsa.c:128
struct timeval last_audio_read
Definition alsa.c:139
struct audio_desc desc
Definition alsa.c:114
char * scratchpad
Definition alsa.c:146
audio_buffer_t * buf
Definition alsa.c:132
bool non_interleaved
Definition alsa.c:121
long int audio_buf_len_ms
Definition alsa.c:133
long sched_latency_ms
Definition alsa.c:144
snd_pcm_uframes_t period_size
Definition alsa.c:124
snd_config_t * local_config
Definition alsa.c:119
snd_pcm_t * handle
Definition alsa.c:113
int64_t timestamp
Definition types.h:331
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
#define MS_TO_US(val_ms)
Definition tv.h:97
#define US_TO_MS(val_us)
Definition tv.h:96
This file contains some common data types.
void signed2unsigned(char *out, const char *in, int in_len)
Definition utils.cpp:515
void interleaved2noninterleaved(char *out, const char *in, int bps, int in_len, int channel_count)
Definition utils.cpp:610