diff --git a/src/modules/module-protocol-pulse/ext-stream-restore.c b/src/modules/module-protocol-pulse/ext-stream-restore.c new file mode 100644 index 000000000..cb7108370 --- /dev/null +++ b/src/modules/module-protocol-pulse/ext-stream-restore.c @@ -0,0 +1,91 @@ +/* PipeWire + * + * Copyright © 2020 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#define EXT_STREAM_RESTORE_VERSION 1 + +static const struct extension_sub ext_stream_restore[]; + +static int do_extension_stream_restore_test(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + struct message *reply; + + reply = reply_new(client, tag); + message_put(reply, + TAG_U32, EXT_STREAM_RESTORE_VERSION, + TAG_INVALID); + return send_message(client, reply); +} + +static int do_extension_stream_restore_read(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + struct message *reply; + reply = reply_new(client, tag); + return send_message(client, reply); +} + +static int do_extension_stream_restore_write(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + return reply_simple_ack(client, tag); +} + +static int do_extension_stream_restore_delete(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + return reply_simple_ack(client, tag); +} + +static int do_extension_stream_restore_subscribe(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + return reply_simple_ack(client, tag); +} + +static const struct extension_sub ext_stream_restore[] = { + { "TEST", 0, do_extension_stream_restore_test, }, + { "READ", 1, do_extension_stream_restore_read, }, + { "WRITE", 2, do_extension_stream_restore_write, }, + { "DELETE", 3, do_extension_stream_restore_delete, }, + { "SUBSCRIBE", 4, do_extension_stream_restore_subscribe, }, + { "EVENT", 5, }, +}; + +static int do_extension_stream_restore(struct client *client, uint32_t tag, struct message *m) +{ + struct impl *impl = client->impl; + uint32_t command; + int res; + + if ((res = message_get(m, + TAG_U32, &command, + TAG_INVALID)) < 0) + return -EPROTO; + + if (command >= SPA_N_ELEMENTS(ext_stream_restore)) + return -ENOTSUP; + if (ext_stream_restore[command].process == NULL) + return -EPROTO; + + pw_log_info(NAME" %p: [EXT_STREAM_RESTORE_%s] %s tag:%u", impl, client->name, + ext_stream_restore[command].name, tag); + + return ext_stream_restore[command].process(client, command, tag, m); +} diff --git a/src/modules/module-protocol-pulse/extension.c b/src/modules/module-protocol-pulse/extension.c new file mode 100644 index 000000000..56987e39a --- /dev/null +++ b/src/modules/module-protocol-pulse/extension.c @@ -0,0 +1,64 @@ +/* PipeWire + * + * Copyright © 2020 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +struct extension_sub { + const char *name; + uint32_t command; + int (*process)(struct client *client, uint32_t command, uint32_t tag, struct message *m); +}; + +struct extension { + const char *name; + uint32_t idx; + int (*process)(struct client *client, uint32_t tag, struct message *m); +}; + +#include "ext-stream-restore.c" + +static int do_extension_device_restore(struct client *client, uint32_t tag, struct message *m) +{ + return -ENOTSUP; +} + +static int do_extension_device_manager(struct client *client, uint32_t tag, struct message *m) +{ + return -ENOTSUP; +} + +struct extension extensions[] = { + { "module-stream-restore", 0 | EXTENSION_FLAG, do_extension_stream_restore, }, + { "module-device-restore", 1 | EXTENSION_FLAG, do_extension_device_restore, }, + { "module-device-manager", 2 | EXTENSION_FLAG, do_extension_device_manager, }, +}; + +static struct extension *find_extension(uint32_t idx, const char *name) +{ + uint32_t i; + for (i = 0; i < SPA_N_ELEMENTS(extensions); i++) { + if (idx == extensions[i].idx || + (name && strcmp(name, extensions[i].name) == 0)) + return &extensions[i]; + } + return 0; +} diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 0e3036739..e0926f9ae 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -420,6 +420,8 @@ static int reply_error(struct client *client, uint32_t command, uint32_t tag, in return send_message(client, reply); } +#include "extension.c" + static int send_underflow(struct stream *stream, int64_t offset) { struct client *client = stream->client; @@ -4015,6 +4017,34 @@ static int do_update_stream_sample_rate(struct client *client, uint32_t command, return reply_simple_ack(client, tag); } +static int do_extension(struct client *client, uint32_t command, uint32_t tag, struct message *m) +{ + struct impl *impl = client->impl; + uint32_t idx; + const char *name; + struct extension *ext; + int res; + + if ((res = message_get(m, + TAG_U32, &idx, + TAG_STRING, &name, + TAG_INVALID)) < 0) + return -EPROTO; + + pw_log_info(NAME" %p: [%s] %s tag:%u id:%u name:%s", impl, client->name, + commands[command].name, tag, idx, name); + + if ((idx == SPA_ID_INVALID && name == NULL) || + (idx != SPA_ID_INVALID && name != NULL)) + return -EINVAL; + + ext = find_extension(idx, name); + if (ext == NULL) + return -ENOENT; + + return ext->process(client, tag, m); +} + static int do_set_profile(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct impl *impl = client->impl; @@ -4432,7 +4462,7 @@ static const struct command commands[COMMAND_MAX] = [COMMAND_STARTED] = { "STARTED", }, /* Supported since protocol v14 (0.9.12) */ - [COMMAND_EXTENSION] = { "EXTENSION", do_error_not_implemented, }, + [COMMAND_EXTENSION] = { "EXTENSION", do_extension, }, /* Supported since protocol v15 (0.9.15) */ [COMMAND_SET_CARD_PROFILE] = { "SET_CARD_PROFILE", do_set_profile, },