2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <sys/types.h>
37 #include <sys/socket.h>
43 #include <audio-session-manager.h>
45 #include <murphy/common.h>
46 #include <murphy/core.h>
48 #include <murphy/resource/client-api.h>
50 #include "resource-asm/asm-bridge.h"
57 uint32_t current_handle;
59 bool monitor; /* if the client has set up a monitor resource */
69 /* asm-bridge management */
71 mrp_transport_t *mt; /* listening transport */
72 mrp_transport_t *t; /* connected transport */
75 /* resource management */
77 mrp_resource_client_t *resource_client;
80 char *playback_resource;
81 char *recording_resource;
84 uint32_t current_request;
86 /* murphy integration */
87 mrp_sighandler_t *sighandler;
95 request_type_server_event
103 mrp_resource_set_t *rset;
108 request_type_t rtype;
112 } resource_set_data_t;
119 ARG_ASM_TPORT_ADDRESS,
120 ARG_ASM_PLAYBACK_RESOURCE,
121 ARG_ASM_RECORDING_RESOURCE,
124 static int tport_setup(const char *address, asm_data_t *ctx);
126 static void *u_to_p(uint32_t u)
128 #ifdef __SIZEOF_POINTER__
129 #if __SIZEOF_POINTER__ == 8
140 static uint32_t p_to_u(const void *p)
142 #ifdef __SIZEOF_POINTER__
143 #if __SIZEOF_POINTER__ == 8
145 uint64_t big = (uint64_t) p;
146 o = big & 0xffffffff;
148 uint32_t o = (uint32_t) p;
157 static int int_comp(const void *key1, const void *key2)
163 static uint32_t int_hash(const void *key)
169 static void dump_incoming_msg(lib_to_asm_t *msg, asm_data_t *ctx)
173 mrp_log_info(" --> client id: %u", msg->instance_id);
174 mrp_log_info(" --> data handle: %d", msg->handle);
175 mrp_log_info(" --> request id: 0x%04x", msg->request_id);
176 mrp_log_info(" --> sound event: 0x%04x", msg->sound_event);
177 mrp_log_info(" --> system resource: 0x%04x", msg->system_resource);
178 mrp_log_info(" --> state: 0x%04x", msg->sound_state);
181 int n_cookie = msg->n_cookie_bytes;
184 mrp_log_info(" --> cookie: ")
185 for (i = 0; i < n_cookie, i++) {
186 mrp_log_info("0x%02x ", msg->cookie[i]);
195 static void dump_outgoing_msg(asm_to_lib_t *msg, asm_data_t *ctx)
199 mrp_log_info(" <-- client id: %u", msg->instance_id);
200 mrp_log_info(" <-- alloc handle: %d", msg->alloc_handle);
201 mrp_log_info(" <-- command handle: %d", msg->cmd_handle);
202 mrp_log_info(" <-- sound command: 0x%04x", msg->result_sound_command);
203 mrp_log_info(" <-- state: 0x%04x", msg->result_sound_state);
204 mrp_log_info(" <-- check privilege: %s",
205 msg->check_privilege ? "TRUE" : "FALSE");
209 static uint32_t encode_pid_handle(uint32_t pid, uint32_t handle) {
211 uint32_t max_pid = 4194304; /* 2^22 */
212 uint32_t max_handle = 1024; /* 2^10 */
214 if (pid > max_pid || handle > max_handle) {
218 return pid | (handle << 22);
221 static uint32_t get_pid(uint32_t data) {
222 uint32_t pid_mask = 0xffffffff >> 10;
224 return data & pid_mask;
228 static uint32_t get_handle(uint32_t data) {
235 static void htbl_free_set(void *key, void *object)
237 resource_set_data_t *d = object;
242 mrp_resource_set_destroy(d->rset);
248 static client_t *create_client(uint32_t pid) {
249 client_t *client = mrp_allocz(sizeof(client_t));
250 mrp_htbl_config_t set_conf;
255 set_conf.comp = int_comp;
256 set_conf.hash = int_hash;
257 set_conf.free = htbl_free_set;
258 set_conf.nbucket = 0;
259 set_conf.nentry = 10;
261 client->sets = mrp_htbl_create(&set_conf);
269 client->current_handle = 1;
276 static void event_cb(uint32_t request_id, mrp_resource_set_t *set, void *data)
278 resource_set_data_t *d = data;
279 asm_data_t *ctx = d->ctx;
281 mrp_log_info("Event CB: id %u, set %p", request_id, set);
282 mrp_log_info("Resource set %u.%u", d->pid, d->handle);
283 mrp_log_info("Advice 0x%08x, Grant 0x%08x",
284 mrp_get_resource_set_advice(d->rset),
285 mrp_get_resource_set_grant(d->rset));
288 case request_type_acquire:
291 mrp_log_info("callback for acquire request %u", request_id);
293 /* expecting next server events */
294 d->rtype = request_type_server_event;
296 reply.instance_id = d->pid;
297 reply.check_privilege = TRUE;
298 reply.alloc_handle = d->handle;
299 reply.cmd_handle = d->handle;
301 reply.result_sound_command = ASM_COMMAND_NONE;
303 /* TODO: check the mask properly */
304 if (mrp_get_resource_set_grant(d->rset))
305 reply.result_sound_state = ASM_STATE_PLAYING;
307 reply.result_sound_state = ASM_STATE_STOP;
309 d->rtype = request_type_server_event;
311 dump_outgoing_msg(&reply, ctx);
312 mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB);
315 case request_type_release:
318 mrp_log_info("callback for release request %u", request_id);
320 /* expecting next server events */
321 d->rtype = request_type_server_event;
323 reply.instance_id = d->pid;
324 reply.check_privilege = TRUE;
325 reply.alloc_handle = d->handle;
326 reply.cmd_handle = d->handle;
328 reply.result_sound_command = ASM_COMMAND_NONE;
329 reply.result_sound_state = ASM_STATE_STOP;
331 d->rtype = request_type_server_event;
333 /* stop processing server_events */
336 dump_outgoing_msg(&reply, ctx);
337 mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB);
340 case request_type_server_event:
342 asm_to_lib_cb_t reply;
343 mrp_log_info("callback for no request %u", request_id);
345 reply.instance_id = d->pid;
346 reply.handle = d->handle;
348 /* TODO: get the client and see if there is the monitor
349 * resource present. If yes, tell the availability state changes
352 if (d->request_id == 0) {
353 /* We either haven't requested any resources or have
354 * given up the resources. Filter out events. */
358 /* TODO: check if the d->rset state has actually changed -> only
359 * process server side notifications in that case */
361 if (mrp_get_resource_set_grant(d->rset)) {
362 reply.sound_command = ASM_COMMAND_RESUME;
363 /* ASM doesn't send callback to RESUME commands */
364 reply.callback_expected = FALSE;
367 reply.sound_command = ASM_COMMAND_PAUSE;
368 reply.callback_expected = TRUE;
371 /* FIXME: the player-player case needs to be solved here? */
372 reply.event_source = ASM_EVENT_SOURCE_OTHER_PLAYER_APP;
374 mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB_CB);
382 static asm_to_lib_t *process_msg(lib_to_asm_t *msg, asm_data_t *ctx)
384 pid_t pid = msg->instance_id;
388 reply = mrp_allocz(sizeof(asm_to_lib_t));
393 reply->instance_id = pid;
394 reply->check_privilege = TRUE;
396 reply->alloc_handle = msg->handle;
397 reply->cmd_handle = msg->handle;
399 reply->result_sound_command = ASM_COMMAND_NONE;
400 reply->result_sound_state = ASM_STATE_IGNORE;
402 switch(msg->request_id) {
403 case ASM_REQUEST_REGISTER:
407 char *resource = "invalid";
409 mrp_log_info("REQUEST: REGISTER");
411 /* see if the process already has a client object */
412 client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
415 client = create_client(pid);
416 mrp_htbl_insert(ctx->clients, u_to_p(pid), client);
420 /* From Murphy point of view this is actually an error case,
421 * since the application can only belong to one class. This is
422 * a Murphy limitation and should be fixed later. */
424 mrp_log_error("Application tried to register twice");
429 switch (msg->sound_event) {
432 case ASM_EVENT_SHARE_MMPLAYER:
436 case ASM_EVENT_SHARE_MMCAMCORDER:
440 case ASM_EVENT_SHARE_MMSOUND:
444 case ASM_EVENT_SHARE_OPENAL:
447 case ASM_EVENT_SHARE_AVSYSTEM:
450 case ASM_EVENT_EXCLUSIVE_MMPLAYER:
454 case ASM_EVENT_EXCLUSIVE_MMCAMCORDER:
458 case ASM_EVENT_EXCLUSIVE_MMSOUND:
462 case ASM_EVENT_EXCLUSIVE_OPENAL:
465 case ASM_EVENT_EXCLUSIVE_AVSYSTEM:
468 case ASM_EVENT_NOTIFY:
475 case ASM_EVENT_SHARE_FMRADIO:
478 case ASM_EVENT_EXCLUSIVE_FMRADIO:
481 case ASM_EVENT_EARJACK_UNPLUG:
482 resource = "earjack";
485 case ASM_EVENT_ALARM:
488 case ASM_EVENT_VIDEOCALL:
492 case ASM_EVENT_MONITOR:
493 resource = "monitor";
496 case ASM_EVENT_RICH_CALL:
504 if (strcmp(resource, "invalid") == 0) {
505 mrp_log_error("unknown resource type: %d", msg->sound_event);
509 uint32_t handle = client->current_handle++;
510 resource_set_data_t *d = mrp_allocz(sizeof(resource_set_data_t));
518 d->rtype = request_type_server_event;
521 if (strcmp(resource, "earjack") == 0) {
522 mrp_log_info("earjack status request was received");
525 else if (strcmp(resource, "monitor") == 0) {
526 mrp_log_info("monitor resource was received");
527 /* TODO: tell the available state changes to this pid
528 * via the monitor resource. */
529 client->monitor = TRUE;
533 /* a normal resource request */
535 d->rset = mrp_resource_set_create(ctx->resource_client, 0,
539 mrp_log_error("Failed to create resource set!");
544 if (mrp_resource_set_add_resource(d->rset,
545 ctx->playback_resource, shared, NULL, TRUE) < 0) {
546 mrp_log_error("Failed to add playback resource!");
547 mrp_resource_set_destroy(d->rset);
552 if (mrp_resource_set_add_resource(d->rset,
553 ctx->recording_resource, shared, NULL, TRUE) < 0) {
554 mrp_log_error("Failed to add recording resource!");
555 mrp_resource_set_destroy(d->rset);
560 if (mrp_application_class_add_resource_set(resource,
561 ctx->zone, d->rset, 0) < 0) {
562 mrp_log_error("Failed to put the rset in a class!");
563 mrp_resource_set_destroy(d->rset);
569 mrp_htbl_insert(client->sets, u_to_p(handle), d);
572 reply->alloc_handle = handle;
573 reply->cmd_handle = reply->alloc_handle;
575 reply->result_sound_state = ASM_STATE_WAITING;
576 reply->result_sound_command = ASM_COMMAND_NONE;
581 case ASM_REQUEST_UNREGISTER:
583 client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
585 mrp_log_info("REQUEST: UNREGISTER");
588 resource_set_data_t *d;
590 d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle));
592 mrp_log_error("set '%u.%u' not found", pid, msg->handle);
597 /* this is a resource request with no associated
598 * murphy resource, meaning a monitor or earjack. */
600 mrp_log_info("unregistering special resource %s",
601 d->monitor ? "monitor" : "earjack");
604 client->monitor = FALSE;
606 /* TODO: what to do with the earjack unregister case? */
609 /* the resource set id destroyed when it's removed from the
611 mrp_htbl_remove(client->sets, u_to_p(msg->handle), TRUE);
614 if (client->n_sets <= 0) {
615 mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE);
620 /* TODO: free memory and check if the resource set is empty when
621 * the resource library supports it */
623 /* no reply needed! */
628 case ASM_REQUEST_SETSTATE:
630 client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
632 resource_set_data_t *d;
634 mrp_log_info("REQUEST: SET STATE");
637 mrp_log_error("client '%u' not found", pid);
641 d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle));
642 if (!d || !d->rset) {
643 mrp_log_error("set '%u.%u' not found", pid, msg->handle);
647 d->request_id = ++ctx->current_request;
649 switch(msg->sound_state) {
650 case ASM_STATE_PLAYING:
652 d->rtype = request_type_acquire;
654 mrp_log_info("requesting acquisition of playback rights"
655 " for set '%u.%u' (id: %u)", pid, msg->handle,
658 mrp_resource_set_acquire(d->rset, d->request_id);
663 case ASM_STATE_PAUSE:
665 d->rtype = request_type_release;
667 mrp_log_info("requesting release of playback rights for"
668 " set '%u.%u' (id: %u)", pid, msg->handle,
671 mrp_resource_set_release(d->rset, d->request_id);
677 mrp_log_error("Unknown state: %d", msg->sound_state);
685 case ASM_REQUEST_GETSTATE:
686 mrp_log_info("REQUEST: GET STATE");
687 /* TODO: get the current resource state for msg->sound_event (which
688 * is the application class). Put it to reply->result_sound_state
691 case ASM_REQUEST_GETMYSTATE:
692 mrp_log_info("REQUEST: GET MY STATE");
693 /* TODO: get the current state for the process (resource set). Put
694 * it to reply->result_sound_state field. */
696 case ASM_REQUEST_EMERGENT_EXIT:
698 client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
700 mrp_log_info("REQUEST: EMERGENCY EXIT");
703 mrp_log_error("client '%u' not found", pid);
707 mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE);
712 case ASM_REQUEST_SET_SUBSESSION:
713 mrp_log_info("REQUEST: SET SUBSESSION");
715 case ASM_REQUEST_GET_SUBSESSION:
716 mrp_log_info("REQUEST: GET SUBSESSION");
719 mrp_log_info("REQUEST: UNKNOWN REQUEST");
726 /* TODO: need to write some sort of message back? */
735 static void process_cb_msg(lib_to_asm_cb_t *msg, asm_data_t *ctx)
741 /* TODO: this function might tell something to the resource library */
743 switch (msg->cb_result) {
744 case ASM_CB_RES_IGNORE:
747 case ASM_CB_RES_NONE:
750 case ASM_CB_RES_PAUSE:
753 case ASM_CB_RES_PLAYING:
756 case ASM_CB_RES_STOP:
760 mrp_log_error("unknown callback state %d", msg->cb_result);
764 mrp_log_info("client %d.%u ended in state '%s' after callback",
765 msg->instance_id, msg->handle, str);
769 static void recvdatafrom_evt(mrp_transport_t *t, void *data, uint16_t tag,
770 mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
772 asm_data_t *ctx = user_data;
780 lib_to_asm_t *msg = data;
783 /* client requests something from us */
785 dump_incoming_msg(msg, ctx);
787 reply = process_msg(msg, ctx);
789 dump_outgoing_msg(reply, ctx);
790 mrp_transport_senddata(t, reply, TAG_ASM_TO_LIB);
794 case TAG_LIB_TO_ASM_CB:
796 lib_to_asm_cb_t *msg = data;
798 /* client tells us which state it entered after preemption */
800 process_cb_msg(msg, ctx);
805 mrp_log_error("Unknown message received!");
809 mrp_data_free(data, tag);
813 static void recvdata_evt(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
815 recvdatafrom_evt(t, data, tag, NULL, 0, user_data);
820 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
823 asm_data_t *ctx = user_data;
827 mrp_log_info("closed!");
829 mrp_transport_disconnect(t);
830 mrp_transport_destroy(t);
834 /* TODO: start the listening socket again and relaunch the binary? */
839 static void connection_evt(mrp_transport_t *lt, void *user_data)
841 asm_data_t *ctx = user_data;
843 mrp_log_info("connection!");
846 mrp_log_error("Already connected");
849 ctx->t = mrp_transport_accept(lt, ctx, 0);
852 /* close the listening socket, since we only have one client */
854 mrp_transport_destroy(lt);
860 static int tport_setup(const char *address, asm_data_t *ctx)
868 static mrp_transport_evt_t evt = {
869 { .recvdata = recvdata_evt },
870 { .recvdatafrom = recvdatafrom_evt },
871 .closed = closed_evt,
872 .connection = connection_evt
875 alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype);
878 mrp_log_error("Error resolving transport address");
882 /* remove the old socket if present */
884 if (strcmp(atype, "unxs") == 0) {
885 char *path = addr.unx.sun_path;
886 if (path[0] == '/') {
887 /* if local socket and file exists, remove it */
888 if (stat(path, &statbuf) == 0) {
889 if (S_ISSOCK(statbuf.st_mode)) {
890 if (unlink(path) < 0) {
891 mrp_log_error("error removing the socket");
896 mrp_log_error("a file where the socket should be created");
903 ctx->mt = mrp_transport_create(ctx->ctx->ml, atype, &evt, ctx,
904 MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK);
906 if (ctx->mt == NULL) {
907 mrp_log_error("Failed to create the transport");
911 if (!mrp_transport_bind(ctx->mt, &addr, alen)) {
912 mrp_log_error("Failed to bind the transport to address '%s'", address);
917 if (!mrp_transport_listen(ctx->mt, 5)) {
918 mrp_log_error("Failed to listen to transport");
926 mrp_transport_destroy(ctx->mt);
933 static void signal_handler(mrp_mainloop_t *ml, mrp_sighandler_t *h,
934 int signum, void *user_data)
936 asm_data_t *ctx = user_data;
941 if (signum == SIGCHLD) {
942 /* wait for the child */
946 mrp_log_info("Received SIGCHLD, waiting for asm-bridge");
948 ret = waitpid(ctx->pid, NULL, WNOHANG);
950 if (ret == ctx->pid) {
951 mrp_log_warning("asm-bridge process died");
958 static void htbl_free_client(void *key, void *object)
962 client_t *client = object;
964 mrp_htbl_destroy(client->sets, TRUE);
966 /* TODO: free memory when resource API allows that */
970 static int close_fds()
974 int newin, newout, newerr;
976 /* Closing all file descriptors in a protable way is tricky, so improve
977 this function as we go. */
979 maxfd = sysconf(_SC_OPEN_MAX);
981 for (i = 0; i < maxfd; i++) {
982 if (i != fileno(stdin) && i != fileno(stdout) && i != fileno(stderr))
986 /* redirect the streams to /dev/null */
988 newin = open("/dev/null", O_RDONLY);
989 newout = open("/dev/null", O_WRONLY);
990 newerr = open("/dev/null", O_WRONLY);
992 if (newin < 0 || newout < 0 || newerr < 0)
995 if (dup2(newin, fileno(stdin)) < 0 ||
996 dup2(newout, fileno(stdout)) < 0 ||
997 dup2(newerr, fileno(stderr)) < 0)
1007 static int asm_init(mrp_plugin_t *plugin)
1009 mrp_plugin_arg_t *args = plugin->args;
1010 asm_data_t *ctx = mrp_allocz(sizeof(asm_data_t));
1012 mrp_htbl_config_t client_conf;
1018 ctx->ctx = plugin->ctx;
1019 ctx->address = args[ARG_ASM_TPORT_ADDRESS].str;
1020 ctx->binary = args[ARG_ASM_BRIDGE].str;
1021 ctx->zone = args[ARG_ASM_ZONE].str;
1023 ctx->playback_resource = args[ARG_ASM_PLAYBACK_RESOURCE].str;
1024 ctx->recording_resource = args[ARG_ASM_RECORDING_RESOURCE].str;
1026 /* create the transport and put it to listen mode */
1028 if (!mrp_msg_register_type(&asm_to_lib_descr)) {
1029 mrp_log_error("Failed to register message type asm_to_lib");
1033 if (!mrp_msg_register_type(&lib_to_asm_descr)) {
1034 mrp_log_error("Failed to register message type lib_to_asm");
1038 if (!mrp_msg_register_type(&asm_to_lib_cb_descr)) {
1039 mrp_log_error("Failed to register message type asm_to_lib_cb");
1043 if (!mrp_msg_register_type(&lib_to_asm_cb_descr)) {
1044 mrp_log_error("Failed to register message type lib_to_asm_cb");
1048 if (tport_setup(ctx->address, ctx) < 0) {
1052 /* listen to SIGCHLD signal */
1054 ctx->sighandler = mrp_add_sighandler(plugin->ctx->ml, SIGCHLD, signal_handler, ctx);
1056 if (!ctx->sighandler) {
1057 mrp_log_error("Failed to register signal handling");
1061 client_conf.comp = int_comp;
1062 client_conf.hash = int_hash;
1063 client_conf.free = htbl_free_client;
1064 client_conf.nbucket = 0;
1065 client_conf.nentry = 10;
1067 ctx->clients = mrp_htbl_create(&client_conf);
1069 if (!ctx->clients) {
1070 mrp_log_error("Error creating resource set hash table");
1074 /* create the client structure towards Murphy */
1076 ctx->resource_client = mrp_resource_client_create("ASM", ctx);
1078 if (!ctx->resource_client) {
1079 mrp_log_error("Failed to get a resource client");
1083 /* fork-exec the asm bridge binary */
1085 mrp_log_info("going to fork!");
1090 mrp_log_error("error launching asm-bridge");
1093 else if (pid == 0) {
1095 if (close_fds() < 0) {
1096 mrp_log_error("close_fds() failed");
1099 execl(ctx->binary, ctx->binary, ctx->address, NULL);
1105 mrp_log_info("child pid is %d", pid);
1118 kill(ctx->pid, SIGTERM);
1122 if (ctx->sighandler) {
1123 mrp_del_sighandler(ctx->sighandler);
1124 ctx->sighandler = NULL;
1127 if (ctx->resource_client) {
1128 mrp_resource_client_destroy(ctx->resource_client);
1137 static void asm_exit(mrp_plugin_t *plugin)
1139 asm_data_t *ctx = plugin->data;
1142 kill(ctx->pid, SIGTERM);
1147 mrp_transport_disconnect(ctx->mt);
1148 mrp_transport_destroy(ctx->mt);
1153 mrp_transport_disconnect(ctx->t);
1154 mrp_transport_destroy(ctx->t);
1158 if (ctx->sighandler) {
1159 mrp_del_sighandler(ctx->sighandler);
1160 ctx->sighandler = NULL;
1164 mrp_htbl_destroy(ctx->clients, TRUE);
1165 ctx->clients = NULL;
1168 mrp_resource_client_destroy(ctx->resource_client);
1171 plugin->data = NULL;
1175 #define ASM_DESCRIPTION "A plugin to handle SLP Audio Session Manager client requests."
1176 #define ASM_HELP "Audio Session Manager backend"
1177 #define ASM_VERSION MRP_VERSION_INT(0, 0, 1)
1178 #define ASM_AUTHORS "Ismo Puustinen <ismo.puustinen@intel.com>"
1180 static mrp_plugin_arg_t args[] = {
1181 MRP_PLUGIN_ARGIDX(ARG_ASM_BRIDGE, STRING, "asm_bridge", "/usr/sbin/asm-bridge"),
1182 MRP_PLUGIN_ARGIDX(ARG_ASM_ZONE, STRING, "zone", "default"),
1183 MRP_PLUGIN_ARGIDX(ARG_ASM_TPORT_ADDRESS, STRING, "tport_address", "unxs:/tmp/murphy/asm"),
1184 MRP_PLUGIN_ARGIDX(ARG_ASM_PLAYBACK_RESOURCE, STRING, "playback_resource", "audio_playback"),
1185 MRP_PLUGIN_ARGIDX(ARG_ASM_RECORDING_RESOURCE, STRING, "recording_resource", "audio_recording"),
1189 MURPHY_REGISTER_PLUGIN("resource-asm",
1190 ASM_VERSION, ASM_DESCRIPTION, ASM_AUTHORS, ASM_HELP,
1191 MRP_SINGLETON, asm_init, asm_exit,
1192 args, MRP_ARRAY_SIZE(args),
1193 NULL, 0, NULL, 0, NULL);