summaryrefslogtreecommitdiffstats
path: root/src/modules/alsa/alsa-source.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/alsa/alsa-source.c')
-rw-r--r--src/modules/alsa/alsa-source.c90
1 files changed, 81 insertions, 9 deletions
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 843f70bb..c176309e 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -114,6 +114,8 @@ struct userdata {
pa_reserve_wrapper *reserve;
pa_hook_slot *reserve_slot;
+ pa_reserve_monitor_wrapper *monitor;
+ pa_hook_slot *monitor_slot;
};
static void userdata_free(struct userdata *u);
@@ -122,7 +124,7 @@ static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct u
pa_assert(r);
pa_assert(u);
- if (pa_source_suspend(u->source, TRUE) < 0)
+ if (pa_source_suspend(u->source, TRUE, PA_SUSPEND_APPLICATION) < 0)
return PA_HOOK_CANCEL;
return PA_HOOK_OK;
@@ -183,6 +185,57 @@ static int reserve_init(struct userdata *u, const char *dname) {
return 0;
}
+static pa_hook_result_t monitor_cb(pa_reserve_monitor_wrapper *w, void* busy, struct userdata *u) {
+ pa_bool_t b;
+
+ pa_assert(w);
+ pa_assert(u);
+
+ b = PA_PTR_TO_UINT(busy) && !u->reserve;
+
+ pa_source_suspend(u->source, b, PA_SUSPEND_APPLICATION);
+ return PA_HOOK_OK;
+}
+
+static void monitor_done(struct userdata *u) {
+ pa_assert(u);
+
+ if (u->monitor_slot) {
+ pa_hook_slot_free(u->monitor_slot);
+ u->monitor_slot = NULL;
+ }
+
+ if (u->monitor) {
+ pa_reserve_monitor_wrapper_unref(u->monitor);
+ u->monitor = NULL;
+ }
+}
+
+static int reserve_monitor_init(struct userdata *u, const char *dname) {
+ char *rname;
+
+ pa_assert(u);
+ pa_assert(dname);
+
+ 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;
+
+ u->monitor = pa_reserve_monitor_wrapper_get(u->core, rname);
+ pa_xfree(rname);
+
+ if (!(u->monitor))
+ return -1;
+
+ pa_assert(!u->monitor_slot);
+ u->monitor_slot = pa_hook_connect(pa_reserve_monitor_wrapper_hook(u->monitor), PA_HOOK_NORMAL, (pa_hook_cb_t) monitor_cb, u);
+
+ return 0;
+}
+
static void fix_min_sleep_wakeup(struct userdata *u) {
size_t max_use, max_use_2;
pa_assert(u);
@@ -455,7 +508,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
u->read_count += frames * u->frame_size;
#ifdef DEBUG_TIMING
- pa_log_debug("Read %lu bytes", (unsigned long) (frames * u->frame_size));
+ pa_log_debug("Read %lu bytes (of possible %lu bytes)", (unsigned long) (frames * u->frame_size), (unsigned long) n_bytes);
#endif
if ((size_t) frames * u->frame_size >= n_bytes)
@@ -1105,7 +1158,7 @@ fail:
static void source_get_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
- int err, sw;
+ int err, sw = 0;
pa_assert(u);
pa_assert(u->mixer_elem);
@@ -1366,6 +1419,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
size_t frame_size;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
pa_source_new_data data;
+ char *control_device = NULL;
pa_assert(m);
pa_assert(ma);
@@ -1437,9 +1491,14 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_rtclock_usec(),
FALSE);
- if (reserve_init(u, pa_modargs_get_value(
- ma, "device_id",
- pa_modargs_get_value(ma, "device", DEFAULT_DEVICE))) < 0)
+ dev_id = pa_modargs_get_value(
+ ma, "device_id",
+ pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
+
+ if (reserve_init(u, dev_id) < 0)
+ goto fail;
+
+ if (reserve_monitor_init(u, dev_id) < 0)
goto fail;
b = use_mmap;
@@ -1519,7 +1578,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
/* ALSA might tweak the sample spec, so recalculate the frame size */
frame_size = pa_frame_size(&ss);
- pa_alsa_find_mixer_and_elem(u->pcm_handle, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
+ pa_alsa_find_mixer_and_elem(u->pcm_handle, &control_device, &u->mixer_handle, &u->mixer_elem, pa_modargs_get_value(ma, "control", NULL), profile);
pa_source_new_data_init(&data);
data.driver = driver;
@@ -1542,6 +1601,17 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_alsa_init_description(data.proplist);
+ if (control_device) {
+ pa_alsa_init_proplist_ctl(data.proplist, control_device);
+ pa_xfree(control_device);
+ }
+
+ if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+ pa_log("Invalid properties");
+ pa_source_new_data_done(&data);
+ goto fail;
+ }
+
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|(u->use_tsched ? PA_SOURCE_DYNAMIC_LATENCY : 0));
pa_source_new_data_done(&data);
@@ -1582,7 +1652,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
pa_log_info("Time scheduling watermark is %0.2fms",
(double) pa_bytes_to_usec(u->tsched_watermark, &ss) / PA_USEC_PER_MSEC);
} else
- u->source->fixed_latency = pa_bytes_to_usec(u->hwbuf_size, &ss);
+ pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->hwbuf_size, &ss));
reserve_update(u);
@@ -1621,7 +1691,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
fail:
- userdata_free(u);
+ if (u)
+ userdata_free(u);
return NULL;
}
@@ -1663,6 +1734,7 @@ static void userdata_free(struct userdata *u) {
pa_smoother_free(u->smoother);
reserve_done(u);
+ monitor_done(u);
pa_xfree(u->device_name);
pa_xfree(u);