diff options
Diffstat (limited to 'src/audiomanager_proxy.c')
-rw-r--r-- | src/audiomanager_proxy.c | 651 |
1 files changed, 651 insertions, 0 deletions
diff --git a/src/audiomanager_proxy.c b/src/audiomanager_proxy.c new file mode 100644 index 0000000..cdf5b4c --- /dev/null +++ b/src/audiomanager_proxy.c @@ -0,0 +1,651 @@ +/* + * 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 "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); + + SEND_RESULT_NO_RESP(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); +} |