/* * 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 #include #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 _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(NULL, 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(NULL, 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(NULL, connectionID, connectionState); } static void _on_volume_changed( AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 volume) { AFB_DEBUG("%s is called",__FUNCTION__); _am_event.on_volume_changed(NULL, 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(NULL, 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(NULL); } static void _on_set_routing_rundown( AudiomanagerRoutinginterface* interface) { AFB_DEBUG("%s is called",__FUNCTION__); _am_event.on_set_routing_rundown(NULL); } static ErrorCode check_send_error(GError *err, guint16 result){ if(err != NULL){ return UNABLE_SEND; } return result; } /* ********** Callback Function invoked by Sound Manager Adapter Interface********** * * For now, there may be no need to send events to applications from these invocation. * Sound Manager just sends ack to Audio Manager in charge of applications. * */ static gboolean _on_async_abort( AudiomanagerRoutingSoundmanager *object, GDBusMethodInvocation *invocation, guint16 arg_handle) { AFB_DEBUG( "%s called", __FUNCTION__); _am_instruction.on_async_abort(NULL, (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(NULL, handle, connection, source, sink, connection_format); /* GError must be initialized here because it is same as grobal errno, so if afb_event_push is failed due to something, number will be changed */ 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(NULL, 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(NULL, handle, source, source_state); return TRUE; } 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; } guint16 connection_id = -1, ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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){ if(is_range_over_guint16(main_connection_id) == OUT_RANGE){ return OUT_RANGE; } guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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){ if(is_range_over_guint16(sink) == OUT_RANGE && is_range_over_gint16(volume) == OUT_RANGE){ return OUT_RANGE; } guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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){ if(is_range_over_guint16(sink) == OUT_RANGE && is_range_over_gint16(volume) == OUT_RANGE){ return OUT_RANGE; } guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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){ if(is_range_over_guint16(sink) == OUT_RANGE || is_range_over_gint16(mute_state) == OUT_RANGE){ return OUT_RANGE; } guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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 = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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 = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); 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 = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_cmd_bus); audiomanager_commandinterface_call_get_list_main_sources_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){ 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); 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){ 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); 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){ if(is_range_over_guint16(handle) == OUT_RANGE || is_range_over_guint16(usr_err) == OUT_RANGE){ return OUT_RANGE; } assert(!am_route_bus); 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){ assert(!am_route_bus); guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; audiomanager_routinginterface_call_register_source_sync( am_route_bus, source_data, source, &ret, NULL, &err); g_variant_unref(source_data); ec = check_send_error(err, ret); return ec; } ErrorCode am_proxy_deregister_source(int source){ if(is_range_over_guint16(source) == OUT_RANGE){ return OUT_RANGE; } guint16 ret = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_route_bus); 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 = UNABLE_SEND; ErrorCode ec; GError *err = NULL; assert(!am_route_bus); audiomanager_routinginterface_call_register_domain_sync( am_route_bus, domain_data, SOUND_MANAGER_BUS_NAME, SOUND_MANAGER_PATH, SOUND_MANAGER_RETURN_INTERFACE, domain, &ret, NULL, &err); g_variant_unref(domain_data); 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 only used by soundmanager. */ GVariantBuilder builder; 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); 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("created sourceData %d", __LINE__); return g_variant_builder_end (&builder); } ErrorCode initialize_proxy(){ if(am_cmd_bus || am_route_bus) { return UNABLE_SEND; } 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 ); 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 ); 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); assert(!am_route_bus); /* 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_removed_main_connection; _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); } ErrorCode open_soundmanager_interface(const am_instruction *callback){ guint ret = g_bus_own_name(G_BUS_TYPE_SYSTEM, SOUND_MANAGER_BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL,NULL, NULL, NULL, NULL); AFB_DEBUG( "g_bus_own_name ret: %d", ret); GError *error = NULL;; GVariant *value; system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); if (error) { g_error_free(error); return NOT_INITIALIZED; } sm_adapter = audiomanager_routing_soundmanager_skeleton_new(); sm_itf = AUDIOMANAGER_ROUTING_SOUNDMANAGER_GET_IFACE(sm_adapter); _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; /* 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); gboolean rc = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(sm_adapter), system_conn, SOUND_MANAGER_PATH, &error); if (FALSE == rc) { AFB_ERROR( "failed to export"); g_error_free(error); g_object_unref(system_conn); return NOT_INITIALIZED; } return OK; } void close_soundmanager_inerface(){ g_dbus_interface_skeleton_unexport(sm_adapter); }