]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/sink.c
devices: Set certain sink/source flags automatically.
[pulseaudio] / src / pulsecore / sink.c
index 626c727886a9825c1938f15a4c3cd9f26f6ad0f6..b51156f7e10a797e0f12fb37287d2714ad242d0a 100644 (file)
@@ -24,9 +24,9 @@
 #include <config.h>
 #endif
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 
 #include <pulse/introspect.h>
 #include <pulse/utf8.h>
@@ -449,6 +449,55 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
     return 0;
 }
 
+void pa_sink_set_get_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
+    pa_assert(s);
+
+    s->get_volume = cb;
+}
+
+void pa_sink_set_set_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
+    pa_assert(s);
+
+    pa_assert(!s->write_volume || cb);
+
+    s->set_volume = cb;
+
+    if (cb)
+        s->flags |= PA_SINK_HW_VOLUME_CTRL;
+    else
+        s->flags &= ~PA_SINK_HW_VOLUME_CTRL;
+}
+
+void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
+    pa_assert(s);
+
+    pa_assert(!cb || s->set_volume);
+
+    s->write_volume = cb;
+
+    if (cb)
+        s->flags |= PA_SINK_SYNC_VOLUME;
+    else
+        s->flags &= ~PA_SINK_SYNC_VOLUME;
+}
+
+void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
+    pa_assert(s);
+
+    s->get_mute = cb;
+}
+
+void pa_sink_set_set_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
+    pa_assert(s);
+
+    s->set_mute = cb;
+
+    if (cb)
+        s->flags |= PA_SINK_HW_MUTE_CTRL;
+    else
+        s->flags &= ~PA_SINK_HW_MUTE_CTRL;
+}
+
 /* Called from main context */
 void pa_sink_put(pa_sink* s) {
     pa_sink_assert_ref(s);
@@ -462,8 +511,18 @@ void pa_sink_put(pa_sink* s) {
     pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
 
     /* Generally, flags should be initialized via pa_sink_new(). As a
-     * special exception we allow volume related flags to be set
-     * between _new() and _put(). */
+     * special exception we allow some volume related flags to be set
+     * between _new() and _put() by the callback setter functions above.
+     *
+     * Thus we implement a couple safeguards here which ensure the above
+     * setters were used (or at least the implementor made manual changes
+     * in a compatible way).
+     *
+     * Note: All of these flags set here can change over the life time
+     * of the sink. */
+    pa_assert(!(s->flags & PA_SINK_HW_VOLUME_CTRL) || s->set_volume);
+    pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || s->write_volume);
+    pa_assert(!(s->flags & PA_SINK_HW_MUTE_CTRL) || s->set_mute);
 
     /* XXX: Currently decibel volume is disabled for all sinks that use volume
      * sharing. When the master sink supports decibel volume, it would be good
@@ -472,6 +531,10 @@ void pa_sink_put(pa_sink* s) {
      * a master sink to another. One solution for this problem would be to
      * remove user-visible volume altogether from filter sinks when volume
      * sharing is used, but the current approach was easier to implement... */
+    /* We always support decibel volumes in software, otherwise we leave it to
+     * the sink implementor to set this flag as needed.
+     *
+     * Note: This flag can also change over the life time of the sink. */
     if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
         s->flags |= PA_SINK_DECIBEL_VOLUME;
 
@@ -506,10 +569,6 @@ void pa_sink_put(pa_sink* s) {
     pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->thread_info.fixed_latency != 0));
     pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
     pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY));
-    pa_assert(!(s->flags & PA_SINK_HW_VOLUME_CTRL) || s->set_volume);
-    pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || (s->flags & PA_SINK_HW_VOLUME_CTRL));
-    pa_assert(!(s->flags & PA_SINK_SYNC_VOLUME) || s->write_volume);
-    pa_assert(!(s->flags & PA_SINK_HW_MUTE_CTRL) || s->set_mute);
 
     pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency);
     pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency);
@@ -1252,7 +1311,7 @@ pa_bool_t pa_sink_is_passthrough(pa_sink *s) {
     if (pa_idxset_size(s->inputs) == 1) {
         alt_i = pa_idxset_first(s->inputs, &idx);
 
-        if (!pa_format_info_is_pcm(alt_i->format))
+        if (pa_sink_input_is_passthrough(alt_i))
             return TRUE;
     }
 
@@ -1728,8 +1787,10 @@ void pa_sink_set_volume(
 /* Called from the io thread if sync volume is used, otherwise from the main thread.
  * Only to be called by sink implementor */
 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
+
     pa_sink_assert_ref(s);
     pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
+
     if (s->flags & PA_SINK_SYNC_VOLUME)
         pa_sink_assert_io_context(s);
     else
@@ -2153,7 +2214,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
 
             /* If you change anything here, make sure to change the
              * sink input handling a few lines down at
-             * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
+             * PA_SINK_MESSAGE_START_MOVE, too. */
 
             if (i->detach)
                 i->detach(i);
@@ -2614,6 +2675,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
         return 0;
 
     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
+
     return usec;
 }
 
@@ -2871,8 +2933,8 @@ void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency) {
 /* Called from main context */
 size_t pa_sink_get_max_rewind(pa_sink *s) {
     size_t r;
-    pa_sink_assert_ref(s);
     pa_assert_ctl_context();
+    pa_sink_assert_ref(s);
 
     if (!PA_SINK_IS_LINKED(s->state))
         return s->thread_info.max_rewind;
@@ -2900,6 +2962,7 @@ size_t pa_sink_get_max_request(pa_sink *s) {
 int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
     pa_device_port *port;
     int ret;
+
     pa_sink_assert_ref(s);
     pa_assert_ctl_context();
 
@@ -3295,25 +3358,27 @@ pa_idxset* pa_sink_get_formats(pa_sink *s) {
 /* Checks if the sink can accept this format */
 pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f)
 {
-    pa_idxset *sink_formats = NULL;
-    pa_format_info *f_sink;
-    uint32_t i;
+    pa_idxset *formats = NULL;
     pa_bool_t ret = FALSE;
 
     pa_assert(s);
     pa_assert(f);
 
-    sink_formats = pa_sink_get_formats(s);
+    formats = pa_sink_get_formats(s);
 
-    PA_IDXSET_FOREACH(f_sink, sink_formats, i) {
-        if (pa_format_info_is_compatible(f_sink, f)) {
-            ret = TRUE;
-            break;
+    if (formats) {
+        pa_format_info *finfo_device;
+        uint32_t i;
+
+        PA_IDXSET_FOREACH(finfo_device, formats, i) {
+            if (pa_format_info_is_compatible(finfo_device, f)) {
+                ret = TRUE;
+                break;
+            }
         }
-    }
 
-    if (sink_formats)
-        pa_idxset_free(sink_formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
+        pa_idxset_free(formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
+    }
 
     return ret;
 }