From 8803474fb1ef8b1b56105f888137895db584be9b Mon Sep 17 00:00:00 2001 From: Ismo Puustinen Date: Mon, 26 Nov 2012 15:51:52 +0200 Subject: [PATCH] resource-asm: added initial version of Audio Session Manager plugin. Audio Session Manager handles resource policy arbitration in Tizen. The Murphy ASM plugin makes Murphy the Tizen audio resource manager. --- src/plugins/plugin-resource-asm.c | 1057 +++++++++++++++++++++++++++++++++ src/plugins/resource-asm/Makefile.am | 7 + src/plugins/resource-asm/asm-bridge.c | 545 +++++++++++++++++ src/plugins/resource-asm/asm-bridge.h | 121 ++++ 4 files changed, 1730 insertions(+) create mode 100644 src/plugins/plugin-resource-asm.c create mode 100644 src/plugins/resource-asm/Makefile.am create mode 100644 src/plugins/resource-asm/asm-bridge.c create mode 100644 src/plugins/resource-asm/asm-bridge.h diff --git a/src/plugins/plugin-resource-asm.c b/src/plugins/plugin-resource-asm.c new file mode 100644 index 0000000..76ac590 --- /dev/null +++ b/src/plugins/plugin-resource-asm.c @@ -0,0 +1,1057 @@ +/* + * Copyright (c) 2012, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "resource-asm/asm-bridge.h" + + +typedef struct { + uint32_t pid; + mrp_htbl_t *sets; + uint32_t n_sets; + uint32_t current_handle; +} client_t; + + + +typedef struct { + /* configuration */ + const char *address; + const char *binary; + + /* asm-bridge management */ + pid_t pid; + mrp_transport_t *mt; /* listening transport */ + mrp_transport_t *t; /* connected transport */ + bool active; + + /* resource management */ + mrp_htbl_t *clients; + mrp_resource_client_t *resource_client; + char *zone; + + mrp_htbl_t *requests; + uint32_t current_request; + + /* murphy integration */ + mrp_sighandler_t *sighandler; + mrp_context_t *ctx; +} asm_data_t; + + +typedef enum { + request_type_acquire, + request_type_release, + request_type_server_event +} request_type_t; + + +typedef struct { + /* immutable */ + uint32_t pid; + uint32_t handle; + mrp_resource_set_t *rset; + uint32_t request_id; + asm_data_t *ctx; + + /* mutable */ + request_type_t rtype; +} resource_set_data_t; + + + +enum { + ARG_ASM_BRIDGE, + ARG_ASM_ZONE, + ARG_ASM_TPORT_ADDRESS, +}; + +static int tport_setup(const char *address, asm_data_t *ctx); + +static void *u_to_p(uint32_t u) +{ +#ifdef __SIZEOF_POINTER__ +#if __SIZEOF_POINTER__ == 8 + uint64_t o = u; +#else + uint32_t o = u; +#endif +#else + uint32_t o = o; +#endif + return (void *) o; +} + +static uint32_t p_to_u(const void *p) +{ +#ifdef __SIZEOF_POINTER__ +#if __SIZEOF_POINTER__ == 8 + uint32_t o = 0; + uint64_t big = (uint64_t) p; + o = big & 0xffffffff; +#else + uint32_t o = (uint32_t) p; +#endif +#else + uint32_t o = p; +#endif + return o; +} + + +static int int_comp(const void *key1, const void *key2) +{ + return key1 != key2; +} + + +static uint32_t int_hash(const void *key) +{ + return p_to_u(key); +} + + +static void dump_incoming_msg(lib_to_asm_t *msg, asm_data_t *ctx) +{ + MRP_UNUSED(ctx); + + mrp_log_info(" --> client id: %u", msg->instance_id); + mrp_log_info(" --> data handle: %d", msg->handle); + mrp_log_info(" --> request id: 0x%04x", msg->request_id); + mrp_log_info(" --> sound event: 0x%04x", msg->sound_event); + mrp_log_info(" --> system resource: 0x%04x", msg->system_resource); + mrp_log_info(" --> state: 0x%04x", msg->sound_state); +#ifdef USE_SECURITY + { + int n_cookie = msg->n_cookie_bytes; + int i; + + mrp_log_info(" --> cookie: ") + for (i = 0; i < n_cookie, i++) { + mrp_log_info("0x%02x ", msg->cookie[i]); + } + mrp_log_info("\n"); + } +#endif +} + + + +static void dump_outgoing_msg(asm_to_lib_t *msg, asm_data_t *ctx) +{ + MRP_UNUSED(ctx); + + mrp_log_info(" <-- client id: %u", msg->instance_id); + mrp_log_info(" <-- alloc handle: %d", msg->alloc_handle); + mrp_log_info(" <-- command handle: %d", msg->cmd_handle); + mrp_log_info(" <-- sound command: 0x%04x", msg->result_sound_command); + mrp_log_info(" <-- state: 0x%04x", msg->result_sound_state); + mrp_log_info(" <-- check privilege: %s", + msg->check_privilege ? "TRUE" : "FALSE"); +} + +#if 0 +static uint32_t encode_pid_handle(uint32_t pid, uint32_t handle) { + + uint32_t max_pid = 4194304; /* 2^22 */ + uint32_t max_handle = 1024; /* 2^10 */ + + if (pid > max_pid || handle > max_handle) { + return 0; + } + + return pid | (handle << 22); +} + +static uint32_t get_pid(uint32_t data) { + uint32_t pid_mask = 0xffffffff >> 10; + + return data & pid_mask; +} + + +static uint32_t get_handle(uint32_t data) { + + return data >> 22; +} +#endif + + +static void htbl_free_set(void *key, void *object) +{ + resource_set_data_t *d = object; + + MRP_UNUSED(key); + + mrp_resource_set_destroy(d->rset); + + mrp_free(d); +} + + +static client_t *create_client(uint32_t pid) { + client_t *client = mrp_allocz(sizeof(client_t)); + mrp_htbl_config_t set_conf; + + if (!client) + return NULL; + + set_conf.comp = int_comp; + set_conf.hash = int_hash; + set_conf.free = htbl_free_set; + set_conf.nbucket = 0; + set_conf.nentry = 10; + + client->sets = mrp_htbl_create(&set_conf); + + if (!client->sets) { + mrp_free(client); + return NULL; + } + + client->pid = pid; + client->current_handle = 1; + client->n_sets = 0; + + return client; +} + + +static void event_cb(uint32_t request_id, mrp_resource_set_t *set, void *data) +{ + resource_set_data_t *d = data; + asm_data_t *ctx = d->ctx; + + mrp_log_info("Event CB: id %u, set %p", request_id, set); + mrp_log_info("Resource set %u.%u", d->pid, d->handle); + mrp_log_info("Advice 0x%08x, Grant 0x%08x", + mrp_get_resource_set_advice(d->rset), + mrp_get_resource_set_grant(d->rset)); + + + switch(d->rtype) { + case request_type_acquire: + { + asm_to_lib_t reply; + mrp_log_info("callback for acquire request %u", request_id); + + /* expecting next server events */ + d->rtype = request_type_server_event; + + reply.instance_id = d->pid; + reply.check_privilege = FALSE; + reply.alloc_handle = d->handle; + reply.cmd_handle = d->handle; + + reply.result_sound_command = ASM_COMMAND_NONE; + + /* TODO: check the mask properly */ + if (mrp_get_resource_set_grant(d->rset)) + reply.result_sound_state = ASM_STATE_PLAYING; + else + reply.result_sound_state = ASM_STATE_STOP; + + d->rtype = request_type_server_event; + + dump_outgoing_msg(&reply, ctx); + mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB); + break; + } + case request_type_release: + { + asm_to_lib_t reply; + mrp_log_info("callback for release request %u", request_id); + + /* expecting next server events */ + d->rtype = request_type_server_event; + + reply.instance_id = d->pid; + reply.check_privilege = FALSE; + reply.alloc_handle = d->handle; + reply.cmd_handle = d->handle; + + reply.result_sound_command = ASM_COMMAND_NONE; + reply.result_sound_state = ASM_STATE_STOP; + + d->rtype = request_type_server_event; + + dump_outgoing_msg(&reply, ctx); + mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB); + break; + } + case request_type_server_event: + { + asm_to_lib_cb_t reply; + mrp_log_info("callback for no request %u", request_id); + + reply.instance_id = d->pid; + reply.handle = d->handle; + reply.callback_expected = FALSE; + + if (mrp_get_resource_set_grant(d->rset)) + reply.sound_command = ASM_COMMAND_PLAY; + else + reply.sound_command = ASM_COMMAND_STOP; + + /* FIXME: the player-player case needs to be solved here? */ + reply.event_source = ASM_EVENT_SOURCE_RESOURCE_CONFLICT; + + mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB_CB); + + break; + } + } +} + + +static asm_to_lib_t *process_msg(lib_to_asm_t *msg, asm_data_t *ctx) +{ + pid_t pid = msg->instance_id; + + asm_to_lib_t *reply; + + reply = mrp_allocz(sizeof(asm_to_lib_t)); + + reply->instance_id = pid; + reply->check_privilege = FALSE; + + reply->alloc_handle = msg->handle; + reply->cmd_handle = msg->handle; + + reply->result_sound_command = ASM_COMMAND_NONE; + reply->result_sound_state = ASM_STATE_IGNORE; + + switch(msg->request_id) { + case ASM_REQUEST_REGISTER: + { + client_t *client; + bool shared = FALSE; + char *resource = "invalid"; + + mrp_log_info("REQUEST: REGISTER"); + + /* see if the process already has a client object */ + client = mrp_htbl_lookup(ctx->clients, u_to_p(pid)); + + if (!client) { + client = create_client(pid); + mrp_htbl_insert(ctx->clients, u_to_p(pid), client); + } +#if 1 + else { + /* From Murphy point of view this is actually an error case, + * since the application can only belong to one class. This is + * a Murphy limitation and should be fixed later. */ + + mrp_log_error("Application tried to register twice"); + goto error; + } +#endif + + switch (msg->sound_event) { + case ASM_EVENT_NONE: + break; + case ASM_EVENT_SHARE_MMPLAYER: + resource = "player"; + shared = TRUE; + break; + case ASM_EVENT_SHARE_MMCAMCORDER: + resource = "camera"; + shared = TRUE; + break; + case ASM_EVENT_SHARE_MMSOUND: + resource = "sound"; + shared = TRUE; + break; + case ASM_EVENT_SHARE_OPENAL: + shared = TRUE; + break; + case ASM_EVENT_SHARE_AVSYSTEM: + shared = TRUE; + break; + case ASM_EVENT_EXCLUSIVE_MMPLAYER: + resource = "player"; + shared = FALSE; + break; + case ASM_EVENT_EXCLUSIVE_MMCAMCORDER: + resource = "camera"; + shared = FALSE; + break; + case ASM_EVENT_EXCLUSIVE_MMSOUND: + resource = "sound"; + shared = FALSE; + break; + case ASM_EVENT_EXCLUSIVE_OPENAL: + shared = FALSE; + break; + case ASM_EVENT_EXCLUSIVE_AVSYSTEM: + shared = FALSE; + break; + case ASM_EVENT_NOTIFY: + shared = FALSE; + break; + case ASM_EVENT_CALL: + resource = "phone"; + shared = FALSE; + break; + case ASM_EVENT_SHARE_FMRADIO: + shared = TRUE; + break; + case ASM_EVENT_EXCLUSIVE_FMRADIO: + shared = FALSE; + break; + case ASM_EVENT_EARJACK_UNPLUG: + mrp_log_info("earjack unplug event"); + break; + case ASM_EVENT_ALARM: + shared = FALSE; + break; + case ASM_EVENT_VIDEOCALL: + resource = "phone"; + shared = FALSE; + break; + case ASM_EVENT_MONITOR: + break; + case ASM_EVENT_RICH_CALL: + resource = "phone"; + shared = FALSE; + break; + default: + break; + } + + if (strcmp(resource, "invalid") == 0) { + mrp_log_error("unknown resource type: %d", msg->sound_event); + goto error; + } + + else { + uint32_t handle = client->current_handle++; + mrp_resource_set_t *set; + resource_set_data_t *d = mrp_allocz(sizeof(resource_set_data_t)); + + d->handle = handle; + d->ctx = ctx; + d->pid = pid; + d->rtype = request_type_server_event; + d->request_id = 0; + + set = mrp_resource_set_create(ctx->resource_client, 0, 0, + event_cb, d); + + if (!set) { + mrp_log_error("Failed to create resource set!"); + goto error; + } + + d->rset = set; + + mrp_resource_set_add_resource(set, "audio_playback", shared, NULL, TRUE); + mrp_resource_set_add_resource(set, "audio_record", shared, NULL, TRUE); + + mrp_application_class_add_resource_set(resource, ctx->zone, set, 0); + + mrp_htbl_insert(client->sets, u_to_p(handle), d); + client->n_sets++; + + reply->alloc_handle = handle; + reply->cmd_handle = reply->alloc_handle; + + reply->result_sound_state = ASM_STATE_WAITING; + reply->result_sound_command = ASM_COMMAND_NONE; + } + + break; + } + case ASM_REQUEST_UNREGISTER: + { + client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid)); + + mrp_log_info("REQUEST: UNREGISTER"); + + if (client) { + resource_set_data_t *d; + + d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle)); + if (!d || !d->rset) { + mrp_log_error("set '%u.%u' not found", pid, msg->handle); + goto error; + } + + /* the resource set id destroyed when it's removed from the + * table */ + mrp_htbl_remove(client->sets, u_to_p(msg->handle), TRUE); + client->n_sets--; + + if (client->n_sets <= 0) { + mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE); + client = NULL; + } + } + + /* TODO: free memory and check if the resource set is empty when + * the resource library supports it */ + + /* no reply needed! */ + goto noreply; + + break; + } + case ASM_REQUEST_SETSTATE: + { + client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid)); + + resource_set_data_t *d; + + mrp_log_info("REQUEST: SET STATE"); + + if (!client) { + mrp_log_error("client '%u' not found", pid); + goto error; + } + + d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle)); + if (!d || !d->rset) { + mrp_log_error("set '%u.%u' not found", pid, msg->handle); + goto error; + } + + d->request_id = ++ctx->current_request; + + switch(msg->sound_state) { + case ASM_STATE_PLAYING: + { + d->rtype = request_type_acquire; + + mrp_log_info("requesting acquisition of playback rights" + " for set '%u.%u' (id: %u)", pid, msg->handle, + d->request_id); + + mrp_resource_set_acquire(d->rset, d->request_id); + + break; + } + case ASM_STATE_STOP: + { + d->rtype = request_type_release; + + mrp_log_info("requesting release of playback rights for" + " set '%u.%u' (id: %u)", pid, msg->handle, + d->request_id); + + mrp_resource_set_release(d->rset, d->request_id); + + break; + } + default: + { + mrp_log_error("Unknown state: %d", msg->sound_state); + } + } + + goto noreply; + + break; + } + case ASM_REQUEST_GETSTATE: + mrp_log_info("REQUEST: GET STATE"); + /* TODO: get the current resource state for msg->sound_event (which + * is the application class). Put it to reply->result_sound_state + * field. */ + break; + case ASM_REQUEST_GETMYSTATE: + mrp_log_info("REQUEST: GET MY STATE"); + /* TODO: get the current state for the process (resource set). Put + * it to reply->result_sound_state field. */ + break; + case ASM_REQUEST_EMERGENT_EXIT: + { + client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid)); + + mrp_log_info("REQUEST: EMERGENCY EXIT"); + + if (!client) { + mrp_log_error("client '%u' not found", pid); + goto noreply; + } + + mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE); + + goto noreply; + break; + } + case ASM_REQUEST_SET_SUBSESSION: + mrp_log_info("REQUEST: SET SUBSESSION"); + break; + case ASM_REQUEST_GET_SUBSESSION: + mrp_log_info("REQUEST: GET SUBSESSION"); + break; + default: + mrp_log_info("REQUEST: UNKNOWN REQUEST"); + break; + } + + return reply; + +error: +noreply: + + mrp_free(reply); + return NULL; +} + + +static void process_cb_msg(lib_to_asm_cb_t *msg, asm_data_t *ctx) +{ + const char *str; + + MRP_UNUSED(ctx); + + /* TODO: this function might tell something to the resource library */ + + switch (msg->cb_result) { + case ASM_CB_RES_IGNORE: + str = "ignore"; + break; + case ASM_CB_RES_NONE: + str = "none"; + break; + case ASM_CB_RES_PAUSE: + str = "pause"; + break; + case ASM_CB_RES_PLAYING: + str = "playing"; + break; + case ASM_CB_RES_STOP: + str = "stop"; + break; + default: + mrp_log_error("unknown callback state %d", msg->cb_result); + return; + } + + mrp_log_info("client %d.%u ended in state '%s' after callback", + msg->instance_id, msg->handle, str); +} + + +static void recvdatafrom_evt(mrp_transport_t *t, void *data, uint16_t tag, + mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data) +{ + asm_data_t *ctx = user_data; + + MRP_UNUSED(addr); + MRP_UNUSED(addrlen); + + switch (tag) { + case TAG_LIB_TO_ASM: + { + lib_to_asm_t *msg = data; + asm_to_lib_t *reply; + + /* client requests something from us */ + + dump_incoming_msg(msg, ctx); + + reply = process_msg(msg, ctx); + if (reply) { + dump_outgoing_msg(reply, ctx); + mrp_transport_senddata(t, reply, TAG_ASM_TO_LIB); + } + break; + } + case TAG_LIB_TO_ASM_CB: + { + lib_to_asm_cb_t *msg = data; + + /* client tells us which state it entered after preemption */ + + process_cb_msg(msg, ctx); + break; + } + + default: + mrp_log_error("Unknown message received!"); + break; + } + + mrp_data_free(data, tag); +} + + +static void recvdata_evt(mrp_transport_t *t, void *data, uint16_t tag, void *user_data) +{ + recvdatafrom_evt(t, data, tag, NULL, 0, user_data); +} + + + +static void closed_evt(mrp_transport_t *t, int error, void *user_data) +{ +#if 1 + asm_data_t *ctx = user_data; + + MRP_UNUSED(error); + + mrp_log_info("closed!"); + + mrp_transport_disconnect(t); + mrp_transport_destroy(t); + + ctx->t = NULL; + + /* TODO: start the listening socket again and relaunch the binary? */ +#endif +} + + +static void connection_evt(mrp_transport_t *lt, void *user_data) +{ + asm_data_t *ctx = user_data; + + mrp_log_info("connection!"); + + if (ctx->t) { + mrp_log_error("Already connected"); + } + else { + ctx->t = mrp_transport_accept(lt, ctx, 0); + } + + /* close the listening socket, since we only have one client */ + + mrp_transport_destroy(lt); + ctx->mt = NULL; +} + + + +static int tport_setup(const char *address, asm_data_t *ctx) +{ + const char *atype; + ssize_t alen; + mrp_sockaddr_t addr; + + struct stat statbuf; + + static mrp_transport_evt_t evt = { + { .recvdata = recvdata_evt }, + { .recvdatafrom = recvdatafrom_evt }, + .closed = closed_evt, + .connection = connection_evt + }; + + alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype); + + if (alen <= 0) { + mrp_log_error("Error resolving transport address"); + goto error; + } + + /* remove the old socket if present */ + + if (strcmp(atype, "unxs") == 0) { + char *path = addr.unx.sun_path; + if (path[0] == '/') { + /* if local socket and file exists, remove it */ + if (stat(path, &statbuf) == 0) { + if (S_ISSOCK(statbuf.st_mode)) { + if (unlink(path) < 0) { + mrp_log_error("error removing the socket"); + goto error; + } + } + else { + mrp_log_error("a file where the socket should be created"); + goto error; + } + } + } + } + + ctx->mt = mrp_transport_create(ctx->ctx->ml, atype, &evt, ctx, + MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK); + + if (ctx->mt == NULL) { + mrp_log_error("Failed to create the transport"); + goto error; + } + + if (!mrp_transport_bind(ctx->mt, &addr, alen)) { + mrp_log_error("Failed to bind the transport to address '%s'", address); + goto error; + } + + + if (!mrp_transport_listen(ctx->mt, 5)) { + mrp_log_error("Failed to listen to transport"); + goto error; + } + + return 0; + +error: + if (ctx->mt) { + mrp_transport_destroy(ctx->mt); + ctx->mt = NULL; + } + + return -1; +} + +static void signal_handler(mrp_mainloop_t *ml, mrp_sighandler_t *h, + int signum, void *user_data) +{ + asm_data_t *ctx = user_data; + + MRP_UNUSED(ml); + MRP_UNUSED(h); + + if (signum == SIGCHLD) { + /* wait for the child */ + if (ctx->pid > 0) { + int ret; + + mrp_log_info("Received SIGCHLD, waiting for asm-bridge"); + + ret = waitpid(ctx->pid, NULL, WNOHANG); + + if (ret == ctx->pid) { + mrp_log_warning("asm-bridge process died"); + ctx->pid = 0; + } + } + } +} + +static void htbl_free_client(void *key, void *object) +{ + MRP_UNUSED(key); + + client_t *client = object; + + mrp_htbl_destroy(client->sets, TRUE); + + /* TODO: free memory when resource API allows that */ + mrp_free(client); +} + +static int asm_init(mrp_plugin_t *plugin) +{ + mrp_plugin_arg_t *args = plugin->args; + asm_data_t *ctx = mrp_allocz(sizeof(asm_data_t)); + pid_t pid; + mrp_htbl_config_t client_conf; + + if (!ctx) { + goto error; + } + + ctx->ctx = plugin->ctx; + ctx->address = args[ARG_TPORT_ADDRESS].str; + ctx->binary = args[ARG_ASM_BRIDGE].str; + ctx->zone = args[ARG_ASM_ZONE].str; + + /* create the transport and put it to listen mode */ + + if (!mrp_msg_register_type(&asm_to_lib_descr)) { + mrp_log_error("Failed to register message type asm_to_lib"); + goto error; + } + + if (!mrp_msg_register_type(&lib_to_asm_descr)) { + mrp_log_error("Failed to register message type lib_to_asm"); + goto error; + } + + if (!mrp_msg_register_type(&asm_to_lib_cb_descr)) { + mrp_log_error("Failed to register message type asm_to_lib_cb"); + goto error; + } + + if (!mrp_msg_register_type(&lib_to_asm_cb_descr)) { + mrp_log_error("Failed to register message type lib_to_asm_cb"); + goto error; + } + + if (tport_setup(ctx->address, ctx) < 0) { + goto error; + } + + /* listen to SIGCHLD signal */ + + ctx->sighandler = mrp_add_sighandler(plugin->ctx->ml, SIGCHLD, signal_handler, ctx); + + if (!ctx->sighandler) { + mrp_log_error("Failed to register signal handling"); + goto error; + } + + client_conf.comp = int_comp; + client_conf.hash = int_hash; + client_conf.free = htbl_free_client; + client_conf.nbucket = 0; + client_conf.nentry = 10; + + ctx->clients = mrp_htbl_create(&client_conf); + + if (!ctx->clients) { + mrp_log_error("Error creating resource set hash table"); + goto error; + } + + /* create the client structure towards Murphy */ + + ctx->resource_client = mrp_resource_client_create("ASM", ctx); + + if (!ctx->resource_client) { + mrp_log_error("Failed to get a resource client"); + goto error; + } + + /* fork-exec the asm bridge binary */ + + mrp_log_info("going to fork!"); + + pid = fork(); + + if (pid < 0) { + mrp_log_error("error launching asm-bridge"); + goto error; + } + else if (pid == 0) { + /* child */ + execl(ctx->binary, ctx->binary, ctx->address, NULL); + exit(1); + } + else { + /* parent */ + ctx->pid = pid; + mrp_log_info("child pid is %d", pid); + } + + plugin->data = ctx; + + return TRUE; + +error: + + if (ctx->pid) { + kill(ctx->pid, SIGTERM); + ctx->pid = 0; + } + + if (ctx->sighandler) { + mrp_del_sighandler(ctx->sighandler); + ctx->sighandler = NULL; + } + + if (ctx->resource_client) { + mrp_resource_client_destroy(ctx->resource_client); + } + + mrp_free(ctx); + + return FALSE; +} + + +static void asm_exit(mrp_plugin_t *plugin) +{ + asm_data_t *ctx = plugin->data; + + if (ctx->pid) { + kill(ctx->pid, SIGTERM); + ctx->pid = 0; + } + + if (ctx->mt) { + mrp_transport_disconnect(ctx->mt); + mrp_transport_destroy(ctx->mt); + ctx->mt = NULL; + } + + if (ctx->t) { + mrp_transport_disconnect(ctx->t); + mrp_transport_destroy(ctx->t); + ctx->t = NULL; + } + + if (ctx->sighandler) { + mrp_del_sighandler(ctx->sighandler); + ctx->sighandler = NULL; + } + + if (ctx->clients) { + mrp_htbl_destroy(ctx->clients, TRUE); + ctx->clients = NULL; + } + + mrp_resource_client_destroy(ctx->resource_client); + + mrp_free(ctx); + plugin->data = NULL; +} + + +#define ASM_DESCRIPTION "A plugin to handle SLP Audio Session Manager client requests." +#define ASM_HELP "Audio Session Manager backend" +#define ASM_VERSION MRP_VERSION_INT(0, 0, 1) +#define ASM_AUTHORS "Ismo Puustinen " + +static mrp_plugin_arg_t args[] = { + MRP_PLUGIN_ARGIDX(ARG_ASM_BRIDGE, STRING, "asm_bridge", "/usr/sbin/asm-bridge"), + MRP_PLUGIN_ARGIDX(ARG_ASM_ZONE, STRING, "zone", "default"), + MRP_PLUGIN_ARGIDX(ARG_ASM_TPORT_ADDRESS, STRING, "tport_address", "unxs:/tmp/murphy/asm"), +}; + + +MURPHY_REGISTER_PLUGIN("resource-asm", + ASM_VERSION, ASM_DESCRIPTION, ASM_AUTHORS, ASM_HELP, + MRP_SINGLETON, asm_init, asm_exit, + args, MRP_ARRAY_SIZE(args), + NULL, 0, NULL, 0, NULL); diff --git a/src/plugins/resource-asm/Makefile.am b/src/plugins/resource-asm/Makefile.am new file mode 100644 index 0000000..7fb9563 --- /dev/null +++ b/src/plugins/resource-asm/Makefile.am @@ -0,0 +1,7 @@ +AM_CFLAGS = $(WARNING_CFLAGS) -I$(top_builddir) + +sbin_PROGRAMS = asm-bridge + +asm_bridge_SOURCES = asm-bridge.c asm-bridge.h +asm_bridge_CFLAGS = $(AM_CFLAGS) $(AUDIO_SESSION_MANAGER_CFLAGS) +asm_bridge_LDADD = ../../libmurphy-common.la -lpthread diff --git a/src/plugins/resource-asm/asm-bridge.c b/src/plugins/resource-asm/asm-bridge.c new file mode 100644 index 0000000..62b119d --- /dev/null +++ b/src/plugins/resource-asm/asm-bridge.c @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2012, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include + +#include "asm-bridge.h" + + +typedef struct ctx_s { + mrp_mainloop_t *ml; + mrp_transport_t *mt; + int snd_msgq; + mrp_htbl_t *watched_files; +} ctx_t; + +struct watched_file { + char *watched_file; + mrp_io_watch_t *wd; + int32_t instance_id; + uint32_t handle; + ctx_t *ctx; +}; + +static void *wait_queue (void *arg) { + ASM_msg_lib_to_asm_t msg; + + int *arg_thread = arg; + + int asm_rcv_msgid = arg_thread[0]; + int fd = arg_thread[1]; + + if (asm_rcv_msgid == -1) { + mrp_log_error("failed to create the receive message queue\n"); + exit(1); + } + + while (1) { + int ret = msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, 0); + + if (ret < 0) { + /* FIXME: proper error handling */ + mrp_log_error("error receiving a message!"); + continue; + } + + /* alignment is fine, since the first argument to the struct is a long */ + write(fd, &msg, sizeof(ASM_msg_lib_to_asm_t)); + } + + return NULL; +} + + +static void dump_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx) +{ + MRP_UNUSED(ctx); + + mrp_log_info("Message id %ld:", msg->instance_id); + + mrp_log_info("Data handle: %d", msg->data.handle); + mrp_log_info(" request id: 0x%04x", msg->data.request_id); + mrp_log_info(" sound event: 0x%04x", msg->data.sound_event); + mrp_log_info(" sound state: 0x%04x", msg->data.sound_state); + mrp_log_info(" system resource: 0x%04x", msg->data.system_resource); +#ifdef USE_SECURITY + { + int i; + + mrp_log_info(" cookie: ") + for (i = 0; i < COOKIE_SIZE, i++) { + mrp_log_info("0x%02x ", msg->data.cookie[i]); + } + mrp_log_info("\n"); + } +#endif +} + + +static int process_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx) +{ + lib_to_asm_t res; + uint8_t cookie_arr[] = {}; + int cookie_len = 0; + + dump_msg(msg, ctx); + + /* FIXME: instance_id is signed? */ + res.instance_id = msg->instance_id; + res.handle = msg->data.handle; + res.request_id = msg->data.request_id; + res.sound_event = msg->data.sound_event; + res.sound_state = msg->data.sound_state; + res.system_resource = msg->data.system_resource; +#ifdef USE_SECURITY + { + cookie_len = strlen(msg->data.cookie); + cookie_arr = msg->data.cookie; + + res.n_cookie_bytes = cookie_len; + res.cookie = cookie_arr; + } +#endif + + res.n_cookie_bytes = cookie_len; + res.cookie = cookie_arr; + + if (!mrp_transport_senddata(ctx->mt, &res, lib_to_asm_descr.tag)) { + mrp_log_error("Failed to send message to murphy"); + return -1; + } + + return 0; +} + + +static void pipe_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd, + mrp_io_event_t events, void *user_data) +{ + ASM_msg_lib_to_asm_t msg; + ctx_t *ctx = user_data; + int bytes; + int ret; + + MRP_UNUSED(ml); + MRP_UNUSED(w); + MRP_UNUSED(events); + + bytes = read(fd, &msg, sizeof(ASM_msg_lib_to_asm_t)); + + if (bytes != sizeof(ASM_msg_lib_to_asm_t)) { + mrp_log_error("failed to read from the pipe"); + return; + } + + ret = process_msg(&msg, ctx); + + if (ret < 0) { + mrp_log_error("error parsing or proxying message"); + } +} + + +static void read_watch_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd, + mrp_io_event_t events, void *user_data) +{ + struct watched_file *wf = user_data; + ctx_t *ctx = wf->ctx; + + MRP_UNUSED(ml); + MRP_UNUSED(w); + + if (events & MRP_IO_EVENT_IN) { + uint32_t buf; + int ret; + + ret = read(fd, &buf, sizeof(uint32_t)); + + if (ret == sizeof(uint32_t)) { + lib_to_asm_cb_t msg; + + msg.instance_id = wf->instance_id; + msg.handle = wf->handle; + msg.cb_result = buf; + + if (!mrp_transport_senddata(ctx->mt, &msg, lib_to_asm_cb_descr.tag)) { + mrp_log_error("Failed to send message to murphy"); + } + } + } + if (events & MRP_IO_EVENT_HUP) { + /* can we assume that the client went away? */ + mrp_log_error("HUP event from client"); + } + + mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE); + close(fd); +} + + +static int send_callback_to_client(asm_to_lib_cb_t *msg, ctx_t *ctx) +{ +#define ASM_FILENAME_SIZE 64 + char wr_filename[ASM_FILENAME_SIZE]; + char rd_filename[ASM_FILENAME_SIZE]; + + int wr_fd = -1; + int rd_fd = -1; + uint32_t data; + int ret; + + struct watched_file *wf = NULL; + + snprintf(wr_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%u", + msg->instance_id, msg->handle); + + mrp_log_info("writing client preemption to file %s", wr_filename); + + wr_fd = open(wr_filename, O_NONBLOCK | O_WRONLY); + if (wr_fd < 0) { + mrp_log_error("failed to open file '%s' for writing", wr_filename); + goto error; + } + + if (msg->callback_expected) { + + snprintf(rd_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%ur", + msg->instance_id, msg->handle); + rd_fd = open(wr_filename, O_NONBLOCK | O_RDONLY); + if (rd_fd < 0) { + mrp_log_error("failed to open file '%s' for reading", rd_filename); + goto error; + } + + wf = mrp_htbl_lookup(ctx->watched_files, rd_filename); + + if (wf) { + /* already watched, this is a bad thing */ + + mrp_log_error("client %d.%u missed a callback notification", + msg->instance_id, msg->handle); + } + else { + + wf = mrp_allocz(sizeof(struct watched_file)); + + wf->watched_file = mrp_strdup(rd_filename); + wf->ctx = ctx; + wf->instance_id = msg->instance_id; + wf->handle = msg->handle; + wf->wd = mrp_add_io_watch(ctx->ml, rd_fd, MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP, + read_watch_cb, wf); + + mrp_htbl_insert(ctx->watched_files, wf->watched_file, wf); + } + } + + /* encode the data for sending */ + data = 0x0000ffff; + data &= msg->handle; + data |= msg->sound_command << 16; + data |= msg->event_source << 24; + + ret = write(wr_fd, &data, sizeof(uint32_t)); + + if (ret < (int) sizeof(uint32_t)) { + mrp_log_error("failed to write callback data to %d.%u", + msg->instance_id, msg->handle); + goto error; + } + + mrp_log_error("Wrote data 0x%08x successfully to client", data); + + close(wr_fd); + + return 0; + +error: + if (wf && wf->watched_file) { + mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE); + } + + if (wr_fd >= 0) { + close(wr_fd); + } + + if (rd_fd >= 0) { + close(wr_fd); + } + + return -1; +#undef ASM_FILENAME_SIZE +} + + +static void recvfrom_murphy(mrp_transport_t *t, void *data, uint16_t tag, + mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data) +{ + ctx_t *ctx = user_data; + + MRP_UNUSED(t); + MRP_UNUSED(addr); + MRP_UNUSED(addrlen); + + switch (tag) { + case TAG_ASM_TO_LIB: + { + asm_to_lib_t *res = data; + ASM_msg_asm_to_lib_t msg; + + msg.instance_id = res->instance_id; + msg.data.alloc_handle = res->alloc_handle; + msg.data.cmd_handle = res->cmd_handle; + msg.data.result_sound_command = res->result_sound_command; + msg.data.result_sound_state = res->result_sound_state; +#ifdef USE_SECURITY + msg.data.check_privilege = res->check_privilege; +#endif + + if (msgsnd(ctx->snd_msgq, (void *) &msg, + sizeof(msg.data), 0) < 0) { + mrp_log_error("failed to send message to client"); + } + break; + } + + case TAG_ASM_TO_LIB_CB: + { + if (send_callback_to_client(data, ctx) < 0) { + mrp_log_error("failed to send callback message to client"); + } + break; + } + + default: + mrp_log_error("Unknown message received!"); + break; + } +} + + +static void recv_murphy(mrp_transport_t *t, void *data, uint16_t tag, void *user_data) +{ + recvfrom_murphy(t, data, tag, NULL, 0, user_data); +} + + +static void closed_evt(mrp_transport_t *t, int error, void *user_data) +{ + ctx_t *ctx = user_data; + + MRP_UNUSED(t); + MRP_UNUSED(error); + + mrp_log_error("server closed the connection"); + + mrp_mainloop_quit(ctx->ml, 0); +} + + +static int connect_to_murphy(char *address, ctx_t *ctx) +{ + const char *atype; + ssize_t alen; + mrp_sockaddr_t addr; + + static mrp_transport_evt_t evt = { + { .recvdata = recv_murphy }, + { .recvdatafrom = recvfrom_murphy }, + .closed = closed_evt, + .connection = NULL + }; + + if (!mrp_msg_register_type(&lib_to_asm_descr) || + !mrp_msg_register_type(&asm_to_lib_descr) || + !mrp_msg_register_type(&asm_to_lib_cb_descr) || + !mrp_msg_register_type(&lib_to_asm_cb_descr)) { + mrp_log_error("Failed to register message types"); + goto error; + } + + alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype); + + if (alen <= 0) { + mrp_log_error("Error resolving transport address"); + goto error; + } + + ctx->mt = mrp_transport_create(ctx->ml, atype, &evt, ctx, + MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK); + + if (ctx->mt == NULL) { + mrp_log_error("Failed to create the transport"); + goto error; + } + +#if 0 + if (!mrp_transport_bind(ctx->mt, &addr, alen)) { + mrp_log_error("Failed to bind the transport to address '%s'", address); + goto error; + } +#endif + + if (!mrp_transport_connect(ctx->mt, &addr, alen)) { + mrp_log_error("Failed to connect the transport"); + goto error; + } + + return 0; + +error: + if (ctx->mt) + mrp_transport_destroy(ctx->mt); + + return -1; +} + +static void htbl_free_watches(void *key, void *object) +{ + struct watched_file *wf = object; + + MRP_UNUSED(key); + + mrp_free(wf->watched_file); + if (wf->wd) + mrp_del_io_watch(wf->wd); + + mrp_free(wf); +} + + +int main (int argc, char **argv) +{ + pthread_t thread = 0; + void *res; + int pipes[2]; + int thread_arg[2]; + mrp_io_watch_t *iow; + mrp_io_event_t events = MRP_IO_EVENT_IN; + + int asm_snd_msgid = msgget((key_t)4102, 0666 | IPC_CREAT); + int asm_rcv_msgid = msgget((key_t)2014, 0666 | IPC_CREAT); + + mrp_htbl_config_t watches_conf; + + ctx_t ctx; + + /* set up the signal handling */ + + if (asm_snd_msgid == -1 || asm_rcv_msgid == -1) { + mrp_log_error("failed to create the message queues\n"); + goto end; + } + + ctx.ml = NULL; + ctx.mt = NULL; + ctx.snd_msgq = asm_snd_msgid; + + if (argc != 2 || strncmp(argv[1], "unxs", 4) != 0) { + mrp_log_error("Usage: asm-bridge "); + goto end; + } + + watches_conf.comp = mrp_string_comp; + watches_conf.hash = mrp_string_hash; + watches_conf.free = htbl_free_watches; + watches_conf.nbucket = 0; + watches_conf.nentry = 10; + + ctx.watched_files = mrp_htbl_create(&watches_conf); + + ctx.ml = mrp_mainloop_create(); + + /* Initialize connection to murphyd */ + + if (connect_to_murphy(argv[1], &ctx) < 0) { + goto end; + } + + /* create a pipe for communicating with the ASM thread */ + + pipe(pipes); + + /* pass the message queue and the pipe writing end to the thread */ + + thread_arg[0] = asm_rcv_msgid; + thread_arg[1] = pipes[1]; + + /* start listening to the read end of the pipe */ + + iow = mrp_add_io_watch(ctx.ml, pipes[0], events, pipe_cb, &ctx); + + if (!iow) { + goto end; + } + + pthread_create(&thread, NULL, wait_queue, thread_arg); + + /* start processing events */ + + mrp_mainloop_run(ctx.ml); + + mrp_log_warning("shutting down asm-bridge"); + +end: + if (iow) + mrp_del_io_watch(iow); + + if (ctx.watched_files) { + mrp_htbl_destroy(ctx.watched_files, TRUE); + } + + if (thread) { + pthread_cancel(thread); + pthread_join(thread, &res); + } + + /* free the message queues */ + + msgctl(asm_snd_msgid, IPC_RMID, 0); + msgctl(asm_rcv_msgid, IPC_RMID, 0); + + exit(0); +} diff --git a/src/plugins/resource-asm/asm-bridge.h b/src/plugins/resource-asm/asm-bridge.h new file mode 100644 index 0000000..429875f --- /dev/null +++ b/src/plugins/resource-asm/asm-bridge.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2012, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MURPHY_ASM_BRIDGE_H +#define MURPHY_ASM_BRIDGE_H + +#include +#include +#include +#include + +#include + +#define TAG_LIB_TO_ASM ((uint16_t) 0x100) +#define TAG_ASM_TO_LIB ((uint16_t) 0x101) +#define TAG_ASM_TO_LIB_CB ((uint16_t) 0x102) +#define TAG_LIB_TO_ASM_CB ((uint16_t) 0x103) + +/* library requests something */ + +typedef struct { + uint32_t instance_id; + int32_t handle; + uint32_t request_id; + uint32_t sound_event; + uint32_t sound_state; + uint32_t system_resource; + uint32_t n_cookie_bytes; + uint8_t *cookie; +} lib_to_asm_t; + +/* server reply to library */ + +typedef struct { + uint32_t instance_id; + int32_t alloc_handle; + int32_t cmd_handle; + uint32_t result_sound_command; + uint32_t result_sound_state; + bool check_privilege; +} asm_to_lib_t; + +/* server sends a preemption command */ + +typedef struct { + uint32_t instance_id; + int32_t handle; + bool callback_expected; + uint32_t sound_command; /* ASM_sound_commands_t */ + uint32_t event_source; /* ASM_event_sources_t */ +} asm_to_lib_cb_t; + +/* library tells the state it landed in after preemption */ + +typedef struct { + uint32_t instance_id; + int32_t handle; + uint32_t cb_result; /* ASM_cb_result_t */ +} lib_to_asm_cb_t; + + + +MRP_DATA_DESCRIPTOR(lib_to_asm_descr, TAG_LIB_TO_ASM, lib_to_asm_t, + MRP_DATA_MEMBER(lib_to_asm_t, instance_id, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_t, handle, MRP_MSG_FIELD_INT32), + MRP_DATA_MEMBER(lib_to_asm_t, request_id, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_t, sound_event, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_t, sound_state, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_t, system_resource, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_t, n_cookie_bytes, MRP_MSG_FIELD_UINT32), + MRP_DATA_ARRAY_COUNT(lib_to_asm_t, cookie, n_cookie_bytes, + MRP_MSG_FIELD_UINT8)); + +MRP_DATA_DESCRIPTOR(asm_to_lib_descr, TAG_ASM_TO_LIB, asm_to_lib_t, + MRP_DATA_MEMBER(asm_to_lib_t, instance_id, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(asm_to_lib_t, alloc_handle, MRP_MSG_FIELD_INT32), + MRP_DATA_MEMBER(asm_to_lib_t, cmd_handle, MRP_MSG_FIELD_INT32), + MRP_DATA_MEMBER(asm_to_lib_t, result_sound_command, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(asm_to_lib_t, result_sound_state, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(asm_to_lib_t, check_privilege, MRP_MSG_FIELD_BOOL)); + +MRP_DATA_DESCRIPTOR(asm_to_lib_cb_descr, TAG_ASM_TO_LIB_CB, asm_to_lib_cb_t, + MRP_DATA_MEMBER(asm_to_lib_cb_t, instance_id, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(asm_to_lib_cb_t, handle, MRP_MSG_FIELD_INT32), + MRP_DATA_MEMBER(asm_to_lib_cb_t, callback_expected, MRP_MSG_FIELD_BOOL), + MRP_DATA_MEMBER(asm_to_lib_cb_t, sound_command, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(asm_to_lib_cb_t, event_source, MRP_MSG_FIELD_UINT32)); + +MRP_DATA_DESCRIPTOR(lib_to_asm_cb_descr, TAG_LIB_TO_ASM_CB, lib_to_asm_cb_t, + MRP_DATA_MEMBER(lib_to_asm_cb_t, instance_id, MRP_MSG_FIELD_UINT32), + MRP_DATA_MEMBER(lib_to_asm_cb_t, handle, MRP_MSG_FIELD_INT32), + MRP_DATA_MEMBER(lib_to_asm_cb_t, cb_result, MRP_MSG_FIELD_UINT32)); + + +#endif -- 2.7.4