summaryrefslogtreecommitdiffstats
path: root/src/modules/alsa
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/alsa')
-rw-r--r--src/modules/alsa/alsa-sink.c65
-rw-r--r--src/modules/alsa/alsa-sink.h2
-rw-r--r--src/modules/alsa/alsa-source.c37
-rw-r--r--src/modules/alsa/alsa-source.h2
-rw-r--r--src/modules/alsa/alsa-util.c44
-rw-r--r--src/modules/alsa/alsa-util.h3
-rw-r--r--src/modules/alsa/module-alsa-card.c8
-rw-r--r--src/modules/alsa/module-alsa-sink.c2
-rw-r--r--src/modules/alsa/module-alsa-source.c2
9 files changed, 109 insertions, 56 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index dbd95b63..7bf16c3c 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -6,7 +6,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
@@ -61,10 +61,11 @@
/* #define DEBUG_TIMING */
#define DEFAULT_DEVICE "default"
-#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s */
-#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms */
-#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */
-#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */
+#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s -- Overall buffer size */
+#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms -- Fill up when only this much is left in the buffer */
+#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- On underrun, increase watermark by this */
+#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms -- Sleep at least 10ms on each iteration */
+#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms -- Wakeup at least this long before the buffer runs empty*/
struct userdata {
pa_core *core;
@@ -86,7 +87,16 @@ struct userdata {
pa_bool_t mixer_seperate_channels:1;
pa_cvolume hardware_volume;
- size_t frame_size, fragment_size, hwbuf_size, tsched_watermark, hwbuf_unused, min_sleep, min_wakeup;
+ size_t
+ frame_size,
+ fragment_size,
+ hwbuf_size,
+ tsched_watermark,
+ hwbuf_unused,
+ min_sleep,
+ min_wakeup,
+ watermark_step;
+
unsigned nfragments;
pa_memchunk memchunk;
@@ -138,7 +148,7 @@ static void reserve_update(struct userdata *u) {
const char *description;
pa_assert(u);
- if (!u->sink)
+ if (!u->sink || !u->reserve)
return;
if ((description = pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)))
@@ -154,6 +164,9 @@ static int reserve_init(struct userdata *u, const char *dname) {
if (u->reserve)
return 0;
+ if (pa_in_system_mode())
+ return 0;
+
/* We are resuming, try to lock the device */
if (!(rname = pa_alsa_get_reserve_name(dname)))
return 0;
@@ -205,10 +218,11 @@ static void adjust_after_underrun(struct userdata *u) {
pa_usec_t old_min_latency, new_min_latency;
pa_assert(u);
+ pa_assert(u->use_tsched);
/* First, just try to increase the watermark */
old_watermark = u->tsched_watermark;
- u->tsched_watermark *= 2;
+ u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_step);
fix_tsched_watermark(u);
if (old_watermark != u->tsched_watermark) {
@@ -219,7 +233,8 @@ static void adjust_after_underrun(struct userdata *u) {
/* Hmm, we cannot increase the watermark any further, hence let's raise the latency */
old_min_latency = u->sink->thread_info.min_latency;
- new_min_latency = PA_MIN(old_min_latency * 2, u->sink->thread_info.max_latency);
+ new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_STEP_USEC);
+ new_min_latency = PA_MIN(new_min_latency, u->sink->thread_info.max_latency);
if (old_min_latency != new_min_latency) {
pa_log_notice("Increasing minimal latency to %0.2f ms",
@@ -1175,17 +1190,11 @@ static int process_rewind(struct userdata *u) {
/* Figure out how much we shall rewind and reset the counter */
rewind_nbytes = u->sink->thread_info.rewind_nbytes;
- u->sink->thread_info.rewind_nbytes = 0;
- if (rewind_nbytes <= 0)
- goto finish;
-
- pa_assert(rewind_nbytes > 0);
pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
- snd_pcm_hwsync(u->pcm_handle);
- if ((unused = snd_pcm_avail_update(u->pcm_handle)) < 0) {
- pa_log("snd_pcm_avail_update() failed: %s", snd_strerror((int) unused));
+ if (PA_UNLIKELY((unused = pa_alsa_safe_avail(u->pcm_handle, u->hwbuf_size, &u->sink->sample_spec)) < 0)) {
+ pa_log("snd_pcm_avail() failed: %s", snd_strerror((int) unused));
return -1;
}
@@ -1227,12 +1236,8 @@ static int process_rewind(struct userdata *u) {
} else
pa_log_debug("Mhmm, actually there is nothing to rewind.");
-finish:
-
pa_sink_process_rewind(u->sink, 0);
-
return 0;
-
}
static void thread_func(void *userdata) {
@@ -1261,7 +1266,7 @@ static void thread_func(void *userdata) {
int work_done;
pa_usec_t sleep_usec = 0;
- if (u->sink->thread_info.rewind_requested)
+ if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
if (process_rewind(u) < 0)
goto fail;
@@ -1484,7 +1489,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
struct userdata *u = NULL;
const char *dev_id = NULL;
- pa_sample_spec ss;
+ pa_sample_spec ss, requested_ss;
pa_channel_map map;
uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, tsched_frames;
@@ -1503,6 +1508,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
goto fail;
}
+ requested_ss = ss;
frame_size = pa_frame_size(&ss);
nfrags = m->core->default_n_fragments;
@@ -1654,6 +1660,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, profile->description);
}
+ pa_alsa_init_description(data.proplist);
+
u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
pa_sink_new_data_done(&data);
@@ -1674,19 +1682,20 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);
u->nfragments = nfrags;
u->hwbuf_size = u->fragment_size * nfrags;
- u->tsched_watermark = tsched_watermark;
+ u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->sink->sample_spec);
pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
if (use_tsched) {
fix_min_sleep_wakeup(u);
fix_tsched_watermark(u);
- }
- u->sink->thread_info.max_rewind = use_tsched ? u->hwbuf_size : 0;
- u->sink->thread_info.max_request = u->hwbuf_size;
+ u->watermark_step = pa_usec_to_bytes(TSCHED_WATERMARK_STEP_USEC, &u->sink->sample_spec);
+ }
+ pa_sink_set_max_rewind(u->sink, use_tsched ? u->hwbuf_size : 0);
+ pa_sink_set_max_request(u->sink, u->hwbuf_size);
pa_sink_set_latency_range(u->sink,
- !use_tsched ? pa_bytes_to_usec(u->hwbuf_size, &ss) : (pa_usec_t) -1,
+ use_tsched ? (pa_usec_t) -1 : pa_bytes_to_usec(u->hwbuf_size, &ss),
pa_bytes_to_usec(u->hwbuf_size, &ss));
pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
diff --git a/src/modules/alsa/alsa-sink.h b/src/modules/alsa/alsa-sink.h
index 47ece9e0..bbf64234 100644
--- a/src/modules/alsa/alsa-sink.h
+++ b/src/modules/alsa/alsa-sink.h
@@ -9,7 +9,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 39df4a91..f4acad8c 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -6,7 +6,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
@@ -64,6 +64,7 @@
#define DEFAULT_DEVICE "default"
#define DEFAULT_TSCHED_BUFFER_USEC (2*PA_USEC_PER_SEC) /* 2s */
#define DEFAULT_TSCHED_WATERMARK_USEC (20*PA_USEC_PER_MSEC) /* 20ms */
+#define TSCHED_WATERMARK_STEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */
#define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC) /* 10ms */
#define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC) /* 4ms */
@@ -88,7 +89,16 @@ struct userdata {
pa_cvolume hardware_volume;
- size_t frame_size, fragment_size, hwbuf_size, tsched_watermark, hwbuf_unused, min_sleep, min_wakeup;
+ size_t
+ frame_size,
+ fragment_size,
+ hwbuf_size,
+ tsched_watermark,
+ hwbuf_unused,
+ min_sleep,
+ min_wakeup,
+ watermark_step;
+
unsigned nfragments;
char *device_name;
@@ -136,7 +146,7 @@ static void reserve_update(struct userdata *u) {
const char *description;
pa_assert(u);
- if (!u->source)
+ if (!u->source || !u->reserve)
return;
if ((description = pa_proplist_gets(u->source->proplist, PA_PROP_DEVICE_DESCRIPTION)))
@@ -152,6 +162,9 @@ static int reserve_init(struct userdata *u, const char *dname) {
if (u->reserve)
return 0;
+ if (pa_in_system_mode())
+ return 0;
+
/* We are resuming, try to lock the device */
if (!(rname = pa_alsa_get_reserve_name(dname)))
return 0;
@@ -202,10 +215,12 @@ static void adjust_after_overrun(struct userdata *u) {
pa_usec_t old_min_latency, new_min_latency;
pa_assert(u);
+ pa_assert(u->use_tsched);
/* First, just try to increase the watermark */
old_watermark = u->tsched_watermark;
- u->tsched_watermark *= 2;
+ u->tsched_watermark = PA_MIN(u->tsched_watermark * 2, u->tsched_watermark + u->watermark_step);
+
fix_tsched_watermark(u);
if (old_watermark != u->tsched_watermark) {
@@ -216,7 +231,8 @@ static void adjust_after_overrun(struct userdata *u) {
/* Hmm, we cannot increase the watermark any further, hence let's raise the latency */
old_min_latency = u->source->thread_info.min_latency;
- new_min_latency = PA_MIN(old_min_latency * 2, u->source->thread_info.max_latency);
+ new_min_latency = PA_MIN(old_min_latency * 2, old_min_latency + TSCHED_WATERMARK_STEP_USEC);
+ new_min_latency = PA_MIN(new_min_latency, u->source->thread_info.max_latency);
if (old_min_latency != new_min_latency) {
pa_log_notice("Increasing minimal latency to %0.2f ms",
@@ -1331,7 +1347,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
struct userdata *u = NULL;
const char *dev_id = NULL;
- pa_sample_spec ss;
+ pa_sample_spec ss, requested_ss;
pa_channel_map map;
uint32_t nfrags, hwbuf_size, frag_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, tsched_frames;
@@ -1349,6 +1365,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
goto fail;
}
+ requested_ss = ss;
frame_size = pa_frame_size(&ss);
nfrags = m->core->default_n_fragments;
@@ -1495,6 +1512,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_PROFILE_DESCRIPTION, profile->description);
}
+ pa_alsa_init_description(data.proplist);
+
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
pa_source_new_data_done(&data);
@@ -1515,16 +1534,18 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);
u->nfragments = nfrags;
u->hwbuf_size = u->fragment_size * nfrags;
- u->tsched_watermark = tsched_watermark;
+ u->tsched_watermark = pa_usec_to_bytes_round_up(pa_bytes_to_usec_round_up(tsched_watermark, &requested_ss), &u->source->sample_spec);
pa_cvolume_mute(&u->hardware_volume, u->source->sample_spec.channels);
if (use_tsched) {
fix_min_sleep_wakeup(u);
fix_tsched_watermark(u);
+
+ u->watermark_step = pa_usec_to_bytes(TSCHED_WATERMARK_STEP_USEC, &u->source->sample_spec);
}
pa_source_set_latency_range(u->source,
- !use_tsched ? pa_bytes_to_usec(u->hwbuf_size, &ss) : (pa_usec_t) -1,
+ use_tsched ? (pa_usec_t) -1 : pa_bytes_to_usec(u->hwbuf_size, &ss),
pa_bytes_to_usec(u->hwbuf_size, &ss));
pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
diff --git a/src/modules/alsa/alsa-source.h b/src/modules/alsa/alsa-source.h
index 5fed6cc8..9cbb0e17 100644
--- a/src/modules/alsa/alsa-source.h
+++ b/src/modules/alsa/alsa-source.h
@@ -9,7 +9,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 6740c069..454cfd4e 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -6,7 +6,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
@@ -47,6 +47,10 @@
#include "hal-util.h"
#endif
+#ifdef HAVE_UDEV
+#include "udev-util.h"
+#endif
+
struct pa_alsa_fdlist {
unsigned num_fds;
struct pollfd *fds;
@@ -1362,6 +1366,26 @@ void pa_alsa_redirect_errors_dec(void) {
snd_lib_error_set_handler(NULL);
}
+pa_bool_t pa_alsa_init_description(pa_proplist *p) {
+ const char *s;
+ pa_assert(p);
+
+ if (pa_device_init_description(p))
+ return TRUE;
+
+ if ((s = pa_proplist_gets(p, "alsa.card_name"))) {
+ pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
+ return TRUE;
+ }
+
+ if ((s = pa_proplist_gets(p, "alsa.name"))) {
+ pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
char *cn, *lcn, *dn;
@@ -1385,6 +1409,10 @@ void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card) {
pa_xfree(dn);
}
+#ifdef HAVE_UDEV
+ pa_udev_get_info(c, p, card);
+#endif
+
#ifdef HAVE_HAL
pa_hal_get_info(c, p, card);
#endif
@@ -1411,7 +1439,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *
snd_pcm_class_t class;
snd_pcm_subclass_t subclass;
- const char *n, *id, *sdn, *cn = NULL;
+ const char *n, *id, *sdn;
int card;
pa_assert(p);
@@ -1426,6 +1454,7 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *
if (alsa_class_table[class])
pa_proplist_sets(p, "alsa.class", alsa_class_table[class]);
}
+
subclass = snd_pcm_info_get_subclass(pcm_info);
if (subclass <= SND_PCM_SUBCLASS_LAST)
if (alsa_subclass_table[subclass])
@@ -1443,17 +1472,8 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *
pa_proplist_setf(p, "alsa.device", "%u", snd_pcm_info_get_device(pcm_info));
- if ((card = snd_pcm_info_get_card(pcm_info)) >= 0) {
+ if ((card = snd_pcm_info_get_card(pcm_info)) >= 0)
pa_alsa_init_proplist_card(c, p, card);
- cn = pa_proplist_gets(p, "alsa.card_name");
- }
-
- if (cn && n && !strstr(cn, n) && !strstr(n, cn))
- pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, "%s, %s", cn, n);
- else if (cn && (!n || strstr(cn, n)))
- pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, cn);
- else if (n)
- pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, n);
}
void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm) {
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index 899532e2..fe0f71e0 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -9,7 +9,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
@@ -123,6 +123,7 @@ void pa_alsa_redirect_errors_dec(void);
void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t *pcm_info);
void pa_alsa_init_proplist_card(pa_core *c, pa_proplist *p, int card);
void pa_alsa_init_proplist_pcm(pa_core *c, pa_proplist *p, snd_pcm_t *pcm);
+pa_bool_t pa_alsa_init_description(pa_proplist *p);
int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents);
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index fc6b886b..d5e2cdc2 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -5,7 +5,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
@@ -310,14 +310,16 @@ int pa__init(pa_module *m) {
pa_snprintf(rname, sizeof(rname), "Audio%i", alsa_card_index);
- if (!(reserve = pa_reserve_wrapper_get(m->core, rname)))
- goto fail;
+ if (!pa_in_system_mode())
+ if (!(reserve = pa_reserve_wrapper_get(m->core, rname)))
+ goto fail;
pa_card_new_data_init(&data);
data.driver = __FILE__;
data.module = m;
pa_alsa_init_proplist_card(m->core, data.proplist, alsa_card_index);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_id);
+ pa_alsa_init_description(data.proplist);
set_card_name(&data, ma, u->device_id);
if (reserve)
diff --git a/src/modules/alsa/module-alsa-sink.c b/src/modules/alsa/module-alsa-sink.c
index 4f844e08..c728a446 100644
--- a/src/modules/alsa/module-alsa-sink.c
+++ b/src/modules/alsa/module-alsa-sink.c
@@ -6,7 +6,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
diff --git a/src/modules/alsa/module-alsa-source.c b/src/modules/alsa/module-alsa-source.c
index c35936df..6188019f 100644
--- a/src/modules/alsa/module-alsa-source.c
+++ b/src/modules/alsa/module-alsa-source.c
@@ -6,7 +6,7 @@
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2 of the License,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but