MemoryLimit has been replaced by MemoryMax
[platform/upstream/pulseaudio.git] / src / pulsecore / sink.c
index acf347e..ae3be39 100644 (file)
@@ -49,6 +49,9 @@
 #include <pulsecore/macro.h>
 #include <pulsecore/play-memblockq.h>
 #include <pulsecore/flist.h>
+#ifdef __TIZEN__
+#include <pulsecore/proplist-util.h>
+#endif
 
 #include "sink.h"
 
@@ -179,6 +182,13 @@ void pa_sink_new_data_set_alternate_sample_rate(pa_sink_new_data *data, const ui
     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);
 
@@ -337,9 +347,11 @@ pa_sink* pa_sink_new(
     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
@@ -438,11 +450,11 @@ pa_sink* pa_sink_new(
     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);
@@ -778,8 +790,8 @@ void pa_sink_put(pa_sink* s) {
         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;
@@ -808,9 +820,14 @@ void pa_sink_put(pa_sink* s) {
     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 */
@@ -841,6 +858,9 @@ void pa_sink_unlink(pa_sink* s) {
 
     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);
 
@@ -850,6 +870,10 @@ void pa_sink_unlink(pa_sink* s) {
         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
@@ -861,9 +885,6 @@ void pa_sink_unlink(pa_sink* s) {
 
     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);
@@ -2483,7 +2504,11 @@ void pa_sink_mute_changed(pa_sink *s, bool new_muted) {
 }
 
 /* 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();
 
@@ -2495,8 +2520,29 @@ bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p)
         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() */
@@ -3531,6 +3577,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
         return 0;
     }
 
+    s->port_changing = true;
+
     if (s->set_port(s, port) < 0)
         return -PA_ERR_NOENTITY;
 
@@ -3548,6 +3596,8 @@ int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
 
     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
 
+    s->port_changing = false;
+
     return 0;
 }
 
@@ -3678,6 +3728,14 @@ unsigned pa_device_init_priority(pa_proplist *p) {
 
     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"))
@@ -3710,10 +3768,18 @@ unsigned pa_device_init_priority(pa_proplist *p) {
 
     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;
@@ -4050,3 +4116,48 @@ void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) {
     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);
+    }
+}