[pulseaudio-commits] 9 commits - man/pactl.1.xml.in src/modules src/pulse src/pulsecore src/utils

Arun Raghavan arun at kemper.freedesktop.org
Mon Aug 15 00:38:49 PDT 2011


 man/pactl.1.xml.in                  |    8 +++
 src/modules/alsa/alsa-sink.c        |   69 +++++++++++++++++++++++++++++++++
 src/modules/module-device-restore.c |   57 ++++++++++++++++++++++-----
 src/pulse/format.c                  |   75 ++++++++++++++++++++++++++++++------
 src/pulse/format.h                  |    7 +++
 src/pulsecore/sink.c                |   16 +++++++
 src/pulsecore/sink.h                |   11 ++++-
 src/utils/pactl.c                   |   66 ++++++++++++++++++++++++++++++-
 8 files changed, 282 insertions(+), 27 deletions(-)

New commits:
commit 50b420aebd876557a64f9015e1197e7d12201f5f
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Aug 15 12:07:02 2011 +0530

    device-restore: Log invalid sink index while setting formats
    
    This makes it easier to catch errors when using 'pactl set-sink-formats'

diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 671ffd4..6c5c27e 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -826,8 +826,10 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
             }
 
             /* Now find our sink */
-            if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
+            if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
+                pa_log("Could not find sink #%d", sink_index);
                 goto fail;
+            }
 
             /* Read or create an entry */
             name = pa_sprintf_malloc("sink:%s", sink->name);

commit b9d517cd515a6d53de592b7c33e47caaff738b6c
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Aug 15 11:23:59 2011 +0530

    sink: Fix lazy commenting

diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 0bd5e81..3f89784 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -217,17 +217,17 @@ struct pa_sink {
 
     /* Called whenever the port shall be changed. Called from main
      * thread. */
-    int (*set_port)(pa_sink *s, pa_device_port *port); /* ditto */
+    int (*set_port)(pa_sink *s, pa_device_port *port); /* may be NULL */
 
     /* Called to get the list of formats supported by the sink, sorted
      * in descending order of preference. */
-    pa_idxset* (*get_formats)(pa_sink *s); /* ditto */
+    pa_idxset* (*get_formats)(pa_sink *s); /* may be NULL */
 
     /* Called to set the list of formats supported by the sink. Can be
      * NULL if the sink does not support this. Returns TRUE on success,
      * FALSE otherwise (for example when an unsupportable format is
      * set). Makes a copy of the formats passed in. */
-    pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* ditto */
+    pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* may be NULL */
 
     /* Contains copies of the above data so that the real-time worker
      * thread can work without access locking */

commit 0f3be7b72b2a1ba72a209628e19789dcf8132f11
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Aug 15 09:47:09 2011 +0530

    pactl: Add a set-sink-formats command
    
    This uses the module-device-restore protocol extension to save formats
    on sinks that support it.

diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in
index 3a70fb6..f0060fb 100644
--- a/man/pactl.1.xml.in
+++ b/man/pactl.1.xml.in
@@ -218,6 +218,14 @@ USA.
     </option>
 
     <option>
+      <p><opt>set-sink-formats</opt> <arg>SINK</arg> <arg>FORMATS</arg></p>
+      <optdesc><p>Set the supported formats of the specified sink (identified by its numerical index) if supported by the sink.
+      <arg>FORMATS</arg> is specified as a semi-colon (;) separated list of formats in the form
+      'encoding[, key1=value1, key2=value2, ...]' (for example, AC3 at 32000, 44100 and 48000 Hz would be specified as
+      'ac3-iec61937, format.rate = "[ 32000, 44100, 48000 ]"').
+      </p></optdesc> </option>
+
+    <option>
       <p><opt>subscribe</opt></p>
       <optdesc><p>Subscribe to events, pactl does not exit by itself, but keeps waiting for new events.</p></optdesc>
     </option>
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 2c5be93..947c6e9 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -36,6 +36,7 @@
 #include <sndfile.h>
 
 #include <pulse/pulseaudio.h>
+#include <pulse/ext-device-restore.h>
 
 #include <pulsecore/i18n.h>
 #include <pulsecore/macro.h>
@@ -55,11 +56,13 @@ static char
     *module_args = NULL,
     *card_name = NULL,
     *profile_name = NULL,
-    *port_name = NULL;
+    *port_name = NULL,
+    *formats = NULL;
 
 static uint32_t
     sink_input_idx = PA_INVALID_INDEX,
-    source_output_idx = PA_INVALID_INDEX;
+    source_output_idx = PA_INVALID_INDEX,
+    sink_idx = PA_INVALID_INDEX;
 
 static pa_bool_t short_list_format = FALSE;
 static uint32_t module_index;
@@ -111,6 +114,7 @@ static enum {
     SET_SINK_MUTE,
     SET_SOURCE_MUTE,
     SET_SINK_INPUT_MUTE,
+    SET_SINK_FORMATS,
     SUBSCRIBE
 } action = NONE;
 
@@ -882,6 +886,44 @@ static void get_source_output_volume_callback(pa_context *c, const pa_source_out
     pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
 }
 
+/* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */
+#define MAX_FORMATS 256
+
+static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
+    pa_format_info *f_arr[MAX_FORMATS];
+    char *format = NULL;
+    const char *state = NULL;
+    int i = 0;
+
+    while ((format = pa_split(str, ";", &state))) {
+        pa_format_info *f = pa_format_info_from_string(pa_strip(format));
+
+        if (!f) {
+            pa_log(_("Failed to set format: invalid format string %s"), format);
+            goto error;
+        }
+
+        f_arr[i++] = f;
+        pa_xfree(format);
+    }
+
+    pa_operation_unref(pa_ext_device_restore_save_sink_formats(c, sink, i, f_arr, simple_callback, NULL));
+
+done:
+    if (format)
+        pa_xfree(format);
+    while(i--)
+        pa_format_info_free(f_arr[i]);
+
+    return;
+
+error:
+    while(i--)
+        pa_format_info_free(f_arr[i]);
+    quit(1);
+    goto done;
+}
+
 static void stream_state_callback(pa_stream *s, void *userdata) {
     pa_assert(s);
 
@@ -1157,6 +1199,10 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     }
                     break;
 
+                case SET_SINK_FORMATS:
+                    set_sink_formats(c, sink_idx, formats);
+                    break;
+
                 case SUBSCRIBE:
                     pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
 
@@ -1270,6 +1316,7 @@ static void help(const char *argv0) {
     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME"));
     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0"));
     printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-input-mute", _("#N 1|0"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS"));
     printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
 
     printf(_("\n"
@@ -1662,7 +1709,19 @@ int main(int argc, char *argv[]) {
 
             action = SUBSCRIBE;
 
-        else if (pa_streq(argv[optind], "help")) {
+        else if (pa_streq(argv[optind], "set-sink-formats")) {
+            int32_t tmp;
+
+            if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) {
+                pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats"));
+                goto quit;
+            }
+
+            sink_idx = tmp;
+            action = SET_SINK_FORMATS;
+            formats = pa_xstrdup(argv[optind+2]);
+
+        } else if (pa_streq(argv[optind], "help")) {
             help(bn);
             ret = 0;
             goto quit;
@@ -1723,6 +1782,7 @@ quit:
     pa_xfree(card_name);
     pa_xfree(profile_name);
     pa_xfree(port_name);
+    pa_xfree(formats);
 
     if (sndfile)
         sf_close(sndfile);

commit 8bffbcde1b9ac41703be9c242f4f9f172d5649bb
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 21:55:48 2011 +0530

    format: Add string to pa_format_info conversion function
    
    This will help accept string formats from the command like (so we can
    set formats using pactl).

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 112b103..f4eed83 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -41,20 +41,30 @@
 
 static int pa_format_info_prop_compatible(const char *one, const char *two);
 
-const char *pa_encoding_to_string(pa_encoding_t e) {
-    static const char* const table[]= {
-        [PA_ENCODING_PCM] = "pcm",
-        [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
-        [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
-        [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
-        [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
-        [PA_ENCODING_ANY] = "any",
-    };
+static const char* const _encoding_str_table[]= {
+    [PA_ENCODING_PCM] = "pcm",
+    [PA_ENCODING_AC3_IEC61937] = "ac3-iec61937",
+    [PA_ENCODING_EAC3_IEC61937] = "eac3-iec61937",
+    [PA_ENCODING_MPEG_IEC61937] = "mpeg-iec61937",
+    [PA_ENCODING_DTS_IEC61937] = "dts-iec61937",
+    [PA_ENCODING_ANY] = "any",
+};
 
+const char *pa_encoding_to_string(pa_encoding_t e) {
     if (e < 0 || e >= PA_ENCODING_MAX)
         return NULL;
 
-    return table[e];
+    return _encoding_str_table[e];
+}
+
+pa_encoding_t pa_encoding_from_string(const char *encoding) {
+    pa_encoding_t e;
+
+    for (e = PA_ENCODING_ANY; e < PA_ENCODING_MAX; e++)
+        if (pa_streq(_encoding_str_table[e], encoding))
+            return e;
+
+    return PA_ENCODING_INVALID;
 }
 
 pa_format_info* pa_format_info_new(void) {
@@ -125,6 +135,44 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
     return s;
 }
 
+pa_format_info* pa_format_info_from_string(const char *str) {
+    pa_format_info *f = pa_format_info_new();
+    char *encoding = NULL, *properties = NULL;
+    size_t pos;
+
+    pos = strcspn(str, ",");
+
+    encoding = pa_xstrndup(str, pos);
+    f->encoding = pa_encoding_from_string(pa_strip(encoding));
+    if (f->encoding == PA_ENCODING_INVALID)
+        goto error;
+
+    if (pos != strlen(str)) {
+        pa_proplist *plist;
+
+        properties = pa_xstrdup(&str[pos+1]);
+        plist = pa_proplist_from_string(properties);
+
+        if (!plist)
+            goto error;
+
+        pa_proplist_free(f->plist);
+        f->plist = plist;
+    }
+
+out:
+    if (encoding)
+        pa_xfree(encoding);
+    if (properties)
+        pa_xfree(properties);
+    return f;
+
+error:
+    pa_format_info_free(f);
+    f = NULL;
+    goto out;
+}
+
 int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second) {
     const char *key;
     void *state = NULL;
diff --git a/src/pulse/format.h b/src/pulse/format.h
index 821149c..b8b829e 100644
--- a/src/pulse/format.h
+++ b/src/pulse/format.h
@@ -62,6 +62,9 @@ typedef enum pa_encoding {
 /** Returns a printable string representing the given encoding type. \since 1.0 */
 const char *pa_encoding_to_string(pa_encoding_t e) PA_GCC_CONST;
 
+/** Converts a string of the form returned by \a pa_encoding_to_string() back to a \a pa_encoding_t. \since 1.0 */
+pa_encoding_t pa_encoding_from_string(const char *encoding);
+
 /**< Represents the format of data provided in a stream or processed by a sink. \since 1.0 */
 typedef struct pa_format_info {
     pa_encoding_t encoding;
@@ -105,6 +108,10 @@ int pa_format_info_is_compatible(pa_format_info *first, pa_format_info *second);
 /** Return a human-readable string representing the given format. \since 1.0 */
 char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f);
 
+/** Parse a human-readable string of the form generated by
+ * \a pa_format_info_snprint() into a pa_format_info structure. \since 1.0 */
+pa_format_info* pa_format_info_from_string(const char *str);
+
 /** Sets an integer property on the given format info */
 void pa_format_info_set_prop_int(pa_format_info *f, const char *key, int value);
 /** Sets a property with a list of integer values on the given format info */

commit 348c51bfcdfa58bc99e44329b3aa1067adc0e920
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 21:04:38 2011 +0530

    format: Make pa_format_info_snprint() more parseable
    
    Removes the comma as the proplist separator since that makes
    pa_proplist_from_string() break and prints only the encoding if there
    are no properties (instead of "<encoding>, (no properties)").

diff --git a/src/pulse/format.c b/src/pulse/format.c
index 81c329f..112b103 100644
--- a/src/pulse/format.c
+++ b/src/pulse/format.c
@@ -114,8 +114,11 @@ char *pa_format_info_snprint(char *s, size_t l, const pa_format_info *f) {
     if (!pa_format_info_valid(f))
         pa_snprintf(s, l, _("(invalid)"));
     else {
-        tmp = pa_proplist_to_string_sep(f->plist, ", ");
-        pa_snprintf(s, l, _("%s, %s"), pa_encoding_to_string(f->encoding), tmp[0] ? tmp : _("(no properties)"));
+        tmp = pa_proplist_to_string_sep(f->plist, "  ");
+        if (tmp[0])
+            pa_snprintf(s, l, "%s, %s", pa_encoding_to_string(f->encoding), tmp);
+        else
+            pa_snprintf(s, l, "%s", pa_encoding_to_string(f->encoding));
         pa_xfree(tmp);
     }
 

commit 248394c8bfdaea5b57e2e68df89bebb498b22601
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 20:27:34 2011 +0530

    device-restore: Set sink format when possible
    
    This implements the actual setting of sink formats when a new sink is
    added or when the set of available formats changes.

diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 9441813..671ffd4 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -63,7 +63,8 @@ PA_MODULE_LOAD_ONCE(TRUE);
 PA_MODULE_USAGE(
         "restore_port=<Save/restore port?> "
         "restore_volume=<Save/restore volumes?> "
-        "restore_muted=<Save/restore muted states?>");
+        "restore_muted=<Save/restore muted states?> "
+        "restore_formats=<Save/restore saved formats?>");
 
 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
 
@@ -71,6 +72,7 @@ static const char* const valid_modargs[] = {
     "restore_volume",
     "restore_muted",
     "restore_port",
+    "restore_formats",
     NULL
 };
 
@@ -81,6 +83,7 @@ struct userdata {
     pa_hook_slot
         *sink_new_hook_slot,
         *sink_fixate_hook_slot,
+        *sink_put_hook_slot,
         *source_new_hook_slot,
         *source_fixate_hook_slot,
         *connection_unlink_hook_slot;
@@ -93,6 +96,7 @@ struct userdata {
     pa_bool_t restore_volume;
     pa_bool_t restore_muted;
     pa_bool_t restore_port;
+    pa_bool_t restore_formats;
 };
 
 /* Protocol extention commands */
@@ -590,6 +594,30 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
+    char *name;
+    struct entry *e;
+
+    pa_assert(c);
+    pa_assert(sink);
+    pa_assert(u);
+    pa_assert(u->restore_formats);
+
+    name = pa_sprintf_malloc("sink:%s", sink->name);
+
+    if ((e = entry_read(u, name))) {
+
+        if (!pa_sink_set_formats(sink, e->formats))
+            pa_log_debug("Could not set format on sink %s", sink->name);
+
+        entry_free(e);
+    }
+
+    pa_xfree(name);
+
+    return PA_HOOK_OK;
+}
+
 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
     char *name;
     struct entry *e;
@@ -828,7 +856,7 @@ static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connectio
                 goto fail;
             }
 
-            if (entry_write(u, name, e))
+            if (pa_sink_set_formats(sink, e->formats) && entry_write(u, name, e))
                 trigger_save(u, sink_index);
             else
                 pa_log_warn("Could not save format info for sink %s", sink->name);
@@ -870,7 +898,7 @@ int pa__init(pa_module*m) {
     pa_sink *sink;
     pa_source *source;
     uint32_t idx;
-    pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE;
+    pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE, restore_formats = TRUE;
 
     pa_assert(m);
 
@@ -881,12 +909,13 @@ int pa__init(pa_module*m) {
 
     if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
         pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
-        pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0) {
-        pa_log("restore_port=, restore_volume= and restore_muted= expect boolean arguments");
+        pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 ||
+        pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) {
+        pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments");
         goto fail;
     }
 
-    if (!restore_muted && !restore_volume && !restore_port)
+    if (!restore_muted && !restore_volume && !restore_port && !restore_formats)
         pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
 
     m->userdata = u = pa_xnew0(struct userdata, 1);
@@ -895,6 +924,7 @@ int pa__init(pa_module*m) {
     u->restore_volume = restore_volume;
     u->restore_muted = restore_muted;
     u->restore_port = restore_port;
+    u->restore_formats = restore_formats;
 
     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
@@ -915,6 +945,9 @@ int pa__init(pa_module*m) {
         u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u);
     }
 
+    if (restore_formats)
+        u->sink_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_put_hook_callback, u);
+
     if (!(fname = pa_state_path("device-volumes", TRUE)))
         goto fail;
 
@@ -964,6 +997,8 @@ void pa__done(pa_module*m) {
         pa_hook_slot_free(u->sink_new_hook_slot);
     if (u->source_new_hook_slot)
         pa_hook_slot_free(u->source_new_hook_slot);
+    if (u->sink_put_hook_slot)
+        pa_hook_slot_free(u->sink_put_hook_slot);
 
     if (u->connection_unlink_hook_slot)
         pa_hook_slot_free(u->connection_unlink_hook_slot);

commit ba163b8b23bcd72c35b028eb0b43c31a6ae1724d
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 19:33:41 2011 +0530

    device-restore: Make bools not be bit fields
    
    This makes the pa_bool_t members of userdata not be a single bit field
    since pa_bool_t can be an int, potentially causing signedness issues in
    comparisons.

diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 75b1e40..9441813 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -90,9 +90,9 @@ struct userdata {
     pa_native_protocol *protocol;
     pa_idxset *subscribed;
 
-    pa_bool_t restore_volume:1;
-    pa_bool_t restore_muted:1;
-    pa_bool_t restore_port:1;
+    pa_bool_t restore_volume;
+    pa_bool_t restore_muted;
+    pa_bool_t restore_port;
 };
 
 /* Protocol extention commands */

commit 51fcee89029063998913d1ccab7df54134d72b8d
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 16:36:00 2011 +0530

    alsa: Implement get/set_formats()
    
    This implements the sink get_formats() and set_formats() API in
    alsa-sink. Modules can use this to allow users to specify what formats
    their receivers support.

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index c4aa75b..44331a3 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -36,6 +36,7 @@
 #include <pulse/timeval.h>
 #include <pulse/volume.h>
 #include <pulse/xmalloc.h>
+#include <pulse/internal.h>
 
 #include <pulsecore/core.h>
 #include <pulsecore/i18n.h>
@@ -144,6 +145,8 @@ struct userdata {
     pa_usec_t smoother_interval;
     pa_usec_t last_smoother_update;
 
+    pa_idxset *formats;
+
     pa_reserve_wrapper *reserve;
     pa_hook_slot *reserve_slot;
     pa_reserve_monitor_wrapper *monitor;
@@ -152,6 +155,15 @@ struct userdata {
 
 static void userdata_free(struct userdata *u);
 
+/* FIXME: Is there a better way to do this than device names? */
+static pa_bool_t is_iec958(struct userdata *u) {
+    return (strncmp("iec958", u->device_name, 6) == 0);
+}
+
+static pa_bool_t is_hdmi(struct userdata *u) {
+    return (strncmp("hdmi", u->device_name, 4) == 0);
+}
+
 static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) {
     pa_assert(r);
     pa_assert(u);
@@ -1475,6 +1487,45 @@ static void sink_update_requested_latency_cb(pa_sink *s) {
     }
 }
 
+static pa_idxset* sink_get_formats(pa_sink *s) {
+    struct userdata *u = s->userdata;
+    pa_idxset *ret = pa_idxset_new(NULL, NULL);
+    pa_format_info *f;
+    uint32_t idx;
+
+    pa_assert(u);
+
+    PA_IDXSET_FOREACH(f, u->formats, idx) {
+        pa_idxset_put(ret, pa_format_info_copy(f), NULL);
+    }
+
+    return ret;
+}
+
+static pa_bool_t sink_set_formats(pa_sink *s, pa_idxset *formats) {
+    struct userdata *u = s->userdata;
+    pa_format_info *f;
+    uint32_t idx;
+
+    pa_assert(u);
+
+    /* FIXME: also validate sample rates against what the device supports */
+    PA_IDXSET_FOREACH(f, formats, idx) {
+        if (is_iec958(u) && f->encoding == PA_ENCODING_EAC3_IEC61937)
+            /* EAC3 cannot be sent over over S/PDIF */
+            return FALSE;
+    }
+
+    pa_idxset_free(u->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
+    u->formats = pa_idxset_new(NULL, NULL);
+
+    PA_IDXSET_FOREACH(f, formats, idx) {
+        pa_idxset_put(u->formats, pa_format_info_copy(f), NULL);
+    }
+
+    return TRUE;
+}
+
 static int process_rewind(struct userdata *u) {
     snd_pcm_sframes_t unused;
     size_t rewind_nbytes, unused_nbytes, limit_nbytes;
@@ -2182,6 +2233,21 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     if ((data.volume_is_set || data.muted_is_set) && u->sink->write_volume)
         u->sink->write_volume(u->sink);
 
+    if (is_iec958(u) || is_hdmi(u)) {
+        /* For S/PDIF and HDMI, allow getting/setting custom formats */
+        pa_format_info *format;
+
+        /* To start with, we only support PCM formats. Other formats may be added
+         * with pa_sink_set_formats().*/
+        format = pa_format_info_new();
+        format->encoding = PA_ENCODING_PCM;
+        u->formats = pa_idxset_new(NULL, NULL);
+        pa_idxset_put(u->formats, format, NULL);
+
+        u->sink->get_formats = sink_get_formats;
+        u->sink->set_formats = sink_set_formats;
+    }
+
     pa_sink_put(u->sink);
 
     if (profile_set)
@@ -2247,6 +2313,9 @@ static void userdata_free(struct userdata *u) {
     if (u->smoother)
         pa_smoother_free(u->smoother);
 
+    if (u->formats)
+        pa_idxset_free(u->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
+
     reserve_done(u);
     monitor_done(u);
 

commit 485d4dd54260b680b0e5d0af35ad380280a4c826
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Aug 12 16:34:28 2011 +0530

    sink: Add a set_formats() API
    
    This adds API to let external sources specify what formats a sink
    supports. Sinks must opt-in to allow this, and can perform some
    validation if required.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 42a8eb3..6277698 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -180,6 +180,7 @@ static void reset_callbacks(pa_sink *s) {
     s->update_requested_latency = NULL;
     s->set_port = NULL;
     s->get_formats = NULL;
+    s->set_formats = NULL;
 }
 
 /* Called from main context */
@@ -3429,6 +3430,21 @@ pa_idxset* pa_sink_get_formats(pa_sink *s) {
 }
 
 /* Called from the main thread */
+/* Allows an external source to set what formats a sink supports if the sink
+ * permits this. The function makes a copy of the formats on success. */
+pa_bool_t pa_sink_set_formats(pa_sink *s, pa_idxset *formats) {
+    pa_assert(s);
+    pa_assert(formats);
+
+    if (s->set_formats)
+        /* Sink supports setting formats -- let's give it a shot */
+        return s->set_formats(s, formats);
+    else
+        /* Sink doesn't support setting this -- bail out */
+        return FALSE;
+}
+
+/* Called from the main thread */
 /* Checks if the sink can accept this format */
 pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f)
 {
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 8aa04b8..0bd5e81 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -223,6 +223,12 @@ struct pa_sink {
      * in descending order of preference. */
     pa_idxset* (*get_formats)(pa_sink *s); /* ditto */
 
+    /* Called to set the list of formats supported by the sink. Can be
+     * NULL if the sink does not support this. Returns TRUE on success,
+     * FALSE otherwise (for example when an unsupportable format is
+     * set). Makes a copy of the formats passed in. */
+    pa_bool_t (*set_formats)(pa_sink *s, pa_idxset *formats); /* ditto */
+
     /* Contains copies of the above data so that the real-time worker
      * thread can work without access locking */
     struct {
@@ -434,6 +440,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save);
 void pa_sink_move_all_fail(pa_queue *q);
 
 pa_idxset* pa_sink_get_formats(pa_sink *s);
+pa_bool_t pa_sink_set_formats(pa_sink *s, pa_idxset *formats);
 pa_bool_t pa_sink_check_format(pa_sink *s, pa_format_info *f);
 pa_idxset* pa_sink_check_formats(pa_sink *s, pa_idxset *in_formats);
 



More information about the pulseaudio-commits mailing list