[pulseaudio-discuss] [PATCH v2 1/4] stream-restore: extend ext-stream-restore

Marc-André Lureau marc-andre.lureau at nokia.com
Mon May 11 15:35:42 PDT 2009


This time, the patch introduces new functions using a struct
pa_ext_stream_restore2_info.

pa_ext_stream_restore2_write()
pa_ext_stream_restore2_read()

This will ensure extendability of the stream-restore API without
breakage.

In the pa_ext_stream_restore2_info, a new flag int
volume_is_absolute:1 indicates if the rule volume is absolute.

(The following patches solves the query of extension version with
TEST, by extending context AUTH)
---
 PROTOCOL                       |   11 ++++
 src/map-file                   |    2 +
 src/pulse/context.c            |    2 +
 src/pulse/ext-stream-restore.c |  120 +++++++++++++++++++++++++++++++++-------
 src/pulse/ext-stream-restore.h |   41 +++++++++++++-
 src/pulse/internal.h           |    1 +
 6 files changed, 154 insertions(+), 23 deletions(-)

diff --git a/PROTOCOL b/PROTOCOL
index 88166f1..9955da5 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -181,3 +181,14 @@ new messages:
 
   PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
   PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED
+
+
+### ext-stream-restore v1, implemented by >= 0.9.12
+
+First version supported.
+
+### ext-stream-restore v2, implemented by >= 0.9.16
+
+SUBCOMMAND_WRITE, SUBCOMMAND_READ
+
+  bool volume_is_absolute at the end
diff --git a/src/map-file b/src/map-file
index d0102ae..cc21727 100644
--- a/src/map-file
+++ b/src/map-file
@@ -131,6 +131,8 @@ pa_ext_stream_restore_set_subscribe_cb;
 pa_ext_stream_restore_subscribe;
 pa_ext_stream_restore_test;
 pa_ext_stream_restore_write;
+pa_ext_stream_restore2_read;
+pa_ext_stream_restore2_write;
 pa_frame_size;
 pa_get_binary_name;
 pa_get_fqdn;
diff --git a/src/pulse/context.c b/src/pulse/context.c
index 4aad737..90c15b1 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -168,6 +168,8 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
 
     reset_callbacks(c);
 
+    c->ext_stream_restore.version = 1; /* default version, updated by TEST message */
+
     c->is_local = FALSE;
     c->server_list = NULL;
     c->server = NULL;
diff --git a/src/pulse/ext-stream-restore.c b/src/pulse/ext-stream-restore.c
index 63c911f..a361ff4 100644
--- a/src/pulse/ext-stream-restore.c
+++ b/src/pulse/ext-stream-restore.c
@@ -25,6 +25,7 @@
 
 #include <pulse/context.h>
 #include <pulse/gccmacro.h>
+#include <pulse/xmalloc.h>
 
 #include <pulsecore/macro.h>
 #include <pulsecore/pstream-util.h>
@@ -46,7 +47,6 @@ enum {
 
 static void ext_stream_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_operation *o = userdata;
-    uint32_t version = PA_INVALID_INDEX;
 
     pa_assert(pd);
     pa_assert(o);
@@ -59,7 +59,7 @@ static void ext_stream_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint3
         if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
             goto finish;
 
-    } else if (pa_tagstruct_getu32(t, &version) < 0 ||
+    } else if (pa_tagstruct_getu32(t, &o->context->ext_stream_restore.version) < 0 ||
                !pa_tagstruct_eof(t)) {
 
         pa_context_fail(o->context, PA_ERR_PROTOCOL);
@@ -68,7 +68,7 @@ static void ext_stream_restore_test_cb(pa_pdispatch *pd, uint32_t command, uint3
 
     if (o->callback) {
         pa_ext_stream_restore_test_cb_t cb = (pa_ext_stream_restore_test_cb_t) o->callback;
-        cb(o->context, version, o->userdata);
+        cb(o->context, o->context->ext_stream_restore.version, o->userdata);
     }
 
 finish:
@@ -104,7 +104,41 @@ pa_operation *pa_ext_stream_restore_test(
     return o;
 }
 
-static void ext_stream_restore_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
+struct stream_restore_read_data {
+    pa_ext_stream_restore_read_cb_t cb;
+    void *userdata;
+};
+
+static void ext_stream_restore_read_cb(pa_context *c, const pa_ext_stream_restore2_info *info, int eol, void *userdata) {
+    struct stream_restore_read_data *u;
+    pa_ext_stream_restore_info i;
+
+    pa_assert_se(u = userdata);
+
+    i.name = info->name;
+    i.channel_map = info->channel_map;
+    i.volume = info->volume;
+    i.device = info->device;
+    i.mute = info->mute;
+
+    if (u->cb)
+        u->cb(c, &i, eol, u->userdata);
+
+    if (eol != 0)
+        pa_xfree(u);
+}
+
+pa_operation *pa_ext_stream_restore_read(pa_context *c, pa_ext_stream_restore_read_cb_t cb, void *userdata) {
+    struct stream_restore_read_data *u;
+
+    u = pa_xnew(struct stream_restore_read_data, 1);
+    u->cb = cb;
+    u->userdata = userdata;
+
+    return pa_ext_stream_restore2_read(c, ext_stream_restore_read_cb, u);
+}
+
+static void ext_stream_restore2_read_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
     pa_operation *o = userdata;
     int eol = 1;
 
@@ -123,8 +157,9 @@ static void ext_stream_restore_read_cb(pa_pdispatch *pd, uint32_t command, uint3
     } else {
 
         while (!pa_tagstruct_eof(t)) {
-            pa_ext_stream_restore_info i;
+            pa_ext_stream_restore2_info i;
             pa_bool_t mute = FALSE;
+            pa_bool_t volume_is_absolute = FALSE;
 
             memset(&i, 0, sizeof(i));
 
@@ -138,28 +173,36 @@ static void ext_stream_restore_read_cb(pa_pdispatch *pd, uint32_t command, uint3
                 goto finish;
             }
 
-            i.mute = (int) mute;
+            if (o->context->ext_stream_restore.version >= 2 &&
+                pa_tagstruct_get_boolean(t, &volume_is_absolute) < 0) {
+
+                pa_context_fail(o->context, PA_ERR_PROTOCOL);
+                goto finish;
+            }
+
+	    i.mute = (int) mute;
+	    i.volume_is_absolute = (int) volume_is_absolute;
 
             if (o->callback) {
-                pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
+                pa_ext_stream_restore2_read_cb_t cb = (pa_ext_stream_restore2_read_cb_t) o->callback;
                 cb(o->context, &i, 0, o->userdata);
             }
         }
     }
 
     if (o->callback) {
-        pa_ext_stream_restore_read_cb_t cb = (pa_ext_stream_restore_read_cb_t) o->callback;
+        pa_ext_stream_restore2_read_cb_t cb = (pa_ext_stream_restore2_read_cb_t) o->callback;
         cb(o->context, NULL, eol, o->userdata);
     }
 
-finish:
+ finish:
     pa_operation_done(o);
     pa_operation_unref(o);
 }
 
-pa_operation *pa_ext_stream_restore_read(
+pa_operation *pa_ext_stream_restore2_read(
         pa_context *c,
-        pa_ext_stream_restore_read_cb_t cb,
+        pa_ext_stream_restore2_read_cb_t cb,
         void *userdata) {
 
     uint32_t tag;
@@ -180,7 +223,7 @@ pa_operation *pa_ext_stream_restore_read(
     pa_tagstruct_puts(t, "module-stream-restore");
     pa_tagstruct_putu32(t, SUBCOMMAND_READ);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_stream_restore_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, ext_stream_restore2_read_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
 
     return o;
 }
@@ -193,10 +236,43 @@ pa_operation *pa_ext_stream_restore_write(
         int apply_immediately,
         pa_context_success_cb_t cb,
         void *userdata) {
+    pa_ext_stream_restore2_info **infos;
+    unsigned i;
+    pa_operation *o;
+
+    infos = pa_xnew(pa_ext_stream_restore2_info *, n);
+    for (i = 0; i < n; ++i) {
+        infos[i] = pa_xnew0(pa_ext_stream_restore2_info, 1);
+        infos[i]->name = data[i].name;
+        infos[i]->channel_map = data[i].channel_map;
+        infos[i]->volume = data[i].volume;
+        infos[i]->device = data[i].device;
+        infos[i]->mute = data[i].mute;
+    }
+
+    /* this needs a cast: see http://stackoverflow.com/questions/847772/dynamic-array-of-structs-and-function-call-fconst-structtype-const-data */
+    o = pa_ext_stream_restore2_write(c, mode, (const pa_ext_stream_restore2_info * const *)infos, n, apply_immediately, cb, userdata);
+
+    for (i = 0; i < n; ++i)
+        pa_xfree(infos[i]);
+    pa_xfree(infos);
+
+    return o;
+}
+
+pa_operation *pa_ext_stream_restore2_write(
+        pa_context *c,
+        pa_update_mode_t mode,
+        const pa_ext_stream_restore2_info *const data[],
+        unsigned n,
+        int apply_immediately,
+        pa_context_success_cb_t cb,
+        void *userdata) {
 
     uint32_t tag;
     pa_operation *o = NULL;
     pa_tagstruct *t = NULL;
+    unsigned i;
 
     pa_assert(c);
     pa_assert(PA_REFCNT_VALUE(c) >= 1);
@@ -217,20 +293,22 @@ pa_operation *pa_ext_stream_restore_write(
     pa_tagstruct_putu32(t, mode);
     pa_tagstruct_put_boolean(t, apply_immediately);
 
-    for (; n > 0; n--, data++) {
-        if (!data->name || !*data->name)
+    for (i = 0; i < n; ++i) {
+        if (!data[i]->name || !*data[i]->name)
             goto fail;
 
-        pa_tagstruct_puts(t, data->name);
+        pa_tagstruct_puts(t, data[i]->name);
 
-        if (data->volume.channels > 0 &&
-            !pa_cvolume_compatible_with_channel_map(&data->volume, &data->channel_map))
+        if (data[i]->volume.channels > 0 &&
+            !pa_cvolume_compatible_with_channel_map(&data[i]->volume, &data[i]->channel_map))
             goto fail;
 
-        pa_tagstruct_put_channel_map(t, &data->channel_map);
-        pa_tagstruct_put_cvolume(t, &data->volume);
-        pa_tagstruct_puts(t, data->device);
-        pa_tagstruct_put_boolean(t, data->mute);
+        pa_tagstruct_put_channel_map(t, &data[i]->channel_map);
+        pa_tagstruct_put_cvolume(t, &data[i]->volume);
+        pa_tagstruct_puts(t, data[i]->device);
+        pa_tagstruct_put_boolean(t, data[i]->mute);
+        if (c->ext_stream_restore.version >= 2)
+            pa_tagstruct_put_boolean(t, data[i]->volume_is_absolute);
     }
 
     pa_pstream_send_tagstruct(c->pstream, t);
diff --git a/src/pulse/ext-stream-restore.h b/src/pulse/ext-stream-restore.h
index 0b5d8eb..2efcf0c 100644
--- a/src/pulse/ext-stream-restore.h
+++ b/src/pulse/ext-stream-restore.h
@@ -42,6 +42,20 @@ typedef struct pa_ext_stream_restore_info {
     int mute;                    /**< The boolean mute state of the stream when it was last seen, if applicable and saved */
 } pa_ext_stream_restore_info;
 
+/** Stores information about one entry in the stream database that is
+ * maintained by module-stream-restore v2. This structure deprecate
+ * and replace the pa_ext_stream_restore_info which was not
+ * extensible. This new structure ca be extended without breaking
+ * API/ABI.  \since 0.9.16 */
+typedef struct pa_ext_stream_restore2_info {
+    const char *name;            /**< Identifier string of the stream. A string like "sink-input-by-role:" or similar followed by some arbitrary property value. */
+    pa_channel_map channel_map;  /**< The channel map for the volume field, if applicable */
+    pa_cvolume volume;           /**< The volume of the stream when it was seen last, if applicable and saved */
+    const char *device;          /**< The sink/source of the stream when it was last seen, if applicable and saved */
+    int mute:1;                  /**< The boolean mute state of the stream when it was last seen, if applicable and saved */
+    int volume_is_absolute:1;    /**< True if the volume is absolute, if applicable and saved */
+} pa_ext_stream_restore2_info;
+
 /** Callback prototype for pa_ext_stream_restore_test(). \since 0.9.12 */
 typedef void (*pa_ext_stream_restore_test_cb_t)(
         pa_context *c,
@@ -54,19 +68,32 @@ pa_operation *pa_ext_stream_restore_test(
         pa_ext_stream_restore_test_cb_t cb,
         void *userdata);
 
-/** Callback prototype for pa_ext_stream_restore_read(). \since 0.9.12 */
+/** Callback prototype for pa_ext_stream_restore_read(). \since 0.9.12 \deprecated Use pa_ext_stream_restore2_read instead */
 typedef void (*pa_ext_stream_restore_read_cb_t)(
         pa_context *c,
         const pa_ext_stream_restore_info *info,
         int eol,
         void *userdata);
 
-/** Read all entries from the stream database. \since 0.9.12 */
+/** Read all entries from the stream database. \since 0.9.12 \deprecated Use pa_ext_stream_restore2_read instead */
 pa_operation *pa_ext_stream_restore_read(
         pa_context *c,
         pa_ext_stream_restore_read_cb_t cb,
         void *userdata);
 
+/** Callback prototype for pa_ext_stream_restore2_read(). \since 0.9.16 */
+typedef void (*pa_ext_stream_restore2_read_cb_t)(
+        pa_context *c,
+        const pa_ext_stream_restore2_info *info,
+        int eol,
+        void *userdata);
+
+/** Read all entries from the stream database. \since 0.9.16 */
+pa_operation *pa_ext_stream_restore2_read(
+        pa_context *c,
+        pa_ext_stream_restore2_read_cb_t cb,
+        void *userdata);
+
 /** Store entries in the stream database. \since 0.9.12 */
 pa_operation *pa_ext_stream_restore_write(
         pa_context *c,
@@ -77,6 +104,16 @@ pa_operation *pa_ext_stream_restore_write(
         pa_context_success_cb_t cb,
         void *userdata);
 
+/** Store entries in the stream database. \since 0.9.16 */
+pa_operation *pa_ext_stream_restore2_write(
+        pa_context *c,
+        pa_update_mode_t mode,
+        const pa_ext_stream_restore2_info *const data[],
+        unsigned n,
+        int apply_immediately,
+        pa_context_success_cb_t cb,
+        void *userdata);
+
 /** Delete entries from the stream database. \since 0.9.12 */
 pa_operation *pa_ext_stream_restore_delete(
         pa_context *c,
diff --git a/src/pulse/internal.h b/src/pulse/internal.h
index 28a989b..3c58c49 100644
--- a/src/pulse/internal.h
+++ b/src/pulse/internal.h
@@ -103,6 +103,7 @@ struct pa_context {
     struct {
         pa_ext_stream_restore_subscribe_cb_t callback;
         void *userdata;
+        uint32_t version;
     } ext_stream_restore;
 };
 
-- 
1.6.2.4




More information about the pulseaudio-discuss mailing list