diff options
Diffstat (limited to 'src/modules/alsa')
-rw-r--r-- | src/modules/alsa/alsa-sink.c | 139 | ||||
-rw-r--r-- | src/modules/alsa/alsa-source.c | 134 | ||||
-rw-r--r-- | src/modules/alsa/alsa-util.c | 114 | ||||
-rw-r--r-- | src/modules/alsa/alsa-util.h | 5 | ||||
-rw-r--r-- | src/modules/alsa/module-alsa-card.c | 21 |
5 files changed, 387 insertions, 26 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index ef51f1db..dbd95b63 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -53,6 +53,8 @@ #include <pulsecore/rtclock.h> #include <pulsecore/time-smoother.h> +#include <modules/reserve-wrap.h> + #include "alsa-util.h" #include "alsa-sink.h" @@ -101,10 +103,75 @@ struct userdata { pa_smoother *smoother; uint64_t write_count; uint64_t since_start; + + pa_reserve_wrapper *reserve; + pa_hook_slot *reserve_slot; }; static void userdata_free(struct userdata *u); +static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) { + pa_assert(r); + pa_assert(u); + + if (pa_sink_suspend(u->sink, TRUE) < 0) + return PA_HOOK_CANCEL; + + return PA_HOOK_OK; +} + +static void reserve_done(struct userdata *u) { + pa_assert(u); + + if (u->reserve_slot) { + pa_hook_slot_free(u->reserve_slot); + u->reserve_slot = NULL; + } + + if (u->reserve) { + pa_reserve_wrapper_unref(u->reserve); + u->reserve = NULL; + } +} + +static void reserve_update(struct userdata *u) { + const char *description; + pa_assert(u); + + if (!u->sink) + return; + + if ((description = pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION))) + pa_reserve_wrapper_set_application_device_name(u->reserve, description); +} + +static int reserve_init(struct userdata *u, const char *dname) { + char *rname; + + pa_assert(u); + pa_assert(dname); + + if (u->reserve) + return 0; + + /* We are resuming, try to lock the device */ + if (!(rname = pa_alsa_get_reserve_name(dname))) + return 0; + + u->reserve = pa_reserve_wrapper_get(u->core, rname); + pa_xfree(rname); + + if (!(u->reserve)) + return -1; + + reserve_update(u); + + pa_assert(!u->reserve_slot); + u->reserve_slot = pa_hook_connect(pa_reserve_wrapper_hook(u->reserve), PA_HOOK_NORMAL, (pa_hook_cb_t) reserve_cb, u); + + return 0; +} + static void fix_min_sleep_wakeup(struct userdata *u) { size_t max_use, max_use_2; @@ -255,6 +322,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle pa_bool_t work_done = TRUE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_play; + unsigned j = 0; pa_assert(u); pa_sink_assert_ref(u->sink); @@ -306,9 +374,12 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle if (polled) PA_ONCE_BEGIN { - pa_log(_("ALSA woke us up to write new data to the device, but there was actually nothing to write! " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. " - "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.")); + char *dn = pa_alsa_get_driver_name_by_pcm(u->pcm_handle); + pa_log(_("ALSA woke us up to write new data to the device, but there was actually nothing to write!\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.\n" + "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail() returned 0 or another value < min_avail."), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; #ifdef DEBUG_TIMING @@ -317,6 +388,15 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle break; } + + if (++j > 10) { +#ifdef DEBUG_TIMING + pa_log_debug("Not filling up, because already too many iterations."); +#endif + + break; + } + n_bytes -= u->hwbuf_unused; polled = FALSE; @@ -396,6 +476,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle pa_bool_t work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_play; + unsigned j = 0; pa_assert(u); pa_sink_assert_ref(u->sink); @@ -435,14 +516,25 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle if (polled) PA_ONCE_BEGIN { - pa_log(_("ALSA woke us up to write new data to the device, but there was actually nothing to write! " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. " - "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail_update() returned 0.")); + char *dn = pa_alsa_get_driver_name_by_pcm(u->pcm_handle); + pa_log(_("ALSA woke us up to write new data to the device, but there was actually nothing to write!\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.\n" + "We were woken up with POLLOUT set -- however a subsequent snd_pcm_avail() returned 0 or another value < min_avail."), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; break; } + if (++j > 10) { +#ifdef DEBUG_TIMING + pa_log_debug("Not filling up, because already too many iterations."); +#endif + + break; + } + n_bytes -= u->hwbuf_unused; polled = FALSE; @@ -516,7 +608,7 @@ static void update_smoother(struct userdata *u) { /* Let's update the time smoother */ - if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { + if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->sink->sample_spec)) < 0)) { pa_log_warn("Failed to query DSP status data: %s", snd_strerror(err)); return; } @@ -576,6 +668,7 @@ static int build_pollfd(struct userdata *u) { return 0; } +/* Called from IO context */ static int suspend(struct userdata *u) { pa_assert(u); pa_assert(u->pcm_handle); @@ -597,6 +690,7 @@ static int suspend(struct userdata *u) { return 0; } +/* Called from IO context */ static int update_sw_params(struct userdata *u) { snd_pcm_uframes_t avail_min; int err; @@ -652,6 +746,7 @@ static int update_sw_params(struct userdata *u) { return 0; } +/* Called from IO context */ static int unsuspend(struct userdata *u) { pa_sample_spec ss; int err; @@ -724,6 +819,7 @@ fail: return -1; } +/* Called from IO context */ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; @@ -779,6 +875,25 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse return pa_sink_process_msg(o, code, data, offset, chunk); } +/* Called from main context */ +static int sink_set_state_cb(pa_sink *s, pa_sink_state_t new_state) { + pa_sink_state_t old_state; + struct userdata *u; + + pa_sink_assert_ref(s); + pa_assert_se(u = s->userdata); + + old_state = pa_sink_get_state(u->sink); + + if (PA_SINK_IS_OPENED(old_state) && new_state == PA_SINK_SUSPENDED) + reserve_done(u); + else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state)) + if (reserve_init(u, u->device_name) < 0) + return -1; + + return 0; +} + static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { struct userdata *u = snd_mixer_elem_get_callback_private(elem); @@ -1443,6 +1558,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_smoother_set_time_offset(u->smoother, usec); pa_smoother_pause(u->smoother, usec); + if (reserve_init(u, pa_modargs_get_value( + ma, "device_id", + pa_modargs_get_value(ma, "device", DEFAULT_DEVICE))) < 0) + goto fail; + b = use_mmap; d = use_tsched; @@ -1544,6 +1664,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->sink->parent.process_msg = sink_process_msg; u->sink->update_requested_latency = sink_update_requested_latency_cb; + u->sink->set_state = sink_set_state_cb; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); @@ -1576,6 +1697,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca pa_log_info("Time scheduling watermark is %0.2fms", (double) pa_bytes_to_usec(u->tsched_watermark, &ss) / PA_USEC_PER_MSEC); + reserve_update(u); + if (update_sw_params(u) < 0) goto fail; @@ -1656,6 +1779,8 @@ static void userdata_free(struct userdata *u) { if (u->smoother) pa_smoother_free(u->smoother); + reserve_done(u); + pa_xfree(u->device_name); pa_xfree(u); } diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index fbc21f74..39df4a91 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -54,6 +54,8 @@ #include <pulsecore/time-smoother.h> #include <pulsecore/rtclock.h> +#include <modules/reserve-wrap.h> + #include "alsa-util.h" #include "alsa-source.h" @@ -99,10 +101,75 @@ struct userdata { pa_smoother *smoother; uint64_t read_count; + + pa_reserve_wrapper *reserve; + pa_hook_slot *reserve_slot; }; static void userdata_free(struct userdata *u); +static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) { + pa_assert(r); + pa_assert(u); + + if (pa_source_suspend(u->source, TRUE) < 0) + return PA_HOOK_CANCEL; + + return PA_HOOK_OK; +} + +static void reserve_done(struct userdata *u) { + pa_assert(u); + + if (u->reserve_slot) { + pa_hook_slot_free(u->reserve_slot); + u->reserve_slot = NULL; + } + + if (u->reserve) { + pa_reserve_wrapper_unref(u->reserve); + u->reserve = NULL; + } +} + +static void reserve_update(struct userdata *u) { + const char *description; + pa_assert(u); + + if (!u->source) + return; + + if ((description = pa_proplist_gets(u->source->proplist, PA_PROP_DEVICE_DESCRIPTION))) + pa_reserve_wrapper_set_application_device_name(u->reserve, description); +} + +static int reserve_init(struct userdata *u, const char *dname) { + char *rname; + + pa_assert(u); + pa_assert(dname); + + if (u->reserve) + return 0; + + /* We are resuming, try to lock the device */ + if (!(rname = pa_alsa_get_reserve_name(dname))) + return 0; + + u->reserve = pa_reserve_wrapper_get(u->core, rname); + pa_xfree(rname); + + if (!(u->reserve)) + return -1; + + reserve_update(u); + + pa_assert(!u->reserve_slot); + u->reserve_slot = pa_hook_connect(pa_reserve_wrapper_hook(u->reserve), PA_HOOK_NORMAL, (pa_hook_cb_t) reserve_cb, u); + + return 0; +} + static void fix_min_sleep_wakeup(struct userdata *u) { size_t max_use, max_use_2; pa_assert(u); @@ -248,6 +315,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled pa_bool_t work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; + unsigned j = 0; pa_assert(u); pa_source_assert_ref(u->source); @@ -289,9 +357,12 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled if (polled) PA_ONCE_BEGIN { - pa_log(_("ALSA woke us up to read new data from the device, but there was actually nothing to read! " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. " - "We were woken up with POLLIN set -- however a subsequent snd_pcm_avail_update() returned 0.")); + char *dn = pa_alsa_get_driver_name_by_pcm(u->pcm_handle); + pa_log(_("ALSA woke us up to read new data from the device, but there was actually nothing to read!\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.\n" + "We were woken up with POLLIN set -- however a subsequent snd_pcm_avail() returned 0 or another value < min_avail."), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; #ifdef DEBUG_TIMING @@ -300,6 +371,14 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled break; } + if (++j > 10) { +#ifdef DEBUG_TIMING + pa_log_debug("Not filling up, because already too many iterations."); +#endif + + break; + } + polled = FALSE; #ifdef DEBUG_TIMING @@ -378,6 +457,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled int work_done = FALSE; pa_usec_t max_sleep_usec = 0, process_usec = 0; size_t left_to_record; + unsigned j = 0; pa_assert(u); pa_source_assert_ref(u->source); @@ -410,14 +490,25 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled if (polled) PA_ONCE_BEGIN { - pa_log(_("ALSA woke us up to read new data from the device, but there was actually nothing to read! " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers. " - "We were woken up with POLLIN set -- however a subsequent snd_pcm_avail_update() returned 0.")); + char *dn = pa_alsa_get_driver_name_by_pcm(u->pcm_handle); + pa_log(_("ALSA woke us up to read new data from the device, but there was actually nothing to read!\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers.\n" + "We were woken up with POLLIN set -- however a subsequent snd_pcm_avail() returned 0 or another value < min_avail."), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; break; } + if (++j > 10) { +#ifdef DEBUG_TIMING + pa_log_debug("Not filling up, because already too many iterations."); +#endif + + break; + } + polled = FALSE; for (;;) { @@ -486,7 +577,7 @@ static void update_smoother(struct userdata *u) { /* Let's update the time smoother */ - if (PA_UNLIKELY((err = snd_pcm_delay(u->pcm_handle, &delay)) < 0)) { + if (PA_UNLIKELY((err = pa_alsa_safe_delay(u->pcm_handle, &delay, u->hwbuf_size, &u->source->sample_spec)) < 0)) { pa_log_warn("Failed to get delay: %s", snd_strerror(err)); return; } @@ -741,6 +832,25 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off return pa_source_process_msg(o, code, data, offset, chunk); } +/* Called from main context */ +static int source_set_state_cb(pa_source *s, pa_source_state_t new_state) { + pa_source_state_t old_state; + struct userdata *u; + + pa_source_assert_ref(s); + pa_assert_se(u = s->userdata); + + old_state = pa_source_get_state(u->source); + + if (PA_SINK_IS_OPENED(old_state) && new_state == PA_SINK_SUSPENDED) + reserve_done(u); + else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state)) + if (reserve_init(u, u->device_name) < 0) + return -1; + + return 0; +} + static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) { struct userdata *u = snd_mixer_elem_get_callback_private(elem); @@ -1292,6 +1402,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC*2, DEFAULT_TSCHED_WATERMARK_USEC*2, TRUE, 5); pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); + if (reserve_init(u, pa_modargs_get_value( + ma, "device_id", + pa_modargs_get_value(ma, "device", DEFAULT_DEVICE))) < 0) + goto fail; + b = use_mmap; d = use_tsched; @@ -1390,6 +1505,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->source->parent.process_msg = source_process_msg; u->source->update_requested_latency = source_update_requested_latency_cb; + u->source->set_state = source_set_state_cb; u->source->userdata = u; pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); @@ -1419,6 +1535,8 @@ 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); + reserve_update(u); + if (update_sw_params(u) < 0) goto fail; @@ -1495,6 +1613,8 @@ static void userdata_free(struct userdata *u) { if (u->smoother) pa_smoother_free(u->smoother); + reserve_done(u); + pa_xfree(u->device_name); pa_xfree(u); } diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 016e52ab..6740c069 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1448,9 +1448,9 @@ void pa_alsa_init_proplist_pcm_info(pa_core *c, pa_proplist *p, snd_pcm_info_t * cn = pa_proplist_gets(p, "alsa.card_name"); } - if (cn && n) - pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, "%s - %s", cn, n); - else if (cn) + 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); @@ -1574,18 +1574,70 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa k = (size_t) n * pa_frame_size(ss); - if (k >= hwbuf_size * 3 || - k >= pa_bytes_per_second(ss)*10) + if (k >= hwbuf_size * 5 || + k >= pa_bytes_per_second(ss)*10) { PA_ONCE_BEGIN { - pa_log(_("snd_pcm_avail_update() returned a value that is exceptionally large: %lu bytes (%lu ms). " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers."), - (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); + char *dn = pa_alsa_get_driver_name_by_pcm(pcm); + pa_log(_("snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."), + (unsigned long) k, + (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; + /* Mhmm, let's try not to fail completely */ + n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + } + return n; } +int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss) { + ssize_t k; + size_t abs_k; + int r; + + pa_assert(pcm); + pa_assert(delay); + pa_assert(hwbuf_size > 0); + pa_assert(ss); + + /* Some ALSA driver expose weird bugs, let's inform the user about + * what is going on */ + + if ((r = snd_pcm_delay(pcm, delay)) < 0) + return r; + + k = (ssize_t) *delay * (ssize_t) pa_frame_size(ss); + + abs_k = k >= 0 ? (size_t) k : (size_t) -k; + + if (abs_k >= hwbuf_size * 5 || + abs_k >= pa_bytes_per_second(ss)*10) { + + PA_ONCE_BEGIN { + char *dn = pa_alsa_get_driver_name_by_pcm(pcm); + pa_log(_("snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."), + (signed long) k, + k < 0 ? "-" : "", + (unsigned long) (pa_bytes_to_usec(abs_k, ss) / PA_USEC_PER_MSEC), + pa_strnull(dn)); + pa_xfree(dn); + } PA_ONCE_END; + + /* Mhmm, let's try not to fail completely */ + if (k < 0) + *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + else + *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss)); + } + + return 0; +} + int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss) { int r; snd_pcm_uframes_t before; @@ -1612,9 +1664,13 @@ int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas k >= pa_bytes_per_second(ss)*10) PA_ONCE_BEGIN { - pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms). " - "Most likely this is an ALSA driver bug. Please report this issue to the ALSA developers."), - (unsigned long) k, (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC)); + char *dn = pa_alsa_get_driver_name_by_pcm(pcm); + pa_log(_("snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" + "Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."), + (unsigned long) k, + (unsigned long) (pa_bytes_to_usec(k, ss) / PA_USEC_PER_MSEC), + pa_strnull(dn)); + pa_xfree(dn); } PA_ONCE_END; return r; @@ -1637,3 +1693,39 @@ char *pa_alsa_get_driver_name(int card) { return n; } + +char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) { + int card; + + snd_pcm_info_t* info; + snd_pcm_info_alloca(&info); + + if (snd_pcm_info(pcm, info) < 0) + return NULL; + + if ((card = snd_pcm_info_get_card(info)) < 0) + return NULL; + + return pa_alsa_get_driver_name(card); +} + +char *pa_alsa_get_reserve_name(const char *device) { + const char *t; + int i; + + pa_assert(device); + + if ((t = strchr(device, ':'))) + device = t+1; + + if ((i = snd_card_get_index(device)) < 0) { + int32_t k; + + if (pa_atoi(device, &k) < 0) + return NULL; + + i = (int) k; + } + + return pa_sprintf_malloc("Audio%i", i); +} diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 2d0f407e..899532e2 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -129,8 +129,13 @@ int pa_alsa_recover_from_poll(snd_pcm_t *pcm, int revents); pa_rtpoll_item* pa_alsa_build_pollfd(snd_pcm_t *pcm, pa_rtpoll *rtpoll); snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa_sample_spec *ss); +int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_size, const pa_sample_spec *ss); int pa_alsa_safe_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames, size_t hwbuf_size, const pa_sample_spec *ss); char *pa_alsa_get_driver_name(int card); +char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm); + +char *pa_alsa_get_reserve_name(const char *device); + #endif diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index c9494355..fc6b886b 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -30,6 +30,8 @@ #include <pulsecore/modargs.h> #include <pulsecore/queue.h> +#include <modules/reserve-wrap.h> + #include "alsa-util.h" #include "alsa-sink.h" #include "alsa-source.h" @@ -273,11 +275,14 @@ static void set_card_name(pa_card_new_data *data, pa_modargs *ma, const char *de pa_xfree(t); } -int pa__init(pa_module*m) { +int pa__init(pa_module *m) { pa_card_new_data data; pa_modargs *ma; int alsa_card_index; struct userdata *u; + char rname[32]; + pa_reserve_wrapper *reserve = NULL; + const char *description; pa_alsa_redirect_errors_inc(); snd_config_update_free_global(); @@ -303,6 +308,11 @@ int pa__init(pa_module*m) { goto fail; } + pa_snprintf(rname, sizeof(rname), "Audio%i", alsa_card_index); + + if (!(reserve = pa_reserve_wrapper_get(m->core, rname))) + goto fail; + pa_card_new_data_init(&data); data.driver = __FILE__; data.module = m; @@ -310,6 +320,10 @@ int pa__init(pa_module*m) { pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_id); set_card_name(&data, ma, u->device_id); + if (reserve) + if ((description = pa_proplist_gets(data.proplist, PA_PROP_DEVICE_DESCRIPTION))) + pa_reserve_wrapper_set_application_device_name(reserve, description); + u->profiles = data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); if (pa_alsa_probe_profiles(u->device_id, &m->core->default_sample_spec, enumerate_cb, u) < 0) { pa_card_new_data_done(&data); @@ -335,11 +349,16 @@ int pa__init(pa_module*m) { init_profile(u); + pa_reserve_wrapper_unref(reserve); + return 0; fail: + if (reserve) + pa_reserve_wrapper_unref(reserve); pa__done(m); + return -1; } |