47#include <alsa/asoundlib.h>
72#define BUF_LEN_DEFAULT_MS 60
73#define BUF_LEN_DEFAULT_SYNC_MS 200
74#define MOD_NAME "[ALSA play.] "
75#define SCRATCHPAD_SIZE (1024*1024)
83#ifdef USE_SPEEX_JITTER_BUFFER
84#include <speex/speex_jitter.h>
89#define EXIT_IF_FAILED(cmd, name) \
93 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s: %s\n", name, snd_strerror(rc));\
98#define CHECK_OK(cmd) \
102 log_msg(LOG_LEVEL_ERROR, MOD_NAME "%s: %s\n", #cmd, snd_strerror(rc));\
129#ifdef USE_SPEEX_JITTER_BUFFER
158 const char *proc_file =
"/proc/sys/kernel/sched_latency_ns";
160 int fd = open(proc_file, O_RDONLY);
166 unsigned int idx = 0;
167 while (idx <
sizeof buf - 1) {
168 ssize_t bytes = read(fd, buf + idx,
sizeof buf - 1 - idx);
183 if (idx ==
sizeof buf - 1) {
200#ifdef USE_SPEEX_JITTER_BUFFER
202 JitterBufferPacket pkt;
203 pkt.len = pkt_max_len;
204 pkt.data = alloca(pkt_max_len);
207 pthread_mutex_lock(&s->
lock);
209 pthread_mutex_unlock(&s->
lock);
213#ifdef USE_SPEEX_JITTER_BUFFER
215 int err = jitter_buffer_get(s->
buf, &pkt,
len, &start_offset);
216 jitter_buffer_tick(s->
buf);
220 pthread_mutex_unlock(&s->
lock);
222#ifdef USE_SPEEX_JITTER_BUFFER
223 if (err == JITTER_BUFFER_OK) {
230 JITTER_BUFFER_INTERNAL_ERROR ?
"internal error" :
231 "invalid argument\n");
237 pkt.len = pkt_max_len;
240 gettimeofday(&now, NULL);
247 memset(data, 0,
len);
273 snd_pcm_hw_params_t *
params;
276 memset(&ret, 0,
sizeof ret);
280 snd_pcm_hw_params_alloca(&
params);
290 assert (
desc.bps > 0 &&
desc.bps <= 4);
332 dir == 0 ?
"=" : (dir == -1 ?
"<" :
">"),
333 val, snd_strerror(rc));
337 unsigned int max_channels;
338 rc = snd_pcm_hw_params_get_channels_max(
params, &max_channels);
350 if (
channels > (
int) max_channels) {
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)) {
378 memcpy(data, &ret,
sizeof ret);
398 snd_async_handler_get_callback_private(handler);
408 pthread_mutex_lock(&s->
lock);
410 snd_pcm_sframes_t avail;
411 avail = snd_pcm_avail_update(s->
handle);
412 while (avail >= (snd_pcm_sframes_t) s->
period_size)
416 memset(
data + ret, 0,
len - ret);
420 avail = snd_pcm_avail_update(s->
handle);
425 pthread_mutex_unlock(&s->
lock);
443 " Buffer length. Can be used to balance robustness and latency, in microseconds.\n");
446 snd_pcm_hw_params_t *
params)
449 REC_MIN_BUF_US = 5000,
451 unsigned int buf_len_us = 0;
456 buff_param == NULL) {
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",
462 if (buf_len_us <= REC_MIN_BUF_US) {
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.",
472 buf_len_us = buff_param != NULL ? atoi(buff_param)
477 const int rc = snd_pcm_hw_params_set_buffer_time_near(
478 handle,
params, &buf_len_us, &buf_dir);
481 "Warning - unable to set buffer to its size %u us: %s\n",
482 buf_len_us, snd_strerror(rc));
484 MSG(INFO,
"ALSA driver buffer len set to: %lf ms\n",
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");
499 snd_pcm_hw_params_t *
params;
500 snd_pcm_format_t format;
506 pthread_mutex_lock(&s->
lock);
508 pthread_mutex_unlock(&s->
lock);
522 if (snd_pcm_state(s->
handle) == SND_PCM_STATE_RUNNING) {
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) {
533 snd_pcm_hw_params_alloca(&
params);
547 SND_PCM_ACCESS_RW_INTERLEAVED);
552 SND_PCM_ACCESS_RW_NONINTERLEAVED);
590 rc = snd_pcm_hw_params_set_rate_resample(s->
handle,
622 rc = snd_pcm_hw_params_set_period_size_min(s->
handle,
645#ifdef USE_SPEEX_JITTER_BUFFER
646 jitter_buffer_reset(s->
buf);
665 snd_pcm_sw_params_t *sw_params;
666 CHECK_OK(snd_pcm_sw_params_malloc(&sw_params));
672 snd_pcm_sw_params_free (sw_params);
678 if (snd_pcm_state(s->
handle) == SND_PCM_STATE_PREPARED) {
679 int err = snd_pcm_start(s->
handle);
681 printf(
"Start error: %s\n", snd_strerror(err));
685 if (snd_pcm_state(s->
handle) != SND_PCM_STATE_RUNNING) {
700 const char *whitelist[] = {
"pulse",
"dmix"};
702 strcpy((*available_devices)[0].dev,
"");
703 strcpy((*available_devices)[0].
name,
"Default Linux audio output");
711 color_printf(
"\t\tuse selected API ('thread' is default)\n");
713 color_printf(
"\t\tset buffer max and optionally max (thread and async API only)\n");
715 color_printf(
"\t\tlength of UG internal ALSA buffer (in milliseconds)\n");
718 printf(
"Available ALSA playback devices:\n");
725 bool default_pulse =
false;
726 bool pulse_present =
false;
728 snd_device_name_hint(-1,
"pcm", &hints);
729 while(*hints != NULL) {
730 char *tmp = strdup(*(
char **) hints);
732 char *save_ptr = NULL;
733 char *name_part = NULL;
736 assert(strlen(tmp) >= 4);
737 name_part = strtok_r(tmp + 4,
"|", &save_ptr);
738 if (name_part == NULL) {
742 desc = strtok_r(NULL,
"|", &save_ptr);
744 if (strcmp(name_part,
"default") == 0) {
745 if (
desc && strstr(
desc,
"PulseAudio")) {
746 default_pulse =
true;
750 if (strcmp(name_part,
"pulse") == 0) {
751 pulse_present =
true;
758 return default_pulse && pulse_present;
773 snd_config_t * lconf;
774 snd_config_t * device_node;
775 snd_config_t * type_node;
777 char const * type_string;
781 if (snd_config == NULL) {
785 r = snd_config_copy(&lconf, snd_config);
788 r = snd_config_search(lconf, pcm_node_name, &device_node);
790 snd_config_delete(lconf);
795 r = snd_config_search(device_node,
"type", &type_node);
797 snd_config_delete(lconf);
801 r = snd_config_get_string(type_node, &type_string);
803 snd_config_delete(lconf);
807 if (strcmp(type_string,
"pulse") != 0) {
808 snd_config_delete(lconf);
814 r = snd_config_search(device_node,
"handle_underrun", &node);
816 snd_config_delete(lconf);
820 r = snd_config_imake_integer(&node,
"handle_underrun", 0);
822 snd_config_delete(lconf);
826 r = snd_config_add(device_node, node);
828 snd_config_delete(lconf);
835ADD_TO_PARAM(
"alsa-playback-api",
"* alsa-playback-api={thread|sync|async}\n"
845 if (latency_ns > 0) {
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) {
860 }
else if (strcmp(use_api,
"async") == 0) {
877 if (strlen(cfg) > 0) {
878 if(strcmp(cfg,
"help") == 0) {
892 char device[1024] =
"pcm.";
894 strncat(device,
name,
sizeof(device) - strlen(device) - 1);
905 SND_PCM_STREAM_PLAYBACK, 0);
915 pthread_mutex_init(&s->
lock, NULL);
917#ifdef USE_SPEEX_JITTER_BUFFER
918 s->
buf = jitter_buffer_init(1);
921 rc = snd_pcm_nonblock(s->
handle, 1);
930 if (snd_pcm_name(s->
handle) && strstr(snd_pcm_name(s->
handle),
"CARD=Speakerph")) {
949 if (noninterleaved) {
961 while (written < frames) {
963 if (noninterleaved) {
964 for (
int i = 0; i <
ch_count; ++i) {
965 write_ptr[i] = tmp_buffer + frames *
bps * i + written *
bps;
967 rc = snd_pcm_writen(handle, (
void **) &write_ptr, frames);
969 rc = snd_pcm_writei(handle, data, frames - written);
975 if (playback_mode ==
SYNC) {
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);
1001 snd_pcm_prepare(s->
handle);
1003 for (snd_pcm_uframes_t f = 0; f < s->
buffer_size; f += frames) {
1004 int frames_to_write = frames;
1015 }
else if (rc < 0) {
1018 if (rc == -ENODEV) {
1023 snd_pcm_recover(s->
handle, rc, 0);
1024 }
else if (rc != (
int)frames) {
1036 snd_pcm_prepare(s->
handle);
1038 int err = snd_pcm_start(s->
handle);
1040 printf(
"Start error: %s\n", snd_strerror(err));
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;
1054 jitter_buffer_put(s->
buf, &pkt);
1058 pthread_mutex_unlock(&s->
lock);
1069 pthread_mutex_lock(&s->
lock);
1071 pthread_mutex_unlock(&s->
lock);
1079 snd_pcm_drain(s->
handle);
1080 snd_pcm_close(s->
handle);
1084 if (s->
buf != NULL) {
1085#ifdef USE_SPEEX_JITTER_BUFFER
1086 jitter_buffer_destroy(s->
buf);
1092 pthread_mutex_destroy(&s->
lock);
struct video_frame * frame
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)
static void print_alsa_device_info(snd_pcm_t *handle, const char *module_name)
This file contains definition of some common audio types.
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
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define LOG_LEVEL_FATAL
errors that prevent UG run
#define LOG_LEVEL_WARNING
less severe errors
const char * get_commandline_param(const char *key)
static struct @19 params[100]
#define ADD_TO_PARAM(param, doc)
@ LIBRARY_CLASS_AUDIO_PLAYBACK
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
static bool audio_play_alsa_query_format(struct state_alsa_playback *s, void *data, size_t *len)
static void alsa_play_async_callback(snd_async_handler_t *handler)
static long get_sched_latency_ns(void)
static void audio_play_alsa_done(void *state)
static bool is_default_pulse(void)
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)
static void * audio_play_alsa_init(const char *cfg)
#define BUF_LEN_DEFAULT_MS
static void set_device_buffer(snd_pcm_t *handle, playback_mode_t playback_mode, snd_pcm_hw_params_t *params)
static bool audio_play_alsa_ctl(void *state, int request, void *data, size_t *len)
#define BUF_LEN_DEFAULT_SYNC_MS
static void audio_play_alsa_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
static bool audio_play_alsa_reconfigure(void *state, struct audio_desc desc)
static void audio_play_alsa_write_frame(void *state, const struct audio_frame *frame)
static void audio_play_alsa_put_frame(void *state, const struct audio_frame *frame)
static void write_fill(struct state_alsa_playback *s)
#define EXIT_IF_FAILED(cmd, name)
static void audio_play_alsa_help(void)
static void * worker(void *args)
static snd_config_t * init_local_config_with_workaround(char const *pcm_node_name)
static const struct audio_playback_info aplay_alsa_info
struct used to comunicate with audio capture/playback device
snd_pcm_uframes_t buffer_size
playback_mode_t playback_mode
snd_async_handler_t * pcm_callback
struct timeval last_audio_read
long int audio_buf_len_ms
snd_pcm_uframes_t period_size
snd_config_t * local_config
double tv_diff(struct timeval curr_time, struct timeval prev_time)
This file contains some common data types.
void signed2unsigned(char *out, const char *in, int in_len)
void interleaved2noninterleaved(char *out, const char *in, int bps, int in_len, int channel_count)