#include <pulsecore/macro.h>
#include <pulsecore/play-memblockq.h>
#include <pulsecore/flist.h>
+#ifdef __TIZEN__
+#include <pulsecore/proplist-util.h>
+#endif
#include "sink.h"
data->alternate_sample_rate = alternate_sample_rate;
}
+void pa_sink_new_data_set_avoid_resampling(pa_sink_new_data *data, bool avoid_resampling) {
+ pa_assert(data);
+
+ data->avoid_resampling_is_set = true;
+ data->avoid_resampling = avoid_resampling;
+}
+
void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
pa_assert(data);
else
s->alternate_sample_rate = s->core->alternate_sample_rate;
- s->avoid_resampling = data->avoid_resampling;
+ if (data->avoid_resampling_is_set)
+ s->avoid_resampling = data->avoid_resampling;
+ else
+ s->avoid_resampling = s->core->avoid_resampling;
#ifdef __TIZEN__
- s->origin_avoid_resampling = data->avoid_resampling;
s->selected_sample_format = s->sample_spec.format;
s->selected_sample_rate = s->sample_spec.rate;
#endif
pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
pa_source_new_data_set_alternate_sample_rate(&source_data, s->alternate_sample_rate);
+ pa_source_new_data_set_avoid_resampling(&source_data, s->avoid_resampling);
source_data.name = pa_sprintf_malloc("%s.monitor", name);
source_data.driver = data->driver;
source_data.module = data->module;
source_data.card = data->card;
- source_data.avoid_resampling = data->avoid_resampling;
dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
} else
/* We assume that if the sink implementor changed the default
- * volume he did so in real_volume, because that is the usual
- * place where he is supposed to place his changes. */
+ * volume they did so in real_volume, because that is the usual
+ * place where they are supposed to place their changes. */
s->reference_volume = s->real_volume;
s->thread_info.soft_volume = s->soft_volume;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
- /* This function must be called after the PA_CORE_HOOK_SINK_PUT hook,
- * because module-switch-on-connect needs to know the old default sink */
+ /* It's good to fire the SINK_PUT hook before updating the default sink,
+ * because module-switch-on-connect will set the new sink as the default
+ * sink, and if we were to call pa_core_update_default_sink() before that,
+ * the default sink might change twice, causing unnecessary stream moving. */
+
pa_core_update_default_sink(s->core);
+
+ pa_core_move_streams_to_newly_available_preferred_sink(s->core, s);
}
/* Called from main context */
pa_core_update_default_sink(s->core);
+ if (linked && s->core->rescue_streams)
+ pa_sink_move_streams_to_default_sink(s->core, s, false);
+
if (s->card)
pa_idxset_remove_by_data(s->card->sinks, s, NULL);
j = i;
}
+ /* Unlink monitor source before unlinking the sink */
+ if (s->monitor_source)
+ pa_source_unlink(s->monitor_source);
+
if (linked)
/* It's important to keep the suspend cause unchanged when unlinking,
* because if we remove the SESSION suspend cause here, the alsa sink
reset_callbacks(s);
- if (s->monitor_source)
- pa_source_unlink(s->monitor_source);
-
if (linked) {
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
}
/* Called from main thread */
+#ifdef __TIZEN__
+void pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
+#else
bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
+#endif
pa_sink_assert_ref(s);
pa_assert_ctl_context();
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
+#ifndef __TIZEN__
return true;
+#endif
+}
+
+#ifdef __TIZEN__
+/* Called from main thread */
+void pa_sink_update_proplist_remote_access_permission(pa_sink *s, bool allowed) {
+ pa_proplist* p = NULL;
+
+ pa_sink_assert_ref(s);
+ pa_assert_ctl_context();
+
+ p = pa_proplist_new();
+
+ if (pa_proplist_set_remote_access_permission(p, allowed) == 0)
+ pa_sink_update_proplist(s, PA_UPDATE_REPLACE, p);
+ else
+ pa_log_error("set remote access permission %d on proplist %p failed", allowed, p);
+
+ pa_proplist_free(p);
}
+#endif /* __TIZEN__ */
/* Called from main thread */
/* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
return 0;
}
+ s->port_changing = true;
+
if (s->set_port(s, port) < 0)
return -PA_ERR_NOENTITY;
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
+ s->port_changing = false;
+
return 0;
}
pa_assert(p);
+ /* JACK sinks and sources get very high priority so that we'll switch the
+ * default devices automatically when jackd starts and
+ * module-jackdbus-detect creates the jack sink and source. */
+ if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_API))) {
+ if (pa_streq(s, "jack"))
+ priority += 10000;
+ }
+
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS))) {
if (pa_streq(s, "sound"))
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
- if (pa_startswith(s, "analog-"))
+ if (pa_startswith(s, "analog-")) {
priority += 9;
+
+ /* If an analog device has an intended role of "phone", it probably
+ * co-exists with another device that is meant for everything else,
+ * and that other device should have higher priority than the phone
+ * device. */
+ if (pa_str_in_list_spaces(pa_proplist_gets(p, PA_PROP_DEVICE_INTENDED_ROLES), "phone"))
+ priority -= 1;
+ }
else if (pa_startswith(s, "iec958-"))
- priority += 8;
+ priority += 7;
}
return priority;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s);
}
+
+void pa_sink_move_streams_to_default_sink(pa_core *core, pa_sink *old_sink, bool default_sink_changed) {
+ pa_sink_input *i;
+ uint32_t idx;
+
+ pa_assert(core);
+ pa_assert(old_sink);
+
+ if (core->state == PA_CORE_SHUTDOWN)
+ return;
+
+ if (core->default_sink == NULL || core->default_sink->unlink_requested)
+ return;
+
+ if (old_sink == core->default_sink)
+ return;
+
+ PA_IDXSET_FOREACH(i, old_sink->inputs, idx) {
+ if (!PA_SINK_INPUT_IS_LINKED(i->state))
+ continue;
+
+ if (!i->sink)
+ continue;
+
+ /* Don't move sink-inputs which connect filter sinks to their target sinks */
+ if (i->origin_sink)
+ continue;
+
+ /* If default_sink_changed is false, the old sink became unavailable, so all streams must be moved. */
+ if (pa_safe_streq(old_sink->name, i->preferred_sink) && default_sink_changed)
+ continue;
+
+ if (!pa_sink_input_may_move_to(i, core->default_sink))
+ continue;
+
+ if (default_sink_changed)
+ pa_log_info("The sink input %u \"%s\" is moving to %s due to change of the default sink.",
+ i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), core->default_sink->name);
+ else
+ pa_log_info("The sink input %u \"%s\" is moving to %s, because the old sink became unavailable.",
+ i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)), core->default_sink->name);
+
+ pa_sink_input_move_to(i, core->default_sink, false);
+ }
+}