#include <sys/stat.h>
#include <errno.h>
+#include <pulse/timeval.h>
+#include <pulse/rtclock.h>
+
#include <pulse/xmalloc.h>
#include <pulse/proplist.h>
#define STREAM_FOCUS_STATE_ACQUIRED "1"
#define MUTE_KEY "mute_by_device_disconnection"
+#define TIMED_UNMUTE_USEC 300000
typedef enum _process_stream_result {
PROCESS_STREAM_RESULT_OK,
} else {
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
- /* FIXME: if PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED is not called for some reason,
- * volume factor should be removed forcedly. */
- if (type == STREAM_SINK_INPUT) {
- pa_sink_input *i = (pa_sink_input *)stream;
- if ((pa_hashmap_get(i->volume_factor_items, MUTE_KEY)))
- pa_sink_input_remove_volume_factor(i, MUTE_KEY);
- }
}
/* skip roles */
pa_log_error("[SM][UPDATE_SINK_SOURCE] could not handle it here, stream_route_type(%d)", stream_route_type);
}
-static void mute_sink_inputs_as_device_disconnection(pa_stream_manager *m, uint32_t event_id, bool need_to_mute, void *user_data) {
- pa_idxset *muted_streams;
- uint32_t s_idx = 0;
+static void apply_volume_factor_to_streams(pa_idxset *all_streams, pa_idxset **applied_streams) {
pa_cvolume vol;
pa_sink_input *i;
+ uint32_t idx = 0;
+
+ pa_assert(all_streams);
+ pa_assert(applied_streams);
+
+ pa_log_debug("apply_volume_factor_to_streams is called");
+
+ vol.channels = 1;
+ pa_parse_volume("0%", &vol.values[0]);
+ *applied_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+ PA_IDXSET_FOREACH(i, all_streams, idx) {
+ stream_route_type_t route_type = STREAM_ROUTE_TYPE_AUTO;
+ /* skip in case of auto-all type or manual-ext type */
+ if (!get_route_type(i, STREAM_SINK_INPUT, false, &route_type) &&
+ (route_type == STREAM_ROUTE_TYPE_AUTO_ALL || route_type == STREAM_ROUTE_TYPE_MANUAL_EXT))
+ continue;
+
+ pa_log_info("found a stream(%p, %u) that should be muted.", i, i->index);
+ /* remove MUTE_KEY before adding to avoid abort-case in pa_sink_input_add_volume_factor */
+ pa_hashmap_remove(i->volume_factor_items, MUTE_KEY);
+ pa_sink_input_add_volume_factor(i, MUTE_KEY, &vol);
+ pa_idxset_put(*applied_streams, i, NULL);
+ }
+}
+
+static void clear_volume_factor_from_streams(pa_idxset *applied_streams) {
+ pa_sink_input *i;
+ uint32_t idx = 0;
+
+ pa_assert(applied_streams);
+
+ pa_log_debug("clear_volume_factor_from_streams is called");
+
+ PA_IDXSET_FOREACH(i, applied_streams, idx) {
+ pa_idxset_remove_by_data(applied_streams, i, NULL);
+ pa_sink_input_remove_volume_factor(i, MUTE_KEY);
+ pa_log_info("found a stream(%p, %u) that should be un-muted.", i, i->index);
+ }
+ pa_idxset_free(applied_streams, NULL);
+}
+
+static void timed_unmute_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
+ pa_stream_manager *m = userdata;
+ pa_idxset *applied_streams;
+ void *state;
+
+ pa_assert(m);
+ pa_assert(m->time_event_for_unmute == e);
+
+ pa_log_info("timed_unmute_cb is called");
+
+ PA_HASHMAP_FOREACH(applied_streams, m->muted_streams, state) {
+ clear_volume_factor_from_streams(applied_streams);
+ pa_log_warn("remove volume factors forcedly...");
+ }
+ pa_hashmap_remove_all(m->muted_streams);
+
+ m->core->mainloop->time_free(m->time_event_for_unmute);
+ m->time_event_for_unmute = NULL;
+}
+
+static void mute_sink_inputs_as_device_disconnection(pa_stream_manager *m, uint32_t event_id, bool need_to_mute, void *user_data) {
+ pa_idxset *applied_streams;
pa_assert(m);
+ pa_log_info("mute_sink_inputs_as_device_disconnection(), event_id(%u), mute(%d) is called", event_id, need_to_mute);
+
if (need_to_mute) {
if (!user_data) {
pa_log_error("invalid argument, inputs is needed");
return;
}
- vol.channels = 1;
- pa_parse_volume("0%", &vol.values[0]);
- muted_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- PA_IDXSET_FOREACH(i, (pa_idxset *)user_data, s_idx) {
- pa_log_debug("found a stream(%p, %u) that should be muted.", i, i->index);
- /* remove MUTE_KEY before adding to avoid abort-case in pa_sink_input_add_volume_factor */
- pa_hashmap_remove(i->volume_factor_items, MUTE_KEY);
- pa_sink_input_add_volume_factor(i, MUTE_KEY, &vol);
- pa_idxset_put(muted_streams, i, NULL);
- }
- pa_hashmap_put(m->muted_streams, (void*)event_id, muted_streams);
+ apply_volume_factor_to_streams(m->core->sink_inputs, &applied_streams);
+ pa_hashmap_put(m->muted_streams, (void*)event_id, applied_streams);
+
+ /* If PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED is not called for some reason,
+ * volume factor should be removed forcedly. */
+ if (!m->time_event_for_unmute)
+ m->time_event_for_unmute = pa_core_rttime_new(m->core, pa_rtclock_now() + TIMED_UNMUTE_USEC, timed_unmute_cb, m);
} else {
- if (!(muted_streams = pa_hashmap_get(m->muted_streams, (void*)event_id))) {
- pa_log_debug("could not find muted_streams for event_id(%u)", event_id);
+ if (!(applied_streams = pa_hashmap_get(m->muted_streams, (void*)event_id))) {
+ pa_log_debug("could not find applied_streams for event_id(%u)", event_id);
return;
}
- PA_IDXSET_FOREACH(i, muted_streams, s_idx) {
- pa_idxset_remove_by_data(muted_streams, i, NULL);
- pa_sink_input_remove_volume_factor(i, MUTE_KEY);
- pa_log_debug("found a stream(%p, %u) that should be un-muted.", i, i->index);
- }
+ clear_volume_factor_from_streams(applied_streams);
pa_hashmap_remove(m->muted_streams, (void*)event_id);
- pa_idxset_free(muted_streams, NULL);
}
return;