aboutsummaryrefslogtreecommitdiffstats
path: root/src/audiomanager_proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audiomanager_proxy.c')
-rw-r--r--src/audiomanager_proxy.c697
1 files changed, 697 insertions, 0 deletions
diff --git a/src/audiomanager_proxy.c b/src/audiomanager_proxy.c
new file mode 100644
index 0000000..d1ace2c
--- /dev/null
+++ b/src/audiomanager_proxy.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <glib.h>
+#include <assert.h>
+#include <pthread.h>
+#include "audiomanager_proxy.h"
+#include "sm-helper.h"
+#include "dbus/audio_manager_interface.h"
+
+static AudiomanagerCommandinterface *am_cmd_bus;
+static AudiomanagerRoutinginterface *am_route_bus;
+static AudiomanagerRoutingSoundmanager *sm_adapter;
+static AudiomanagerRoutingSoundmanagerIface* sm_itf;
+static GDBusConnection* system_conn = NULL;
+
+static am_event _am_event = {0};
+static am_instruction _am_instruction = {0};
+static void *dbus_event_loop_run(void *args);
+
+/*
+********** Callback Function invoked by Audio Manager Command Interface**********
+*/
+static void _on_new_main_connection(AudiomanagerCommandinterface* interface,
+ GVariant* mainConnection)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+
+ guint16 mcid, srcid, sinkid;
+ gint16 delay, constate;
+ g_variant_get(
+ mainConnection,"(qqqnn)", &mcid, &srcid, &sinkid, &delay, &constate);
+
+ _am_event.on_new_main_connection(mcid, srcid, sinkid, delay, constate);
+}
+
+static void _on_removed_main_connection(
+ AudiomanagerCommandinterface* interface, guint16 mainConnectionID)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+
+ _am_event.on_removed_main_connection(mainConnectionID);
+}
+
+static void _on_main_connection_state_changed(
+ AudiomanagerCommandinterface* interface, guint16 connectionID, gint16 connectionState)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+ _am_event.on_main_connection_state_changed(connectionID, connectionState);
+}
+
+static void _on_volume_changed(
+ AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 volume)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+ _am_event.on_volume_changed(sinkID, volume);
+}
+
+static void _on_sink_mute_state_changed(
+ AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 mute)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+ _am_event.on_sink_mute_state_changed(sinkID, mute);
+}
+
+/*
+********** Callback Function invoked by Audio Manager Routing Interface**********
+*/
+static void _on_set_routing_ready(
+ AudiomanagerRoutinginterface* interface)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+ _am_event.on_set_routing_ready();
+}
+
+static void _on_set_routing_rundown(
+ AudiomanagerRoutinginterface* interface)
+{
+ AFB_DEBUG("%s is called",__FUNCTION__);
+ _am_event.on_set_routing_rundown();
+}
+
+static ErrorCode check_send_error(GError *err, guint16 result){
+ if(err != NULL){
+ return UNABLE_SEND;
+ }
+ return result;
+}
+
+static gboolean _on_async_abort(
+ AudiomanagerRoutingSoundmanager *object,
+ GDBusMethodInvocation *invocation,
+ guint16 arg_handle)
+{
+ AFB_DEBUG( "%s called", __FUNCTION__);
+ _am_instruction.on_async_abort((int)arg_handle);
+ return TRUE;
+}
+
+static gboolean _on_async_connect(
+ AudiomanagerRoutingSoundmanager *object,
+ GDBusMethodInvocation *invocation,
+ guint16 arg_handle,
+ guint16 arg_connectionID,
+ guint16 arg_sourceID,
+ guint16 arg_sinkID,
+ gint arg_connectionFormat)
+{
+ AFB_DEBUG( "%s called", __FUNCTION__);
+ int handle = (int)arg_handle;
+ int connection = (int)arg_connectionID;
+ int source = (int)arg_sourceID;
+ int sink = (int)arg_sinkID;
+ int connection_format = (int)arg_connectionFormat;
+ _am_instruction.on_async_connect(handle, connection,
+ source, sink, connection_format);
+ int ack_ok = 0;
+ ErrorCode ec = am_proxy_ack_connect(handle, connection, ack_ok);
+ if(ec == UNABLE_SEND)
+ {
+ AFB_ERROR( "Can't send ackConnect", __FUNCTION__);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean _on_async_disconnect(
+ AudiomanagerRoutingSoundmanager *object,
+ GDBusMethodInvocation *invocation,
+ guint16 arg_handle,
+ guint16 arg_connectionID)
+{
+ AFB_DEBUG( "%s called", __FUNCTION__);
+ int handle = (int)arg_handle;
+ int connection = (int)arg_connectionID;
+ _am_instruction.on_async_disconnect(handle, connection);
+ GError* err = NULL;
+ int ack_ok = 0;
+
+ ErrorCode ec = am_proxy_ack_disconnect(handle, connection, ack_ok);
+ if(ec == UNABLE_SEND)
+ {
+ AFB_ERROR( "Can't send ack to sound manager adapter %s", __FUNCTION__);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean _on_async_set_sink_volume(
+ AudiomanagerRoutingSoundmanager *object,
+ GDBusMethodInvocation *invocation,
+ guint16 arg_handle,
+ guint16 arg_sinkID,
+ gint16 arg_volume,
+ gint16 arg_ramp,
+ guint16 arg_time)
+{
+ AFB_DEBUG( "%s called", __FUNCTION__);
+ int handle = (int)arg_handle;
+ int sink = (int)arg_sinkID;
+ int volume = (int)arg_volume;
+ int ramp = (int)arg_ramp;
+ int time = (int)arg_time;
+ GError* err = NULL;
+ int ack_ok = 0;
+ ErrorCode ec = audiomanager_routinginterface_call_ack_set_sink_volume_sync(
+ am_route_bus,
+ arg_handle,
+ arg_volume,
+ ack_ok, NULL, &err);
+ if(ec == UNABLE_SEND);{
+ AFB_ERROR( "Can't send ack to sound manager adapter %s", __FUNCTION__);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean _on_async_set_source_state(
+ AudiomanagerRoutingSoundmanager *object,
+ GDBusMethodInvocation *invocation,
+ guint16 arg_handle,
+ guint16 arg_sourceID,
+ gint arg_sourceState)
+{
+ int handle = (int)arg_handle;
+ int source = (int)arg_sourceID;
+ int source_state = (int)arg_sourceState;
+ AFB_DEBUG( "%s called", __FUNCTION__);
+ _am_instruction.on_async_set_source_state(handle, source, source_state);
+ return TRUE;
+}
+
+/*
+********** API which calls audio manager API **********
+*/
+ErrorCode am_proxy_connect(int source, int sink, int *main_connection_id){
+ if(is_range_over_guint16(source) == OUT_RANGE || is_range_over_guint16(sink) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ AFB_DEBUG("Call %s: source:%d sink:%d", __FUNCTION__, source, sink);
+
+ guint16 connection_id = 0, ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_cmd_bus != NULL);
+
+ audiomanager_commandinterface_call_connect_sync(
+ am_cmd_bus,
+ (guint16)source, (guint16)sink,
+ &ret, &connection_id,
+ NULL, &err);
+ *main_connection_id = (int)connection_id;
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_disconnect(int main_connection_id){
+ AFB_DEBUG("Call %s: mainConnectionID:%d", __FUNCTION__, main_connection_id);
+ if(is_range_over_guint16(main_connection_id) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_disconnect_sync(
+ am_cmd_bus,
+ (guint16)main_connection_id,
+ &ret,
+ NULL, &err);
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_set_volume(int sink, int volume){
+ AFB_DEBUG("Call %s: sink:%d volume:%d", __FUNCTION__, sink, volume);
+ if(is_range_over_guint16(sink) == OUT_RANGE && is_range_over_gint16(volume) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_set_volume_sync(
+ am_cmd_bus,
+ (guint16)sink,
+ (gint16)volume,
+ &ret, NULL, &err);
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_volume_step(int sink, int volume){
+ AFB_DEBUG("Call %s: sink:%d volume:%d", __FUNCTION__, sink, volume);
+ if(is_range_over_guint16(sink) == OUT_RANGE && is_range_over_gint16(volume) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_volume_step_sync(
+ am_cmd_bus,
+ (guint16)sink,
+ (gint16)volume,
+ &ret, NULL, &err);
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_set_sink_mute_state(int sink, int mute_state){
+ AFB_DEBUG("Call %s: sink:%d mute_state:%d", __FUNCTION__, sink, mute_state);
+ if(is_range_over_guint16(sink) == OUT_RANGE || is_range_over_gint16(mute_state) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_set_sink_mute_state_sync(
+ am_cmd_bus,
+ (guint16)sink, (gint16)mute_state,
+ &ret, NULL, &err);
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_get_list_main_connections(GVariant** connection_list){
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ AFB_DEBUG("Call %s", __FUNCTION__);
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_get_list_main_connections_sync(
+ am_cmd_bus,
+ &ret,
+ connection_list,
+ NULL,
+ &err
+ );
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_get_list_main_sources(GVariant** source_list){
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ AFB_DEBUG("Call %s", __FUNCTION__);
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_get_list_main_sources_sync(
+ am_cmd_bus,
+ &ret,
+ source_list,
+ NULL,
+ &err
+ );
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_get_list_main_sinks(GVariant** sink_list){
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ AFB_DEBUG("Call %s", __FUNCTION__);
+ assert(am_cmd_bus != NULL);
+ audiomanager_commandinterface_call_get_list_main_sinks_sync(
+ am_cmd_bus,
+ &ret,
+ sink_list,
+ NULL,
+ &err
+ );
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_ack_connect(int handle, int connection_id, int usr_err){
+ AFB_DEBUG("Call %s handle:%d connectionID:%d error:%d", __FUNCTION__, handle, connection_id, usr_err);
+ if(is_range_over_guint16(handle) == OUT_RANGE ||
+ is_range_over_guint16(connection_id) == OUT_RANGE ||
+ is_range_over_guint16(usr_err) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+
+ assert(am_route_bus != NULL);
+ GError *err = NULL;
+
+ audiomanager_routinginterface_call_ack_connect_sync(
+ am_route_bus,
+ (guint16)handle,
+ (guint16)connection_id,
+ (guint16)usr_err, NULL, &err);
+ return OK;
+}
+
+ErrorCode am_proxy_ack_disconnect(int handle, int connection_id, int usr_err){
+ AFB_DEBUG("Call %s handle:%d connectionID:%d error:%d", __FUNCTION__, handle, connection_id, usr_err);
+ if(is_range_over_guint16(handle) == OUT_RANGE ||
+ is_range_over_guint16(connection_id) == OUT_RANGE ||
+ is_range_over_guint16(usr_err) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ assert(am_route_bus != NULL);
+ GError *err = NULL;
+ audiomanager_routinginterface_call_ack_disconnect_sync(
+ am_route_bus,
+ (guint16)handle,
+ (guint16)connection_id,
+ (guint16)usr_err,NULL, &err);
+ return OK;
+}
+
+ErrorCode am_proxy_ack_set_source_state(int handle, int usr_err){
+ AFB_DEBUG("Call %s handle:%d error:%d", __FUNCTION__, handle, usr_err);
+ if(is_range_over_guint16(handle) == OUT_RANGE ||
+ is_range_over_guint16(usr_err) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+
+ assert(am_route_bus != NULL);
+ GError *err = NULL;
+ audiomanager_routinginterface_call_ack_set_source_state_sync(
+ am_route_bus,
+ (guint16)handle,
+ (guint16)usr_err,
+ NULL, &err);
+ return OK;
+}
+
+ErrorCode am_proxy_register_source(GVariant *source_data, int *source){
+ AFB_DEBUG("Call %s", __FUNCTION__);
+ assert(am_route_bus != NULL);
+ guint16 ret = 0, g_source = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ audiomanager_routinginterface_call_register_source_sync(
+ am_route_bus,
+ source_data,
+ &g_source,
+ &ret,
+ NULL, &err);
+
+ *source = (int)g_source;
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_deregister_source(int source){
+ AFB_DEBUG("Call %s source:%d", __FUNCTION__, source);
+ if(is_range_over_guint16(source) == OUT_RANGE){
+ return OUT_RANGE;
+ }
+ guint16 ret = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_route_bus != NULL);
+ audiomanager_routinginterface_call_deregister_source_sync(
+ am_route_bus,
+ (guint16)source,
+ &ret,
+ NULL, &err
+ );
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+ErrorCode am_proxy_register_domain(GVariant* domain_data, int *domain){
+ guint16 ret = 0, g_domain = 0;
+ ErrorCode ec;
+ GError *err = NULL;
+
+ assert(am_route_bus != NULL);
+ assert(domain_data);
+ AFB_DEBUG("Call %s", __FUNCTION__);
+ audiomanager_routinginterface_call_register_domain_sync(
+ am_route_bus,
+ domain_data,
+ SOUND_MANAGER_BUS_NAME,
+ SOUND_MANAGER_PATH,
+ SOUND_MANAGER_RETURN_INTERFACE,
+ &g_domain, &ret,
+ NULL, &err);
+
+ *domain = (int)g_domain;
+ ec = check_send_error(err, ret);
+ return ec;
+}
+
+GVariant* create_domain_data(struct domain_data* domain){
+ /*
+ * This function doesn't check the range of guint32 or gint16
+ * Soundmanager must keep the input data is between the size of type.
+ * This function is considered to be only used by soundmanager.
+ */
+ GVariantBuilder builder;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(qsssbbn)"));
+ g_variant_builder_add (&builder, "q", (guint16)domain->domainID);
+ g_variant_builder_add (&builder, "s", domain->name);
+ g_variant_builder_add (&builder, "s", domain->busname);
+ g_variant_builder_add (&builder, "s", domain->nodename);
+ g_variant_builder_add (&builder, "b", (gboolean)domain->early);
+ g_variant_builder_add (&builder, "b", (gboolean)domain->complete);
+ g_variant_builder_add (&builder, "n", (gint16)domain->state);
+ AFB_DEBUG("create domainData");
+ return g_variant_builder_end (&builder);
+}
+
+GVariant* create_source_data(int sourceID, int domainID, const char* appname, int sourceClassID,
+ int sourceState, int volume, bool visible, struct availability_s availables,
+ int interrupt, struct sound_property_s soundPropertyList, int connectionFormatList,
+ struct main_sound_property_s mainPropertyList, struct notification_config_s NConfRouting,
+ struct notification_config_s NConfCommand)
+{
+ GVariantBuilder builder;
+ if(is_range_over_guint16(sourceID) == OUT_RANGE ||
+ is_range_over_guint16(domainID) == OUT_RANGE ||
+ is_range_over_gint16(volume) == OUT_RANGE ||
+ is_range_over_guint16(interrupt) == OUT_RANGE ||
+ is_range_over_gint16(soundPropertyList.value) == OUT_RANGE ||
+ is_range_over_gint16(mainPropertyList.value) == OUT_RANGE ||
+ is_range_over_gint16(NConfRouting.parameter) == OUT_RANGE ||
+ is_range_over_gint16(NConfCommand.parameter) == OUT_RANGE)
+ {
+ return NULL;
+ }
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(qqsqinb(ii)qa(in)aia(in)a(iin)a(iin))"));
+ g_variant_builder_add (&builder, "q", (guint16)sourceID);
+ g_variant_builder_add (&builder, "q", (guint16)domainID);
+ g_variant_builder_add (&builder, "s", appname);
+ g_variant_builder_add (&builder, "q", (guint16)sourceClassID);
+ g_variant_builder_add (&builder, "i", (gint32)sourceState);
+ g_variant_builder_add (&builder, "n", (gint16)volume);
+ g_variant_builder_add (&builder, "b", (gboolean)visible);
+ g_variant_builder_add (&builder, "(ii)", (gint32)availables.availability, (gint32)availables.avalilable_reason);
+ g_variant_builder_add (&builder, "q", (guint16)interrupt);
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a(in)"));
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("(in)"));
+ g_variant_builder_add (&builder, "i", (gint32)soundPropertyList.type);
+ g_variant_builder_add (&builder, "n", (gint16)soundPropertyList.value);
+ g_variant_builder_close(&builder);
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("ai"));
+ g_variant_builder_add (&builder, "i", (gint32)connectionFormatList);
+ g_variant_builder_close (&builder);
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a(in)"));
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("(in)"));
+ g_variant_builder_add (&builder, "i", (gint32)mainPropertyList.type);
+ g_variant_builder_add (&builder, "n", (gint16)mainPropertyList.value);
+ g_variant_builder_close (&builder);
+ g_variant_builder_close(&builder);
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a(iin)"));
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("(iin)"));
+ g_variant_builder_add (&builder, "i", (gint32)NConfRouting.type);
+ g_variant_builder_add (&builder, "i", (gint32)NConfRouting.status);
+ g_variant_builder_add (&builder, "n", (gint16)NConfRouting.parameter);
+ g_variant_builder_close(&builder);
+ g_variant_builder_close (&builder);
+
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a(iin)"));
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("(iin)"));
+ g_variant_builder_add (&builder, "i", (gint32)NConfCommand.type);
+ g_variant_builder_add (&builder, "i", (gint32)NConfCommand.status);
+ g_variant_builder_add (&builder, "n", (gint16)NConfCommand.parameter);
+ g_variant_builder_close(&builder);
+ g_variant_builder_close (&builder);
+
+ AFB_DEBUG("create sourceData");
+ return g_variant_builder_end (&builder);
+}
+
+static void *dbus_event_loop_run(void *args)
+{
+ GMainLoop* loop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(loop);
+}
+
+ErrorCode initialize_proxy(){
+ if(am_cmd_bus || am_route_bus)
+ {
+ return NOT_INITIALIZED;
+ }
+ am_cmd_bus = audiomanager_commandinterface_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ AM_NAME,
+ AM_CMD_PATH,
+ NULL,
+ NULL
+ );
+ if(!am_cmd_bus){
+ AFB_ERROR("Failed to create command interface");
+ }
+ am_route_bus = audiomanager_routinginterface_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ AM_NAME,
+ AM_ROUTE_PATH,
+ NULL,
+ NULL
+ );
+ if(!am_route_bus){
+ AFB_ERROR("Failed to create routing interface");
+ }
+ return (am_cmd_bus && am_route_bus) ? OK : UNABLE_SEND;
+}
+
+void close_proxy(){
+ if(am_cmd_bus) free(am_cmd_bus);
+ if(am_route_bus) free(am_route_bus);
+}
+
+void set_event_callback(const am_event* callback){
+ assert(am_cmd_bus != NULL);
+ assert(am_route_bus != NULL);
+ /* initialize signal from audio manager command interface */
+ _am_event.on_main_connection_state_changed = callback->on_main_connection_state_changed;
+ _am_event.on_new_main_connection = callback->on_new_main_connection;
+ _am_event.on_removed_main_connection = callback->on_removed_main_connection;
+ _am_event.on_set_routing_ready = callback->on_set_routing_ready;
+ _am_event.on_set_routing_rundown = callback->on_set_routing_rundown;
+ _am_event.on_sink_mute_state_changed = callback->on_sink_mute_state_changed;
+ _am_event.on_volume_changed = callback->on_volume_changed;
+
+ g_signal_connect(am_cmd_bus, "volume_changed",
+ G_CALLBACK(_on_volume_changed), NULL);
+ g_signal_connect(am_cmd_bus, "new_main_connection",
+ G_CALLBACK(_on_new_main_connection), NULL);
+ g_signal_connect(am_cmd_bus, "removed_main_connection",
+ G_CALLBACK(_on_removed_main_connection),NULL);
+ g_signal_connect(am_cmd_bus, "sink_mute_state_changed",
+ G_CALLBACK(_on_sink_mute_state_changed),NULL);
+ g_signal_connect(am_cmd_bus, "main_connection_state_changed",
+ G_CALLBACK(_on_main_connection_state_changed), NULL);
+ g_signal_connect(am_route_bus, "set_routing_ready",
+ G_CALLBACK(_on_set_routing_ready), NULL);
+ g_signal_connect(am_route_bus, "set_routing_rundown",
+ G_CALLBACK(_on_set_routing_rundown), NULL);
+}
+
+static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data){
+ GError* error = NULL;
+ AFB_DEBUG("%s is called", __FUNCTION__);
+
+ sm_adapter = audiomanager_routing_soundmanager_skeleton_new();
+ sm_itf = AUDIOMANAGER_ROUTING_SOUNDMANAGER_GET_IFACE(sm_adapter);
+
+ /* initialize sound manager adapter */
+ sm_itf->handle_async_abort = _on_async_abort;
+ sm_itf->handle_async_connect = _on_async_connect;
+ sm_itf->handle_async_disconnect = _on_async_disconnect;
+ sm_itf->handle_async_set_sink_volume = _on_async_set_sink_volume;
+ sm_itf->handle_async_set_source_state = _on_async_set_source_state;
+
+ int sigret = g_signal_connect(sm_adapter, "handle-async-abort", G_CALLBACK(_on_async_abort),NULL);
+ sigret = g_signal_connect(sm_adapter, "handle-async-connect", G_CALLBACK(_on_async_connect),NULL);
+ sigret = g_signal_connect(sm_adapter, "handle-async-disconnect", G_CALLBACK(_on_async_disconnect),NULL);
+ sigret = g_signal_connect(sm_adapter, "handle-async-set-sink-volume", G_CALLBACK(_on_async_set_sink_volume),NULL);
+ sigret = g_signal_connect(sm_adapter, "handle-async-set-source-state", G_CALLBACK(_on_async_set_source_state),NULL);
+
+ AFB_DEBUG("register %s", AUDIOMANAGER_ROUTING_SOUNDMANAGER_SKELETON(sm_adapter));
+
+ gboolean rc = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(sm_adapter), connection, SOUND_MANAGER_PATH, &error);
+ AFB_DEBUG("export soundmanager path result: %d", rc);
+ if (FALSE == rc)
+ {
+ AFB_ERROR( "failed to export");
+ g_error_free(error);
+ g_object_unref(connection);
+ }
+}
+
+static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data){
+ AFB_DEBUG("%s is called", __FUNCTION__);
+}
+
+static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data){
+ AFB_DEBUG("bus name is lost");
+ // TODO: soundmanager should register current status?
+}
+
+ErrorCode open_soundmanager_interface(const am_instruction *callback){
+ _am_instruction.on_async_abort = callback->on_async_abort;
+ _am_instruction.on_async_connect = callback->on_async_connect;
+ _am_instruction.on_async_disconnect = callback->on_async_disconnect;
+ _am_instruction.on_async_set_sink_volume = callback->on_async_set_sink_volume;
+ _am_instruction.on_async_set_source_state = callback->on_async_set_source_state;
+
+ guint owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, SOUND_MANAGER_BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired, on_name_acquired, on_name_lost, NULL/* (gpointer)callback */, NULL);
+ // see https://developer.gnome.org/gio/stable/gio-Owning-Bus-Names.html#g-bus-own-name
+
+ pthread_t thread_id;
+ int ret = pthread_create(&thread_id, NULL, dbus_event_loop_run, NULL);
+ if(ret != 0)
+ {
+ AFB_ERROR("Failed to create thread");
+ g_bus_unown_name(owner_id);
+ close_soundmanager_inerface();
+ close_proxy();
+ return NOT_INITIALIZED;
+ }
+ return OK;
+}
+
+void close_soundmanager_inerface(){
+ g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(sm_adapter));
+}