diff options
author | Kazumasa Mitsunari <knimitz@witz-inc.co.jp> | 2018-07-12 18:55:45 +0900 |
---|---|---|
committer | Kazumasa Mitsunari <knimitz@witz-inc.co.jp> | 2018-07-12 18:55:45 +0900 |
commit | 91c0dff9565fd922230378090db20eaf8e4a7bed (patch) | |
tree | 2889ae759e93605be40c3256d651f42772b927b8 | |
parent | b4997430efe1b1895a8d0d61007384fa8e872310 (diff) |
merge master
Signed-off-by: Kazumasa Mitsunari <knimitz@witz-inc.co.jp>
-rw-r--r-- | src/CMakeLists.txt | 14 | ||||
-rw-r--r-- | src/audiomanager_proxy.c | 697 | ||||
-rw-r--r-- | src/audiomanager_proxy.h | 97 | ||||
-rw-r--r-- | src/dbus/command_interface.xml | 2 | ||||
-rw-r--r-- | src/dbus/routing_interface.xml | 52 | ||||
-rw-r--r-- | src/dbus/sound_manager_interface.xml | 58 | ||||
-rw-r--r-- | src/sm-def.h | 70 | ||||
-rw-r--r-- | src/sm-error.c | 71 | ||||
-rw-r--r-- | src/sm-error.h | 91 | ||||
-rw-r--r-- | src/sm-helper.c | 163 | ||||
-rw-r--r-- | src/sm-helper.h | 76 | ||||
-rw-r--r-- | src/sm-pending.c | 76 | ||||
-rw-r--r-- | src/sm-pending.h | 38 | ||||
-rw-r--r-- | src/soundmanager.c | 965 | ||||
-rw-r--r-- | src/soundmanager.h | 49 |
15 files changed, 1667 insertions, 852 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9e0e7b..66e640f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 2.8) -set(TARGETS_SMBINDER soundmanager-service) +set(TARGETS_SMBINDER agl-service-audio-soundmanager) INCLUDE(FindThreads) FIND_PACKAGE(Threads) @@ -25,8 +25,18 @@ pkg_check_modules(sm_binding_depends afb-daemon glib-2.0 gio-2.0 gio-unix-2.0 js set(binding_sm_sources soundmanager.c sm-helper.c + sm-error.c + sm-pending.c + audiomanager_proxy.c dbus/audio_manager_interface.c) +option(ENABLE_AGL_AHL "Implement AGL High Level API" ON) + +if(ENABLE_AGL_AHL) + message(STATUS "Adopt high level API of AGL") + add_definitions(-DENABLE_AGL_AHL) +endif() + include_directories(dbus) link_libraries(-Wl,--as-needed -Wl,--gc-sections -Wl,--no-undefined) @@ -56,5 +66,5 @@ add_custom_command(TARGET ${TARGETS_SMBINDER} POST_BUILD ) add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root - COMMAND wgtpkg-pack -f -o ${PROJECT_BINARY_DIR}/package/${TARGETS_SMBINDER}-2017.wgt ${PROJECT_BINARY_DIR}/package/root + COMMAND wgtpkg-pack -f -o ${PROJECT_BINARY_DIR}/package/${TARGETS_SMBINDER}.wgt ${PROJECT_BINARY_DIR}/package/root ) 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)); +} diff --git a/src/audiomanager_proxy.h b/src/audiomanager_proxy.h new file mode 100644 index 0000000..5a2427b --- /dev/null +++ b/src/audiomanager_proxy.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#ifndef AUDIO_MANAGER_PROXY_H +#define AUDIO_MANAGER_PROXY_H +#include <glib.h> +#include <stdbool.h> +#include "sm-def.h" + +typedef struct audiomanager_event{ + void (*on_new_main_connection)(int connection, int source, int sink, int delay, int connection_state); + void (*on_removed_main_connection)(int connection); + void (*on_main_connection_state_changed)(int connection, int connection_state); + void (*on_volume_changed)(int sink, int volume); + void (*on_sink_mute_state_changed)(int sink, int mute); + void (*on_set_routing_ready)(void); + void (*on_set_routing_rundown)(void); +} am_event; + +typedef struct audiomanager_instruction{ + void (*on_async_abort)(int handle); + void (*on_async_connect)(int handle, int connection, int source, int sink, int connection_format); + void (*on_async_disconnect)(int handle, int connection); + void (*on_async_set_sink_volume)(int handle, int sink, int volume, int ramp, int time); + void (*on_async_set_source_state)(int handle, int source, int source_state); +} am_instruction; + +struct domain_data{ + int domainID; + char* name; + char* busname; + char* nodename; + bool early; + bool complete; + int state; +}; + +struct sound_property_s{ + int type; + int value; +}; +struct availability_s{ + int availability; + int avalilable_reason; +}; +struct notification_config_s{ + int type; + int status; + int parameter; +}; +struct main_sound_property_s{ + int type; /* am_CustomMainSoundPropertyType_t */ + int value; +}; + +ErrorCode am_proxy_connect(int source, int sink, int *main_connection_id); +ErrorCode am_proxy_disconnect(int main_connection_id); +ErrorCode am_proxy_set_volume(int sink, int volume); +ErrorCode am_proxy_volume_step(int sink, int volume); +ErrorCode am_proxy_set_sink_mute_state(int sink, int mute_state); +ErrorCode am_proxy_get_list_main_connections(GVariant** connection_list); +ErrorCode am_proxy_get_list_main_sources(GVariant** source_list); +ErrorCode am_proxy_get_list_main_sinks(GVariant** sink_list); +ErrorCode am_proxy_ack_connect(int handle, int connection_id, int usr_err); +ErrorCode am_proxy_ack_disconnect(int handle, int connection_id, int usr_err); +ErrorCode am_proxy_ack_set_source_state(int handle, int usr_err); +ErrorCode am_proxy_register_source(GVariant *source_data, int *source); +ErrorCode am_proxy_deregister_source(int source); +ErrorCode am_proxy_register_domain(GVariant* domain_data, int *domain); + +GVariant* create_domain_data(struct domain_data* domain); +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); + +ErrorCode initialize_proxy(); +void set_event_callback(const am_event *callback); +void close_proxy(); +ErrorCode open_soundmanager_interface(const am_instruction *callback); +void close_soundmanager_inerface(); + +#endif //AUDIO_MANAGER_PROXY_H
\ No newline at end of file diff --git a/src/dbus/command_interface.xml b/src/dbus/command_interface.xml index 244553c..2be9ba2 100644 --- a/src/dbus/command_interface.xml +++ b/src/dbus/command_interface.xml @@ -32,7 +32,7 @@ </method> <method name="GetListMainSinks"> <arg type="n" name="result" direction="out"/> <!-- method return code (am_Error_e) --> - <arg type="a(qs(nn)nnq)" name="listMainSinks" direction="out"/> + <arg type="a(qs(nn)nnq)" name="listMainSinks" direction="out"/> <!-- uint16 sinkID; std::string name; am_Availability_s availability; am_mainVolume_t volume; am_MuteState_e muteState; am_sinkClass_t sinkClassID; --> </method> <method name="GetListMainSources"> diff --git a/src/dbus/routing_interface.xml b/src/dbus/routing_interface.xml index a91d6eb..f82b456 100644 --- a/src/dbus/routing_interface.xml +++ b/src/dbus/routing_interface.xml @@ -3,11 +3,11 @@ "-//freedesktop//DTD D-Bus Object Introspection 1.0//EN" "http://standards.freedesktop.org/dbus/1.0/introspect.dtd"> -<node> - <interface name="org.genivi.audiomanager.routinginterface"> - <method name="ackConnect"> - <arg name="handle" type="q" direction="in" /> - <arg name="connectionID" type="q" direction="in" /> +<node> + <interface name="org.genivi.audiomanager.routinginterface"> + <method name="ackConnect"> + <arg name="handle" type="q" direction="in" /> + <arg name="connectionID" type="q" direction="in" /> <arg name="error" type="q" direction="in" /> </method> <method name="ackDisconnect"> @@ -24,23 +24,23 @@ <arg name="volume" type="n" direction="in" /> <arg name="error" type="q" direction="in" /> </method> - <method name="registerSink"> - <arg name="sinkData" type="(qsqinb(ii)nna(in)aia(in)a(iin)a(iin))" direction="in" /> <!-- am_sinkID_t sinkID; std::string name; am_domainID_t domainID; am_sinkClass_t sinkClassID; am_volume_t volume; bool visible; am_Availability_s available; am_MuteState_e muteState;am_mainVolume_t mainVolume; std::vector<am_SoundProperty_s> listSoundProperties; std::vector<am_CustomAvailabilityReason_t> listConnectionFormats; std::vector<am_MainSoundProperty_s> listMainSoundProperties; --> - <arg name="sinkID" type="q" direction="out" /> + <method name="registerSink"> + <arg name="sinkData" type="(qsqinb(ii)nna(in)aia(in)a(iin)a(iin))" direction="in" /> <!-- am_sinkID_t sinkID; std::string name; am_domainID_t domainID; am_sinkClass_t sinkClassID; am_volume_t volume; bool visible; am_Availability_s available; am_MuteState_e muteState;am_mainVolume_t mainVolume; std::vector<am_SoundProperty_s> listSoundProperties; std::vector<am_CustomAvailabilityReason_t> listConnectionFormats; std::vector<am_MainSoundProperty_s> listMainSoundProperties; --> + <arg name="sinkID" type="q" direction="out" /> <arg name="error" type="q" direction="out" /> </method> <method name="deregisterSink"> - <arg name="sinkID" type="q" direction="in" /> + <arg name="sinkID" type="q" direction="in" /> <arg name="error" type="i" direction="out" /> - </method> - <method name="registerSource"> - <arg name="sourceData" type="(qqsqinb(ii)qa(in)aia(in)a(iin)a(iin))" direction="in" /> <!-- am_sourceID_t sourceID; am_domainID_t domainID; std::string name; am_sourceClass_t sourceClassID; am_SourceState_e sourceState; am_volume_t volume; bool visible; am_Availability_s available; am_InterruptState_e interruptState; std::vector<am_SoundProperty_s> listSoundProperties; std::vector<am_CustomAvailabilityReason_t> listConnectionFormats; std::vector<am_MainSoundProperty_s> listMainSoundProperties; --> - <arg name="sourceID" type="q" direction="out" /> + </method> + <method name="registerSource"> + <arg name="sourceData" type="(qqsqinb(ii)qa(in)aia(in)a(iin)a(iin))" direction="in" /> <!-- am_sourceID_t sourceID; am_domainID_t domainID; std::string name; am_sourceClass_t sourceClassID; am_SourceState_e sourceState; am_volume_t volume; bool visible; am_Availability_s available; am_InterruptState_e interruptState; std::vector<am_SoundProperty_s> listSoundProperties; std::vector<am_CustomAvailabilityReason_t> listConnectionFormats; std::vector<am_MainSoundProperty_s> listMainSoundProperties; --> + <arg name="sourceID" type="q" direction="out" /> <arg name="error" type="q" direction="out" /> </method> <method name="deregisterSource"> - <arg name="sourceID" type="q" direction="in" /> - <arg name="error" type="q" direction="out" /> + <arg name="sourceID" type="q" direction="in" /> + <arg name="error" type="q" direction="out" /> </method> <method name="hookInterruptStatusChange"> <arg name="sourceID" type="q" direction="in" /> @@ -48,24 +48,24 @@ </method> <method name="hookSourceAvailablityStatusChange"> <arg name="sourceID" type="q" direction="in" /> - <arg name="availability" type="(nn)" direction="in"/> + <arg name="availability" type="(nn)" direction="in"/> </method> - <method name="confirmRoutingReady"> + <method name="confirmRoutingReady"> <arg name="domainID" type="q" direction="in" /> </method> - <method name="confirmRoutingRundown"> + <method name="confirmRoutingRundown"> <arg name="domainID" type="q" direction="in" /> </method> - <method name="ackSetVolumes"> + <method name="ackSetVolumes"> <arg name="handle" type="q" direction="in" /> <arg name="listvolumes" type="a(nqqnq)" direction="in" /> - <arg name="error" type="q" direction="in" /> - </method> - <method name="ackSinkNotificationConfiguration"> + <arg name="error" type="q" direction="in" /> + </method> + <method name="ackSinkNotificationConfiguration"> <arg name="handle" type="q" direction="in" /> <arg name="error" type="q" direction="in" /> - </method> - <method name="ackSourceNotificationConfiguration"> + </method> + <method name="ackSourceNotificationConfiguration"> <arg name="handle" type="q" direction="in" /> <arg name="error" type="q" direction="in" /> </method> @@ -78,8 +78,8 @@ <arg name="error" type="q" direction="out" /> </method> <signal name="setRoutingReady"> - </signal> + </signal> <signal name="setRoutingRundown"> - </signal> + </signal> </interface> </node> diff --git a/src/dbus/sound_manager_interface.xml b/src/dbus/sound_manager_interface.xml index df7df04..de528f9 100644 --- a/src/dbus/sound_manager_interface.xml +++ b/src/dbus/sound_manager_interface.xml @@ -3,34 +3,34 @@ "-//freedesktop//DTD D-Bus Object Introspection 1.0//EN" "http://standards.freedesktop.org/dbus/1.0/introspect.dtd"> -<node> - <interface name='org.genivi.audiomanager.routing.soundmanager'> - <method name='asyncAbort'> - <arg name='handle' type='q' direction='in' /> +<node> + <interface name='org.genivi.audiomanager.routing.soundmanager'> + <method name='asyncAbort'> + <arg name='handle' type='q' direction='in' /> <arg name='error' type='n' direction='out' /> - </method> - <method name='asyncConnect'> - <arg name='handle' type='q' direction='in' /> - <arg name='connectionID' type='q' direction='in' /> - <arg name='sourceID' type='q' direction='in' /> - <arg name='sinkID' type='q' direction='in' /> - <arg name='connectionFormat' type='i' direction='in' /> - </method> - <method name='asyncDisconnect'> - <arg name='handle' type='q' direction='in' /> - <arg name='connectionID' type='q' direction='in' /> - </method> - <method name='asyncSetSinkVolume'> - <arg name='handle' type='q' direction='in' /> - <arg name='sinkID' type='q' direction='in' /> - <arg name='volume' type='n' direction='in' /> - <arg name='ramp' type='n' direction='in' /> - <arg name='time' type='q' direction='in' /> - </method> - <method name='asyncSetSourceState'> - <arg name='handle' type='q' direction='in' /> - <arg name='sourceID' type='q' direction='in' /> - <arg name='sourceState' type='i' direction='in' /> - </method> - </interface> + </method> + <method name='asyncConnect'> + <arg name='handle' type='q' direction='in' /> + <arg name='connectionID' type='q' direction='in' /> + <arg name='sourceID' type='q' direction='in' /> + <arg name='sinkID' type='q' direction='in' /> + <arg name='connectionFormat' type='i' direction='in' /> + </method> + <method name='asyncDisconnect'> + <arg name='handle' type='q' direction='in' /> + <arg name='connectionID' type='q' direction='in' /> + </method> + <method name='asyncSetSinkVolume'> + <arg name='handle' type='q' direction='in' /> + <arg name='sinkID' type='q' direction='in' /> + <arg name='volume' type='n' direction='in' /> + <arg name='ramp' type='n' direction='in' /> + <arg name='time' type='q' direction='in' /> + </method> + <method name='asyncSetSourceState'> + <arg name='handle' type='q' direction='in' /> + <arg name='sourceID' type='q' direction='in' /> + <arg name='sourceState' type='i' direction='in' /> + </method> + </interface> </node> diff --git a/src/sm-def.h b/src/sm-def.h index 9d4acb5..bd565d5 100644 --- a/src/sm-def.h +++ b/src/sm-def.h @@ -1,3 +1,18 @@ +/* + * 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. + */ #ifndef SOUNDMANAGER_DEFINE_H #define SOUNDMANAGER_DEFINE_H @@ -38,7 +53,7 @@ #define KEY_DOMAIN_ID "domainID" #define KEY_HANDLE "handle" -#define KEY_APPNAME "appname" +#define KEY_APPNAME "audio_role" #define KEY_RAMP "ramp" #define KEY_TIME "time" #define KEY_SOURCE_STATE "sourceState" @@ -55,15 +70,64 @@ #define KEY_CONNECTION_FORMAT "connectionFormat" #define KEY_EVENT "event" +#define KEY_RESPONSE "response" + +#define SM_EVENT_VOLUME_CHANGED "volumeChanged" +#define SM_EVENT_NEW_MAIN_CONNECTION "newMainConnection" +#define SM_EVENT_REMOVED_MAIN_CONNECTION "removedMainConnection" +#define SM_EVENT_SINK_MUTE_STATE_CHANGED "sinkMuteStateChanged" +#define SM_EVENT_MAIN_CONNECTION_STATE_CHANGED "mainConnectionStateChanged" +/* Routing event*/ +#define SM_EVENT_SET_ROUTING_READY "setRoutingReady" +#define SM_EVENT_SET_ROUTING_RUNDOWN "setRoutingRundown" +#define SM_EVENT_ASYNC_CONNECT "asyncConnect" +#define SM_EVENT_ASYNC_SET_SOURCE_STATE "asyncSetSourceState" +#define SM_EVENT_ASYNC_DISCONNECT "asyncDisconnect" +#define SM_EVENT_STREAM_STATE_EVENT "stream_state_event" + +#ifdef ENABLE_AGL_AHL #define KEY_AHL_AUDIO_ROLE "audio_role" #define KEY_AHL_ENDPOINT_ID "endpoint_id" #define KEY_AHL_ENDPOINT_TYPE "endpoint_type" +#define KEY_AHL_REP_STREAM_ID "stream_id" +#define KEY_AHL_EVENT_NAME "event_name" +#define KEY_AHL_STATE_EVENT "state_event" +#define AHL_EVENT_NAME "ahl_stream_state_event" +#define KEY_AHL_MUTE "mute" +#define AHL_STREAM_UNMUTE 0 +#define AHL_STREAM_MUTE 1 typedef enum { ENDPOINT_SINK, ENDPOINT_SOURCE, } EndPointType; +#endif + +typedef enum { + NOT_INITIALIZED = -2, + UNABLE_SEND, + OK = 0, + UNKNOWN, + OUT_RANGE, + NOT_USED, + DATABASE_ERR, + OBJECT_ALREADY_EXIST, + NO_CHANGE, + ACTION_IMPOSSIBLE, + OBJECT_NOT_EXIST, + ASYNC_ACTION_ABORTED, + CONNECTION_FORMAT_ERR, + COMMUNICATION_ERR, + EVENT_NOT_EXIST = 100 +} ErrorCode; + +typedef enum { + REQ_FAIL, + OUT_OF_RANGE, + NOT_NUMBER, + REQ_OK +} REQ_ERROR; -#define MAX_LENGTH_STRING 256 +#define MAX_LENGTH_STR 256 -#endif // SOUNDMANAGER_DEFINE_H +#endif // SOUNDMANAGER_DEFINE_H
\ No newline at end of file diff --git a/src/sm-error.c b/src/sm-error.c new file mode 100644 index 0000000..79a2009 --- /dev/null +++ b/src/sm-error.c @@ -0,0 +1,71 @@ +/* + * 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 "sm-error.h" +#include "sm-def.h" + +const char* get_response_audiomanager_massage_error(int am_error_code) +{ + switch (am_error_code){ + case UNABLE_SEND: + return "Unable to send request to audiomanager"; + case NOT_INITIALIZED: + return "soundmanager is not initialized"; + case OK: + return "OK"; + case UNKNOWN: + return "unknown error"; + case OUT_RANGE: + return "value out of range"; + case NOT_USED: + return "not used"; + case DATABASE_ERR: + return "database error occured"; + case OBJECT_ALREADY_EXIST: + return "the desired object already exists"; + case NO_CHANGE: + return "there is no change"; + case ACTION_IMPOSSIBLE: + return "the desired action is not possible"; + case OBJECT_NOT_EXIST: + return "the desired object is non existent"; + case ASYNC_ACTION_ABORTED: + return "the asynchronous action was aborted"; + case CONNECTION_FORMAT_ERR: + return "connectionFormat is not selected"; + case COMMUNICATION_ERR: + return "communication error"; + case EVENT_NOT_EXIST: + return "desired event doesn't exist"; + default: + return "Audio Manager responsed unknown error number"; + } +} + +const char* get_source_state_key(int am_source_state){ + switch (am_source_state){ + case 0: + return "unknown"; + case 1: + return "on"; + case 2: + return "off"; + case 3: + return "paused"; + default: + return ""; + } +}
\ No newline at end of file diff --git a/src/sm-error.h b/src/sm-error.h index bc60175..521fca2 100644 --- a/src/sm-error.h +++ b/src/sm-error.h @@ -1,73 +1,20 @@ -#ifndef SM_ERROR_H -#define SM_ERROR_H -#include <glib.h> -#define _GNU_SOURCE -#define AFB_BINDING_VERSION 2 -#include <afb/afb-binding.h> -#define IS_SEND_ERROR(...) is_send_error(__VA_ARGS__, __FUNCTION__) -#define IS_SEND_ERROR_WITHOUT_RETURN(...) is_send_error_without_return(__VA_ARGS__, __FUNCTION__) - -char* get_response_audiomanager_massage_error(int am_error_code) -{ - switch (am_error_code){ - case 0: - return "OK"; - case 1: - return "unknown error"; - case 2: - return "value out of range"; - case 3: - return "not used"; - case 4: - return "database error occured"; - case 5: - return "the desired object already exists"; - case 6: - return "there is no change"; - case 7: - return "the desired action is not possible"; - case 8: - return "the desired object is non existent"; - case 9: - return "the asynchronous action was aborted"; - case 10: - return "connectionFormat is not selected"; - case 11: - return "communication error"; - case 100: - return "desired event doesn't exist"; - default: - return "Audio Manager responsed unknown error number"; - } -} - -char* get_source_state_key(int am_source_state){ - switch (am_source_state){ - case 0: - return "unknown"; - case 1: - return "on"; - case 2: - return "off"; - case 3: - return "paused"; - default: - return ""; - } -} - -void is_send_error_without_return(GError* result_of_send, const char* function){ - if(result_of_send != NULL){ - AFB_ERROR("Unable to call %s", function); - } -} - -int is_send_error(GError* result_of_send, struct afb_req req, const char* function){ - if(result_of_send != NULL) - { - afb_req_fail_f(req, "failed", "Unable to call %s", function); - return 0; - } - return -1; -} +/* + * 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. + */ +#ifndef SOUNDMANAGER_ERROR_H +#define SOUNDMANAGER_ERROR_H +const char* get_response_audiomanager_massage_error(int am_error_code); +const char* get_source_state_key(int am_source_state); #endif diff --git a/src/sm-helper.c b/src/sm-helper.c index 02de95a..9f78414 100644 --- a/src/sm-helper.c +++ b/src/sm-helper.c @@ -14,13 +14,15 @@ * limitations under the License. */ -#include "sm-helper.h" -#include "sm-def.h" #include <stdlib.h> #include <string.h> #include <limits.h> #include <json-c/json.h> #include <stdarg.h> +#include "sm-helper.h" +#include "sm-error.h" + +static int default_sinkID = DEFAULT_SINK; REQ_ERROR get_value_uint16(const struct afb_req request, const char *source, uint16_t *out_id) { @@ -35,7 +37,7 @@ REQ_ERROR get_value_uint16(const struct afb_req request, const char *source, uin /* error check of range */ if( (tmp_id > UINT16_MAX) || (tmp_id < 0) ) { - return OUT_RANGE; + return OUT_OF_RANGE; } if(*endptr != '\0') { @@ -59,7 +61,7 @@ REQ_ERROR get_value_int16(const struct afb_req request, const char *source, int1 /* error check of range */ if( (tmp_id > INT16_MAX) || (tmp_id < INT16_MIN) ) { - return OUT_RANGE; + return OUT_OF_RANGE; } if(*endptr != '\0') { @@ -83,7 +85,7 @@ REQ_ERROR get_value_int32(const struct afb_req request, const char *source, int3 /* error check of range */ if( (tmp_id > INT32_MAX) || (tmp_id < INT32_MIN) ) { - return OUT_RANGE; + return OUT_OF_RANGE; } if(*endptr != '\0') { @@ -94,6 +96,35 @@ REQ_ERROR get_value_int32(const struct afb_req request, const char *source, int3 return REQ_OK; } +REQ_ERROR get_sink_id(const afb_req request, const char* key, uint16_t* out_sink_id){ + AFB_DEBUG(""); + REQ_ERROR result = REQ_FAIL; + const char* requested_sink_str = afb_req_value (request, key); + json_object* test = afb_req_json(request); + AFB_DEBUG("%s", json_object_to_json_string_ext(test, JSON_C_TO_STRING_PRETTY)); + + if(0 == strcmp(requested_sink_str, "default")){ + *out_sink_id = default_sinkID; + AFB_INFO("sinkID(endpointID) is attached as default sinkID as %d", DEFAULT_SINK); + result = REQ_OK; + } + else{ + result = get_value_uint16(request, key, out_sink_id); + AFB_INFO("sinkID(endpointID) is %d", *out_sink_id); + } + + if(REQ_OK != result){ + AFB_INFO("can't parse %s, result %d", key, result); + afb_req_fail_f(request,"wrong-request","can't parse %s, result: %d", key, result); + return result; + } + return REQ_OK; +} + +void set_default_sinkID(int sinkID){ + default_sinkID = sinkID; +} + void sm_add_object_to_json_object(struct json_object* j_obj, int count,...) { va_list args; @@ -157,102 +188,40 @@ int sm_search_routing_event_name_index(const char* value) return ret; } -GVariant* create_source_data(guint16 sourceID, guint16 domainID, const char* appname, guint16 sourceClassID, - gint32 sourceState, gint16 volume, gboolean visible, struct availability_s availables, - guint16 interrupt, struct sound_property_s soundPropertyList, gint32 connectionFormatList, - struct main_sound_property_s mainPropertyList, struct notification_config_s NConfRouting, - struct notification_config_s NConfCommand) -{ - GVariantBuilder builder; - - AFB_DEBUG("create sourceData %d", __LINE__); - g_variant_builder_init (&builder, G_VARIANT_TYPE ("(qqsqinb(ii)qa(in)aia(in)a(iin)a(iin))")); - g_variant_builder_add (&builder, "q", sourceID); - g_variant_builder_add (&builder, "q", domainID); - g_variant_builder_add (&builder, "s", appname); - g_variant_builder_add (&builder, "q", sourceClassID); - g_variant_builder_add (&builder, "i", sourceState); - g_variant_builder_add (&builder, "n", volume); - g_variant_builder_add (&builder, "b", visible); - g_variant_builder_add (&builder, "(ii)", availables.availability, availables.avalilable_reason); - g_variant_builder_add (&builder, "q", 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", soundPropertyList.type); - g_variant_builder_add (&builder, "n", 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", 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", mainPropertyList.type); - g_variant_builder_add (&builder, "n", 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", NConfRouting.type); - g_variant_builder_add (&builder, "i", NConfRouting.status); - g_variant_builder_add (&builder, "n", 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", NConfCommand.type); - g_variant_builder_add (&builder, "i", NConfCommand.status); - g_variant_builder_add (&builder, "n", NConfCommand.parameter); - g_variant_builder_close(&builder); - g_variant_builder_close (&builder); - - AFB_DEBUG("created sourceData %d", __LINE__); - return g_variant_builder_end (&builder); +bool send_result(ErrorCode ec, struct afb_req req, const char* function){ + /* GError = NULL means success in case of gdbus request */ + if(ec == UNABLE_SEND) + { + AFB_ERROR("Unable to call : %s", function); + afb_req_fail_f(req, "failed", "%s : %s", function, + get_response_audiomanager_massage_error(ec)); + return false; + } + return true; } -GVariant* create_domain_data(struct domain_data* data) -{ - GVariantBuilder builder; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("(qsssbbn)")); - g_variant_builder_add (&builder, "q", data->domainID); - g_variant_builder_add (&builder, "s", data->name); - g_variant_builder_add (&builder, "s", data->busname); - g_variant_builder_add (&builder, "s", data->nodename); - g_variant_builder_add (&builder, "b", data->early); - g_variant_builder_add (&builder, "b", data->complete); - g_variant_builder_add (&builder, "n", data->state); - AFB_DEBUG("created domainData %d", __LINE__); - return g_variant_builder_end (&builder); +bool send_result_no_resp(ErrorCode ec, const char* function){ + if(ec == UNABLE_SEND){ + AFB_ERROR("Unable to call : %s", function); + return false; + } + return true; } -int get_sink_id(struct afb_req req, const char* key){ - const char* default_sink = afb_req_value (req, key); - int sink_id; - REQ_ERROR result = REQ_FAIL; - if(default_sink == NULL) { - afb_req_fail(req, "wrong request", NULL); - return -1; - } - else{ - if((strlen("default") == strlen(default_sink)) && - (0 == strncmp("default", default_sink, strlen("default")))){ - sink_id = DEFAULT_SINK; - result = REQ_OK; - } - else{ - result = get_value_uint16(req, key, &sink_id); - } +ErrorCode is_range_over_guint16(int source){ + /* error check of range */ + if( (source > UINT16_MAX) || (source < 0) ) + { + return OUT_RANGE; } - if(REQ_OK != result){ - AFB_INFO("can't parse %s, result %d", key, result); - afb_req_fail_f(req,"wrong-request","can't parse %s, result: %d", result); - return -1 + return OK; +} + +ErrorCode is_range_over_gint16(int source){ + /* error check of range */ + if( (source > INT16_MAX) || (source < INT16_MIN) ) + { + return OUT_RANGE; } - return sink_id; + return OK; }
\ No newline at end of file diff --git a/src/sm-helper.h b/src/sm-helper.h index f6a3601..ec35ad2 100644 --- a/src/sm-helper.h +++ b/src/sm-helper.h @@ -20,75 +20,41 @@ #define AFB_BINDING_VERSION 2 #include <afb/afb-binding.h> #include <stdint.h> +#include <stdbool.h> #include <glib.h> -//#include <errno.h> - -typedef enum REQ_ERROR -{ - REQ_FAIL = -1, - REQ_OK=0, - NOT_NUMBER, - OUT_RANGE -}REQ_ERROR; +#include "sm-def.h" +#define SEND_RESULT(...) send_result(__VA_ARGS__, __FUNCTION__) +#define SEND_RESULT_NO_RESP(...) send_result_no_resp(__VA_ARGS__, __FUNCTION__) static const char* cmd_evlist[] = { - "volumeChanged", - "newMainConnection", - "removedMainConnection", - "sinkMuteStateChanged", - "mainConnectionStateChanged" + SM_EVENT_VOLUME_CHANGED, + SM_EVENT_NEW_MAIN_CONNECTION, + SM_EVENT_REMOVED_MAIN_CONNECTION, + SM_EVENT_SINK_MUTE_STATE_CHANGED, + SM_EVENT_MAIN_CONNECTION_STATE_CHANGED }; static const char* route_evlist[] = { /* Routing event*/ - "setRoutingReady", - "setRoutingRundown", - "asyncConnect", - "asyncSetSourceState", - "asyncDisconnect" -}; - -struct sound_property_s{ - guint16 type; - gint16 value; -}; -struct availability_s{ - gint32 availability; - gint32 avalilable_reason; -}; -struct notification_config_s{ - gint32 type; - gint32 status; - gint16 parameter; -}; -struct main_sound_property_s{ - gint32 type; /* am_CustomMainSoundPropertyType_t */ - gint16 value; -}; - -struct domain_data{ - guint16 domainID; - gchar* name; - gchar* busname; - gchar* nodename; - gboolean early; - gboolean complete; - gint16 state; + SM_EVENT_SET_ROUTING_READY, + SM_EVENT_SET_ROUTING_RUNDOWN, + SM_EVENT_ASYNC_CONNECT, + SM_EVENT_ASYNC_SET_SOURCE_STATE, + SM_EVENT_ASYNC_DISCONNECT, + SM_EVENT_STREAM_STATE_EVENT }; REQ_ERROR get_value_uint16(const struct afb_req request, const char *source, uint16_t *out_id); REQ_ERROR get_value_int16(const struct afb_req request, const char *source, int16_t *out_id); REQ_ERROR get_value_int32(const struct afb_req request, const char *source, int32_t *out_id); +REQ_ERROR get_sink_id(const struct afb_req request, const char* key, uint16_t *out_sink_id); +void set_default_sinkID(int sinkID); void sm_add_object_to_json_object(struct json_object* j_obj, int count, ...); void sm_add_object_to_json_object_func(struct json_object* j_obj, const char* verb_name, int count, ...); int sm_search_event_name_index(const char* value); int sm_search_routing_event_name_index(const char* value); -GVariant* create_source_data(guint16 sourceID, guint16 domainID, const char* appname, guint16 sourceClassID, - gint32 sourceState, gint16 volume, gboolean visible, struct availability_s availables, - guint16 interrupt, struct sound_property_s soundPropertyList, gint32 connectionFormatList, - struct main_sound_property_s mainPropertyList, struct notification_config_s NConfRouting, - struct notification_config_s NConfCommand); -GVariant* create_domain_data(struct domain_data*); - - +bool send_result_no_resp(ErrorCode ec, const char* function); +bool send_result(ErrorCode ec, struct afb_req req, const char* function); +ErrorCode is_range_over_guint16(int source); +ErrorCode is_range_over_gint16(int source); #endif /*AM_HELPER_H*/
\ No newline at end of file diff --git a/src/sm-pending.c b/src/sm-pending.c new file mode 100644 index 0000000..28a2382 --- /dev/null +++ b/src/sm-pending.c @@ -0,0 +1,76 @@ +/* + * 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 <stdlib.h> +#include "sm-pending.h" + +struct pending* add_pending(struct pending *list, int source_id) +{ + struct pending* pd; + + if(list == NULL){ + pd = malloc(sizeof(struct pending)); + if(NULL == pd){ + AFB_WARNING("memory allocation error"); + return NULL; + } + pd->source.sourceID = source_id; + pd->next = NULL; + return pd; + } + else{ + list->next = add_pending(list->next, source_id); + return list; + } +} + +struct pending* get_pending(struct pending *list, int source_id){ + if(list == NULL){ + return NULL; + } + if(list->source.sourceID == source_id){ + return list; + } + else{ + struct pending* pd = get_pending(list->next, source_id); + return pd; + } +} + +struct pending* del_pending(struct pending* list, int source_id){ + struct pending* tmp; + if(list == NULL){ + return NULL; + } + + if(list->source.sourceID == source_id){ + tmp = list->next; + free(list); + return tmp; + } + else{ + list->next = del_pending(list->next, source_id); + return list; + } +} + +void del_all_pendings(struct pending *list){ + struct pending* tmp; + if(list != NULL){ + tmp = list->next; + free(list); + del_all_pendings(tmp); + } +}
\ No newline at end of file diff --git a/src/sm-pending.h b/src/sm-pending.h new file mode 100644 index 0000000..ab753cd --- /dev/null +++ b/src/sm-pending.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef SOUNDMANAGER_PENDING_H +#define SOUNDMANAGER_PENDING_H + +#define _GNU_SOURCE +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> + +struct pending_source{ + int sourceID; +}; +struct pending{ + struct pending_source source; + struct pending* next; +}; + + +struct pending* add_pending(struct pending *list, int source_id); +struct pending* get_pending(struct pending *list, int source_id); +struct pending* del_pending(struct pending* list, int source_id); +void del_all_pendings(struct pending *list); + +#endif //SOUNDMANAGER_PENDING_H
\ No newline at end of file diff --git a/src/soundmanager.c b/src/soundmanager.c index 2df7bd3..b499a06 100644 --- a/src/soundmanager.c +++ b/src/soundmanager.c @@ -22,18 +22,20 @@ #include <json-c/json.h> #include <glib.h> #include "soundmanager.h" +#include "audiomanager_proxy.h" #include "sm-def.h" #include "sm-error.h" #include "sm-helper.h" +#include "sm-pending.h" -const static struct afb_binding_interface *afbitf; -static AudiomanagerCommandinterface *am_cmd_bus; -static AudiomanagerRoutinginterface *am_route_bus; -static AudiomanagerRoutingSoundmanager *sm_adapter; -static AudiomanagerRoutingSoundmanagerIface* sm_itf; -static GDBusConnection* system_conn = NULL; +struct event{ + char* name; + struct afb_event* event; + }; + +static struct pending* pending_list = NULL; -static guint16 SOUNDMANAGER_DOMAIN_ID; +static int SOUNDMANAGER_DOMAIN_ID; static struct event command_event_list[COMMAND_EVENT_NUM]; static struct event routing_event_list[ROUTING_EVENT_NUM]; @@ -49,6 +51,33 @@ static struct afb_event ev_set_routing_rundown; static struct afb_event ev_async_connect; static struct afb_event ev_async_disconnect; static struct afb_event ev_async_set_source_state; +static struct afb_event ev_stream_state_event; + +/* Client context */ +typedef struct source { + int sourceID; + int mainConnectionID; +} source; + +typedef struct sink { + int endpointID; + int endpointType; + int sinkID; +} sink; + +typedef struct events { + afb_event asyncSetSourceState; +} events; + +typedef struct smClientCtxt{ + char* appname; + source source; + sink sink; + events events; +} smClientCtxt; + +static void on_client_context_terminated(void *data); +static void create_client_context(afb_req request, guint16 source_id, guint16 sink_id, int endpoint_type); /* ********** Method of Sound Manager (API) ********** @@ -58,11 +87,9 @@ void connect (struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); guint16 source_id = 0, sink_id = 0; - guint16 main_connectionID = 0; - gint16 ret = -1; + int main_connectionID = 0; REQ_ERROR req_err1 = REQ_FAIL; REQ_ERROR req_err2 = REQ_FAIL; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_SOURCE_ID, &source_id); /* ToDo: Hardware abstraction for application user is needed. @@ -88,24 +115,18 @@ void connect (struct afb_req request) return; } - audiomanager_commandinterface_call_connect_sync( - am_cmd_bus, - source_id, - sink_id, - &ret, - &main_connectionID, - NULL, &err); + ErrorCode ec = am_proxy_connect(source_id, sink_id, &main_connectionID); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /* ToDo Remember appname(key) and tie to sourceID(value) */ /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 4, - "error", ret, + "error", ec, KEY_MAIN_CONNECTION_ID, main_connectionID); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } @@ -113,32 +134,26 @@ void disconnect (struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); - guint16 id; - gint16 ret; + guint16 main_connection_id; REQ_ERROR req_err; - GError *err = NULL; - req_err = get_value_uint16(request, KEY_MAIN_CONNECTION_ID, &id); - AFB_DEBUG( "requested %s = %d", KEY_MAIN_CONNECTION_ID, id); + req_err = get_value_uint16(request, KEY_MAIN_CONNECTION_ID, &main_connection_id); + AFB_DEBUG( "requested %s = %d", KEY_MAIN_CONNECTION_ID, main_connection_id); if(req_err != REQ_OK) { afb_req_fail(request,"wrong-request",afb_req_value (request, KEY_MAIN_CONNECTION_ID)); return; } - audiomanager_commandinterface_call_disconnect_sync( - am_cmd_bus, - id, - &ret, - NULL, &err); - AFB_DEBUG( "ret = %d", ret); + ErrorCode ec = am_proxy_disconnect(main_connection_id); + AFB_DEBUG( "ret = %d", ec); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2, - KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + KEY_ERROR, ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res_obj, info); /* return error num as status */ } @@ -148,9 +163,7 @@ void setVolume (struct afb_req request) AFB_DEBUG("call %s", __FUNCTION__); guint16 sink_id, vol; - gint16 ret; REQ_ERROR req_err1, req_err2; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id); req_err2 = get_value_int16(request, KEY_VOLUME, &vol); @@ -161,20 +174,15 @@ void setVolume (struct afb_req request) return; } - audiomanager_commandinterface_call_set_volume_sync( - am_cmd_bus, - sink_id, - vol, - &ret, - NULL, &err); - AFB_DEBUG( "ret = %d", ret); + ErrorCode ec = am_proxy_set_volume(sink_id, vol); + AFB_DEBUG( "ret = %d", ec); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2, - "error", ret); - char *info = get_response_audiomanager_massage_error(ret); + "error", ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res_obj, info); /* return error num as status */ } @@ -184,9 +192,7 @@ void volumeStep (struct afb_req request) AFB_DEBUG("call %s", __FUNCTION__); guint16 sink_id, vol; - gint16 ret; REQ_ERROR req_err1, req_err2; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id); req_err2 = get_value_int16(request, KEY_VOLUME_STEP, &vol); @@ -197,20 +203,15 @@ void volumeStep (struct afb_req request) return; } - audiomanager_commandinterface_call_volume_step_sync( - am_cmd_bus, - sink_id, - vol, - &ret, - NULL, &err); - AFB_DEBUG( "ret = %d", ret); + ErrorCode ec = am_proxy_volume_step(sink_id, vol); + AFB_DEBUG( "ret = %d", ec); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2, - "error", ret); - char *info = get_response_audiomanager_massage_error(ret); + "error", ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res_obj, info); /* return error num as status */ } @@ -220,33 +221,27 @@ void setSinkMuteState(struct afb_req request) AFB_DEBUG("call %s", __FUNCTION__); guint16 sink_id, mute; - gint16 ret; REQ_ERROR req_err1, req_err2; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id); req_err2 = get_value_int16(request, KEY_MUTE_STATE, &mute); AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_MUTE_STATE, mute); + if((req_err1 != REQ_OK) || (req_err2 != REQ_OK)) { afb_req_fail(request,"wrong-request", NULL); return; } - audiomanager_commandinterface_call_set_sink_mute_state_sync( - am_cmd_bus, - sink_id, - mute, - &ret, - NULL, &err); - AFB_DEBUG( "ret = %d", ret); + ErrorCode ec = am_proxy_set_sink_mute_state(sink_id, mute); + AFB_DEBUG( "ret = %d", ec); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2, - "error", ret); - char *info = get_response_audiomanager_massage_error(ret); + "error", ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res_obj, info); /* return error num as status */ } @@ -254,32 +249,24 @@ void setSinkMuteState(struct afb_req request) void getListMainConnections(struct afb_req request) { AFB_DEBUG("call getListMainConnections"); - guint16 ret; + GVariant* mainConnectionList; - GError *err = NULL; - audiomanager_commandinterface_call_get_list_main_connections_sync( - am_cmd_bus, - &ret, - &mainConnectionList, - NULL, - &err - ); + ErrorCode ec = am_proxy_get_list_main_connections(&mainConnectionList); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /* create response */ - struct json_object *array_res = json_object_new_array(); + struct json_object *response = json_object_new_object(); gsize size = g_variant_n_children(mainConnectionList); AFB_DEBUG("mainConnectionList size is %u",(uint16_t)size); - struct json_object *verb_obj = json_object_new_object(); - sm_add_object_to_json_object_func(verb_obj, __FUNCTION__, 0); - json_object_array_add(array_res, verb_obj); + sm_add_object_to_json_object_func(response, __FUNCTION__, 0); if(size <= 0) { AFB_NOTICE( "mainConnectionList size is 0"); } else{ + struct json_object *array_res = json_object_new_array(); for(int i = 0; i < size; ++i) { guint16 mcid, srcid, sinkid; @@ -299,27 +286,22 @@ void getListMainConnections(struct afb_req request) ); json_object_array_add(array_res,res_obj); } + json_object_object_add(response, "connections", array_res); } - AFB_DEBUG("json object :%s:",json_object_to_json_string(array_res)); - afb_req_success(request, array_res, "Success to get main connection list"); + AFB_DEBUG("json object :%s:",json_object_to_json_string(response)); + afb_req_success(request, response, "Success to get main connection list"); + g_variant_unref(mainConnectionList); } void getListMainSources(struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); - guint16 ret; + GVariant* mainSourceList; - GError *err = NULL; - audiomanager_commandinterface_call_get_list_main_sources_sync( - am_cmd_bus, - &ret, - &mainSourceList, - NULL, - &err - ); + ErrorCode ec = am_proxy_get_list_main_sources(&mainSourceList); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /* create response */ struct json_object *response = json_object_new_object(); @@ -356,7 +338,7 @@ void getListMainSources(struct afb_req request) json_object_array_add(array_res,res_obj); g_variant_unref(child); } - json_object_object_add(response, "sinks", array_res); + json_object_object_add(response, "sources", array_res); } afb_req_success(request, response, "Success to get main source list"); g_variant_unref(mainSourceList); @@ -365,19 +347,12 @@ void getListMainSources(struct afb_req request) void getListMainSinks(struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); - guint16 ret; + GVariant* mainSinkList; - GError *err = NULL; - audiomanager_commandinterface_call_get_list_main_sinks_sync( - am_cmd_bus, - &ret, - &mainSinkList, - NULL, - &err - ); + ErrorCode ec = am_proxy_get_list_main_sinks(&mainSinkList); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /* create response */ struct json_object *response = json_object_new_object(); @@ -436,7 +411,6 @@ void ackConnect(struct afb_req request) guint16 handle, connection_id, error; guint16 ret = 0; REQ_ERROR req_err1, req_err2 , req_err3; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_HANDLE, &handle); req_err2 = get_value_uint16(request, KEY_CONNECTION_ID, &connection_id); @@ -453,19 +427,15 @@ void ackConnect(struct afb_req request) return; } - audiomanager_routinginterface_call_ack_connect_sync( - am_route_bus, - handle, - connection_id, - error, - NULL, &err); + ErrorCode ec = am_proxy_ack_connect(handle, connection_id, error); + + if(!SEND_RESULT(ec, request)) return; - if(IS_SEND_ERROR(err, request) == 0) return; /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ret); afb_req_success(request, res, info); } @@ -476,7 +446,6 @@ void ackDisconnect(struct afb_req request) guint16 handle, connection_id, error; guint16 ret = 0; REQ_ERROR req_err1, req_err2 , req_err3; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_HANDLE, &handle); req_err2 = get_value_uint16(request, KEY_CONNECTION_ID, &connection_id); @@ -493,20 +462,15 @@ void ackDisconnect(struct afb_req request) return; } - audiomanager_routinginterface_call_ack_disconnect_sync( - am_route_bus, - handle, - connection_id, - error, - NULL, &err); + ErrorCode ec = am_proxy_ack_disconnect(handle, connection_id, error); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ret); afb_req_success(request, res, info); } @@ -516,7 +480,6 @@ void ackSetSourceState(struct afb_req request) guint16 handle, error; guint16 ret = 0; REQ_ERROR req_err1, req_err2; - GError *err = NULL; req_err1 = get_value_uint16(request, KEY_HANDLE, &handle); req_err2 = get_value_uint16(request, KEY_ERROR, &error); @@ -528,27 +491,21 @@ void ackSetSourceState(struct afb_req request) return; } - audiomanager_routinginterface_call_ack_set_source_state_sync( - am_route_bus, - handle, - error, - NULL, &err); + ErrorCode ec = am_proxy_ack_set_source_state(handle, error); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, - KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + KEY_ERROR, ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } void registerSource(struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); - GError *err = NULL; - guint16 source_id; /* q 0 is for dynamic id*/ guint16 domain_id; /* q */ @@ -578,8 +535,8 @@ void registerSource(struct afb_req request) const gchar* name = afb_req_value(request, KEY_APPNAME); /* s */ if(!name) { - char* info = "Must specify the name. Please input json arg such as {\"appname\":\"radio\"}"; - afb_req_fail(request, NULL, info); + char* info = "Must specify the name. Please input json arg such as {\"audio_role\":\"radio\"}"; + afb_req_fail(request, "wrong-request", info); return; } if(REQ_OK != get_value_uint16(request, KEY_SOURCE_CLASS_ID, &source_class_id)){ @@ -620,57 +577,44 @@ void registerSource(struct afb_req request) nconf_command.parameter = 0; /* acquire data */ - guint16 acquire_source_id; - guint16 ret; + int acquire_source_id; + GVariant* sourceData = create_source_data (source_id, domain_id, name, source_class_id, source_state, volume, visible, available, interrupt, sound_property_list, connection_format_list, main_property_list, nconf_routing, nconf_command); - GVariant* input = g_variant_ref_sink(sourceData); - audiomanager_routinginterface_call_register_source_sync( - am_route_bus, - input, - &acquire_source_id, - &ret, - NULL, &err); - g_variant_unref(input); + ErrorCode ec = am_proxy_register_source(sourceData, &acquire_source_id); - if(IS_SEND_ERROR(err, request) == 0) return; + if(!SEND_RESULT(ec, request)) return; /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 4, - KEY_ERROR, ret, + KEY_ERROR, ec, KEY_SOURCE_ID, acquire_source_id); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } void deregisterSource(struct afb_req request) { guint16 source_id; - guint16 ret; GError *err = NULL; if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){ afb_req_fail(request, "wrong-request", NULL); } - audiomanager_routinginterface_call_deregister_source_sync( - am_route_bus, - source_id, - &ret, - NULL, &err - ); - if(IS_SEND_ERROR(err, request) == 0) return; + ErrorCode ec = am_proxy_deregister_source(source_id); + if(!SEND_RESULT(ec, request)) return; /*create response json object*/ struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, - KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + KEY_ERROR, ec); + const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } @@ -708,7 +652,7 @@ void subscribe(struct afb_req request) struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ret); afb_req_success(request, res, info); } @@ -745,7 +689,7 @@ void unsubscribe(struct afb_req request) struct json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 2, KEY_ERROR, ret); - char *info = get_response_audiomanager_massage_error(ret); + const char* info = get_response_audiomanager_massage_error(ret); afb_req_success(request, res, info); } @@ -754,159 +698,203 @@ void unsubscribe(struct afb_req request) ****** High Level API *********** * */ -void streamOpen(struct afb_req req){ + + +#ifdef ENABLE_AGL_AHL + +void stream_open(struct afb_req request){ AFB_DEBUG("call %s", __FUNCTION__); // register audio role and endpoint + // get audio_role const gchar* audio_role = afb_req_value(request, KEY_AHL_AUDIO_ROLE); /* s */ if(!audio_role) { afb_req_fail(request, "wrong request", "Please input 'audio_role' as key"); return; } - guint16 endpoint_type = 0, endpoint_id = 0; - - endpoint_id = get_sink_id(request, KEY_AHL_ENDPOINT_ID); - if(-1 == endpoint_id) return; - + // get endpoint + guint16 endpoint_type = ENDPOINT_SOURCE, endpoint_id = 0; + if(REQ_OK != get_sink_id(request, KEY_AHL_ENDPOINT_ID, &endpoint_id)){return;} get_value_uint16(request, KEY_AHL_ENDPOINT_TYPE, &endpoint_type); - if(endpoint_type == ENDPOINT_SINK){ + + if(endpoint_type != ENDPOINT_SOURCE){ AFB_WARNING("register sink from application is not supported"); - afb_req_fail(request,"wrong-request", "register sink from application is not supported"); + afb_req_fail(request,"wrong-request", "register source from application is only supported"); return; } // call registerSource - json_object *jreq = afb_req_json(req); + json_object *jreq = afb_req_json(request); json_object *response = json_object_new_object(); - json_object_object_add(jreq, KEY_SOURCE_ID, json_object_new_string(audio_role)); - afb_service_call_sync("soundmanager", "registerSource", jreq, &response); + json_object_object_add(jreq, KEY_APPNAME, json_object_new_string(audio_role)); - json_object j_sid = NULL; - if(!json_object_object_get_ex(response, KEY_ERROR, &j_sid) { - afb_req_fail(request, NULL, "Failed streamOpen"); + afb_service_call_sync("soundmanager", "registerSource", jreq, &response); + // jreq is released by afb_service_call_sync then don't release jreq here. + + AFB_DEBUG("request result :%s", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY)); + + json_object *j_resp, *j_sid, *j_err; + int sid = -1, ret = -1; + if(json_object_object_get_ex(response, KEY_RESPONSE, &j_resp)){ + AFB_DEBUG("Get response success: %s", json_object_to_json_string_ext(j_resp, JSON_C_TO_STRING_PRETTY)); + json_object_object_get_ex(j_resp, KEY_SOURCE_ID, &j_sid); + json_object_object_get_ex(j_resp, KEY_ERROR, &j_err); + // registerSource must return sourceID and error then I don't check whether sid and ret is in json_object. + sid = json_object_get_int(j_sid); + ret = json_object_get_int(j_err); + json_object_put(j_resp); + json_object_put(j_sid); + json_object_put(j_err); + json_object_put(response); + }else { + afb_req_fail(request, "unknown-error", "Failed stream_open"); + json_object_put(response); return; } - int sid = json_object_get_int(j_sid); - - // create client context - smClientCtxt* ctxt = (smClientCtxt*)malloc(sizeof smClientCtxt); - char* appid = afb_req_get_application_id((req); - ctxt->appname = malloc(MAX_LENGTH_STRING * sizeof(char)); - strcpy(ctxt->appname, appid, MAX_LENGTH_STRING); - ctxt->source->sourceID = sid; - ctxt->sink->sinkID = endpoint_id; - ctxt->type = endpoint_type; - ctxt->event->asyncSetSourceState = afb_daemon_make_event("asyncSetSourceState"); - afb_req_context_set(req, ctxt, on_client_context_terminated); - - // response + json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 4, KEY_ERROR, ret, - KEY_CONNECTION_ID); - char *info = get_response_audiomanager_massage_error(ret); + KEY_AHL_REP_STREAM_ID, sid); + const char* info = get_response_audiomanager_massage_error(ret); + create_client_context(request, sid, endpoint_id, endpoint_type); + int index = sm_search_routing_event_name_index(SM_EVENT_STREAM_STATE_EVENT); + afb_req_subscribe(request, *routing_event_list[index].event); afb_req_success(request, res, info); - } -void streamClose(struct afb_req req){ -// TODO : wtite function -} - -void setStreamState(struct afb_req req){ -// TODO : wtite function -} - -/* -********** Callback Function invoked by Audio Manager ********** -*/ - -typedef struct source { - struct source* next; - int sourceID; - int mainConnectionID; -} source; - -typedef struct sink { - struct sink* next; - int sinkID; -} sink; - -typedef struct events { - struct afb_event asyncSetSourceState; +void stream_close(struct afb_req request){ + ErrorCode ec; + gint16 source_id = 0; + smClientCtxt* ctxt = afb_req_context_get(request); + if(NULL == ctxt){ + AFB_ERROR("Context is not registered"); + afb_req_fail(request, "wrong-request", "call stream_open at first"); + return; + } + if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){ + if(REQ_OK != get_value_uint16(request, KEY_AHL_REP_STREAM_ID, &source_id)){ + afb_req_fail(request, "wrong-request", "Unable to find sourceID"); + return; + } + } + if(source_id != ctxt->source.sourceID){ + AFB_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID); + afb_req_fail(request, "wrong-request", "sourceID is not yours"); + return; + } + if(ctxt->source.mainConnectionID > 0){ + pending_list = add_pending(pending_list, source_id); + ec = am_proxy_disconnect(ctxt->source.mainConnectionID); + if(!SEND_RESULT(ec, request)) { + del_pending(pending_list, source_id); + return; + } + ctxt->source.mainConnectionID = -1; + } + else{ + AFB_NOTICE("Stream %d doesn't have connection. Ignore disconnect", ctxt->source.sourceID); + return; + } + /*create response json object*/ + struct json_object *res = json_object_new_object(); + sm_add_object_to_json_object_func(res, __FUNCTION__, 2, + KEY_ERROR, ec); + const char* info = get_response_audiomanager_massage_error(ec); + afb_req_success(request, res, info); } -typedef struct smClientCtxt{ - char* appname; - struct source source; - struct sink sink; - struct events events; -} +void set_stream_state(struct afb_req request){ + gint16 source_id = 0; + int main_connection_id = -1; + ErrorCode ec = OK; + int mute_state; + smClientCtxt* ctxt = afb_req_context_get(request); + if(NULL == ctxt){ + AFB_ERROR("Context is not registered"); + afb_req_fail(request, "wrong-request", "call stream_open at first"); + return; + } -static void on_client_context_terminated(void *data){ - smClientCtxt ctxt = (smClientCtxt*)data; - source* source_deleted; - if(ctxt == NULL){ + // get sourceID from request + if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){ + if(REQ_OK != get_value_uint16(request, KEY_AHL_REP_STREAM_ID, &source_id)){ + afb_req_fail(request, "wrong-request", "Unable to find sourceID"); + return; + } + } + if(source_id != ctxt->source.sourceID){ + AFB_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID); + afb_req_fail(request, "wrong-request", "sourceID is not yours"); return; } - AFB_DEBUG("Client %s session is closed", ctxt->appname); - while(ctxt->source->next != NULL){ - gint16 ret; - GError *err = NULL; - audiomanager_routinginterface_call_deregister_source_sync( - am_route_bus, - ctxt->source->sourceID, - &ret, NULL, &err - ); - source = ctxt->source->next; - free(ctxt->source->source); - if(err != NULL){ - AFB_ERROR("failed to call deregisterSource"); + if(REQ_OK != get_value_int32(request, KEY_AHL_MUTE, &mute_state)){ + mute_state = AHL_STREAM_UNMUTE; + AFB_INFO("Mute state is not set. Set mute state %d(unmute) as default.", mute_state); + } + AFB_INFO("souceID: %d , mute : %d", source_id, mute_state); + + if(AHL_STREAM_MUTE == mute_state){ + if(ctxt->source.mainConnectionID > 0){ + pending_list = add_pending(pending_list, source_id); + ec = am_proxy_disconnect(ctxt->source.mainConnectionID); + if(!SEND_RESULT(ec, request)){ + del_pending(pending_list, source_id); + return; + } + ctxt->source.mainConnectionID = -1; + } + else{ + AFB_NOTICE("Stream %d doesn't have connection. Ignore disconnect", ctxt->source.sourceID); + ec = ACTION_IMPOSSIBLE; } - else if(ret != NULL) - ++(ctxt->source); - AFB_DEBUG("ret = %d", ret); } - free(ctxt->appname); - free(ctxt->event); - free(ctxt); + else{ + pending_list = add_pending(pending_list, source_id); + ec = am_proxy_connect(source_id, ctxt->sink.sinkID, &main_connection_id); + ctxt->source.mainConnectionID = main_connection_id; + if(!SEND_RESULT(ec, request)) { + del_pending(pending_list, source_id); + return; + } + } + /*create response json object*/ + struct json_object *res = json_object_new_object(); + sm_add_object_to_json_object_func(res, __FUNCTION__, 2, + KEY_ERROR, ec); + const char* info = get_response_audiomanager_massage_error(ec); + afb_req_success(request, res, info); } +#endif -static void on_new_main_connection(AudiomanagerCommandinterface* interface, - GVariant* mainConnection) +/* +********** Callback Function invoked by Audio Manager ********** +*/ + +static void on_new_main_connection(int mainConnectioID, + int sourceID, int sinkID, int delay, int connectionState) { AFB_DEBUG("%s is called",__FUNCTION__); - guint16 mcid, srcid, sinkid; - gint16 delay, constate; - g_variant_get( - mainConnection,"(qqqnn)", &mcid, &srcid, &sinkid, &delay, &constate); - struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj,10, - KEY_MAIN_CONNECTION_ID, mcid, - KEY_SOURCE_ID, srcid, - KEY_SINK_ID, sinkid, + KEY_MAIN_CONNECTION_ID, mainConnectioID, + KEY_SOURCE_ID, sourceID, + KEY_SINK_ID, sinkID, KEY_DELAY, delay, - KEY_CONNECTION_STATE, constate - ); - AFB_DEBUG("json object :%s:",json_object_to_json_string(res_obj)); - + KEY_CONNECTION_STATE, connectionState); afb_event_push(ev_new_connection, res_obj); } -static void on_removed_main_connection( - AudiomanagerCommandinterface* interface, guint16 mainConnectionID) +static void on_removed_main_connection(int mainConnectionID) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); - sm_add_object_to_json_object(res_obj, 2, - KEY_MAIN_CONNECTION_ID, mainConnectionID); + json_object_object_add(res_obj, KEY_MAIN_CONNECTION_ID, json_object_new_int(mainConnectionID)); afb_event_push(ev_removed_main_connection, res_obj); } -static void on_main_connection_state_changed( - AudiomanagerCommandinterface* interface, guint16 connectionID, gint16 connectionState) +static void on_main_connection_state_changed(int connectionID, int connectionState) { AFB_DEBUG("%s is called",__FUNCTION__); @@ -917,8 +905,7 @@ static void on_main_connection_state_changed( afb_event_push(ev_main_connection_state_changed, res_obj); } -static void on_volume_changed( - AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 volume) +static void on_volume_changed(int sinkID, int volume) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); @@ -928,8 +915,7 @@ static void on_volume_changed( afb_event_push(ev_volume_changed, res_obj); } -static void on_sink_mute_state_changed( - AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 mute) +static void on_sink_mute_state_changed(int sinkID, int mute) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); @@ -942,15 +928,28 @@ static void on_sink_mute_state_changed( /* ********** Callback Function invoked by Audio Manager Routing Interface********** */ -static void on_set_routing_ready( - AudiomanagerRoutinginterface* interface) +static void on_set_routing_ready(void) { AFB_DEBUG("%s is called",__FUNCTION__); + struct domain_data ddata = { + .domainID = DYNAMIC_DOMAIN_ID, + .name = "SoundManager", + .busname = SOUND_MANAGER_BUS_NAME, + .nodename = "soundmanager", + .early = FALSE, + .complete = TRUE, + .state = DS_CONTROLLED + }; + ErrorCode ec = am_proxy_register_domain(create_domain_data(&ddata) , &SOUNDMANAGER_DOMAIN_ID); + if(!SEND_RESULT_NO_RESP(ec)){ + AFB_WARNING("Failed to re-gisterDomain when asyncAbort"); + return; + } + AFB_NOTICE("Sound Manager re-register domain, the old infomation may be lost"); afb_event_push(ev_set_routing_ready, NULL); } -static void on_set_routing_rundown( - AudiomanagerRoutinginterface* interface) +static void on_set_routing_rundown(void) { AFB_DEBUG("%s is called",__FUNCTION__); afb_event_push(ev_set_routing_ready, NULL); @@ -965,122 +964,71 @@ static void on_set_routing_rundown( * Sound Manager just sends ack to Audio Manager in charge of applications. * */ -static gboolean on_async_abort( - AudiomanagerRoutingSoundmanager *object, - GDBusMethodInvocation *invocation, - guint16 arg_handle) +static void on_async_abort(int handle) { AFB_DEBUG( "%s called", __FUNCTION__); /* Nothing To Do. If it is better to implement something, I will implement */ - 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) +static void on_async_connect(int handle, int connectionID, + int sourceID, int sinkID, int connectionFormat) { AFB_DEBUG( "%s called", __FUNCTION__); struct json_object* ev_obj = json_object_new_object(); sm_add_object_to_json_object(ev_obj, 10, - KEY_HANDLE, arg_handle, - KEY_CONNECTION_ID, arg_connectionID, - KEY_SOURCE_ID, arg_sourceID, - KEY_SINK_ID, arg_sinkID, - KEY_CONNECTION_FORMAT, arg_connectionFormat); + KEY_HANDLE, handle, + KEY_CONNECTION_ID, connectionID, + KEY_SOURCE_ID, sourceID, + KEY_SINK_ID, sinkID, + KEY_CONNECTION_FORMAT, connectionFormat); afb_event_push(ev_async_connect, ev_obj); - - /* 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 */ - GError* err = NULL; - audiomanager_routinginterface_call_ack_connect_sync( - am_route_bus, - arg_handle, - arg_connectionID, - 0, - NULL, &err); - if(err != NULL) - { - AFB_ERROR( "Can't send ack to sound manager adapter %s", __FUNCTION__); - return FALSE; - } - return TRUE; } -static gboolean on_async_disconnect( - AudiomanagerRoutingSoundmanager *object, - GDBusMethodInvocation *invocation, - guint16 arg_handle, - guint16 arg_connectionID) +static void on_async_disconnect(int handle, int connectionID) { AFB_DEBUG( "%s called", __FUNCTION__); struct json_object* ev_obj = json_object_new_object(); sm_add_object_to_json_object(ev_obj, 4, - KEY_HANDLE, arg_handle, - KEY_CONNECTION_ID, arg_connectionID); + KEY_HANDLE, handle, + KEY_CONNECTION_ID, connectionID); afb_event_push(ev_async_disconnect, ev_obj); - GError* err = NULL; - audiomanager_routinginterface_call_ack_disconnect_sync( - am_route_bus, - arg_handle, - arg_connectionID, - 0, - NULL, &err); - if(err != NULL) - { - 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) +static void on_async_set_sink_volume(int handle, int sinkID, + int volume, int ramp, int time) { AFB_DEBUG( "%s called", __FUNCTION__); - GError* err = NULL; - audiomanager_routinginterface_call_ack_set_sink_volume_sync( - am_route_bus, - arg_handle, - arg_volume, - 0, NULL, &err); - if(err != NULL);{ - 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) +static void on_async_set_source_state(int handle, int sourceID, int sourceState) { - AFB_DEBUG( "%s called", __FUNCTION__); + AFB_INFO( "%s called. handle : %d, sourceID: %d, state: %s", __FUNCTION__, handle, sourceID, get_source_state_key(sourceState)); struct json_object* ev_obj = json_object_new_object(); - char* ss_key = get_source_state_key(arg_sourceState); + const char* ss_key = get_source_state_key(sourceState); sm_add_object_to_json_object(ev_obj, 4, - KEY_HANDLE, arg_handle, - KEY_SOURCE_ID, arg_sourceID); + KEY_HANDLE, handle, + KEY_SOURCE_ID, sourceID); json_object_object_add(ev_obj, KEY_SOURCE_STATE, json_object_new_string(ss_key)); +#ifdef ENABLE_AGL_AHL + struct pending* pd = get_pending(pending_list, sourceID); + if(pd != NULL){ + int ack_ok = 0; + am_proxy_ack_set_source_state(handle, ack_ok); + pending_list = del_pending(pending_list, sourceID); + } + json_object_object_add(ev_obj, KEY_AHL_EVENT_NAME, json_object_new_string(AHL_EVENT_NAME)); + sm_add_object_to_json_object(ev_obj, 4, + KEY_AHL_REP_STREAM_ID, sourceID, + KEY_AHL_STATE_EVENT, sourceState); + json_object_get(ev_obj); + afb_event_push(ev_stream_state_event, ev_obj); +#endif afb_event_push(ev_async_set_source_state, ev_obj); /* Applications must return ackSetSourceState to look sourceID, then Sound Manager doen't return ackSetSourceState */ /*audiomanager_routinginterface_call_ack_set_source_state_sync( am_route_bus, - arg_handle, + handle, NULL, NULL, &err);*/ } @@ -1091,139 +1039,93 @@ static gboolean on_async_set_source_state( * */ -static int registerDomain() -{ - /* Default Setting of Sound Manager Domain */ - struct domain_data ddata = { - .domainID = DYNAMIC_DOMAIN_ID, - .name = "SoundManager", - .busname = SOUND_MANAGER_BUS_NAME, - .nodename = "soundmanager", - .early = FALSE, - .complete = TRUE, - .state = DS_CONTROLLED - }; - GVariant* domainData = create_domain_data(&ddata); - gchar* retBusName = SOUND_MANAGER_BUS_NAME; - gchar* retPath = SOUND_MANAGER_PATH; - gchar* retInterface = SOUND_MANAGER_RETURN_INTERFACE; - guint16 domain_id; - GError *err = NULL; - guint16 error; +static void on_client_context_terminated(void *data){ + smClientCtxt* ctxt = (smClientCtxt*)data; + if(NULL == ctxt){ + return; + } + AFB_DEBUG("Client %s session is closed", ctxt->appname); + free(ctxt->appname); + free(ctxt); + // TODO : After application is terminated, what should we do? +} - audiomanager_routinginterface_call_register_domain_sync( - am_route_bus, - domainData, - retBusName, - retPath, - retInterface, - &domain_id, &error, - NULL, &err); - if(err != NULL){ - AFB_ERROR( "Failed to call %s", __FUNCTION__); - return -1; +static void create_client_context(afb_req request, guint16 source_id, guint16 sink_id, int endpoint_type){ + AFB_DEBUG(""); + static int applicationID_debug = 0; + smClientCtxt* ctxt = malloc(sizeof(smClientCtxt)); + ctxt->appname = malloc(MAX_LENGTH_STR * sizeof(char)); + char *appid = afb_req_get_application_id(request); + if(NULL == appid){ + char debug[MAX_LENGTH_STR]; + //char* debug; + snprintf(debug, MAX_LENGTH_STR, "%s%d", "applicationID_debug", ++applicationID_debug); + AFB_INFO("application id is not set. Define as %s", debug); + strncpy(ctxt->appname, debug, MAX_LENGTH_STR); } - if(error != 0) - { - AFB_ERROR( "Failed to register domain"); - return error; + else{ + strncpy(ctxt->appname, appid, MAX_LENGTH_STR); } - SOUNDMANAGER_DOMAIN_ID = domain_id; - AFB_NOTICE( "Complete registered domain id:%d",SOUNDMANAGER_DOMAIN_ID); - return 0; + ctxt->source.sourceID = source_id; + ctxt->sink.endpointID = sink_id; + ctxt->sink.sinkID = sink_id; + ctxt->sink.endpointType = endpoint_type; + afb_req_context_set(request, ctxt, on_client_context_terminated); } -static int create_adapter() -{ - GError *error = NULL; - gboolean ret; - GVariant *value; - system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); - if (error) - { - g_error_free(error); - return -1; +void set_default_sink(){ + GVariant *mainSinkList; + ErrorCode ec = am_proxy_get_list_main_sinks(&mainSinkList); + if(ec != OK){ + return; } - 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); - ret = g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(sm_adapter), system_conn, SOUND_MANAGER_PATH, &error); - if (FALSE == ret) - { - AFB_ERROR( "failed to export"); - g_error_free(error); - g_object_unref(system_conn); - return -1; + gsize size = g_variant_n_children(mainSinkList); + + if(0 == size){ + AFB_NOTICE("Sink is not registered in Audio Manaager then can't set default sinkID, then set as %d", DEFAULT_SINK); + return; } - return 0; -} + guint16 sinkid, sinkclassid; + gchar* sinkname; + gint16 av, avr, volume, mutestate; + // Take the first one as default sinkID + GVariant* child = g_variant_get_child_value(mainSinkList, 0); + g_variant_get( + child,"(qs(nn)nnq)", + &sinkid, &sinkname, &av, &avr, &volume, &mutestate, &sinkclassid); + AFB_DEBUG( "sinkID: %d, sinkName: %s, availability: %d, availableReason: %d, volume: %d, muteState: %d, sinkClassID: %d", + sinkid, sinkname, av, avr, volume, mutestate, sinkclassid); + g_variant_unref(child); + g_variant_unref(mainSinkList); -static void on_name_lost(GDBusServer *server, GDBusConnection *conn, gpointer data) -{ - AFB_WARNING("%s called", __FUNCTION__); + set_default_sinkID(sinkid); } int preinit() { - int ret; AFB_INFO("Initialize Dbus object"); - /* Initialize Dbus interface */ - if(am_cmd_bus || am_route_bus) - { - AFB_ERROR( "Dbus object to Audio Manager is already created"); - goto out; - } - 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 - ); - if(!am_cmd_bus || !am_route_bus) - { - goto out; + /* Initialize Dbus interface */ + ErrorCode ec = initialize_proxy(); + if(ec == NOT_INITIALIZED){ + AFB_ERROR("Failed to initialize"); + return -1; } AFB_NOTICE( "Finish Initialize"); return 0; -out: - AFB_ERROR("Failed to initialize"); - return -1; } int sm_init() { AFB_NOTICE("Initialize event receive setting"); - printf("Initialize event receive setting"); - int ret; + /* Initialize make event */ size_t size = sizeof cmd_evlist / sizeof *cmd_evlist; + ErrorCode ec; /*create event*/ /*ToDo Hash table is better. And event should be created in the loop @@ -1233,15 +1135,15 @@ int sm_init() ev_removed_main_connection = afb_daemon_make_event(cmd_evlist[2]); ev_sink_mute_state_changed = afb_daemon_make_event(cmd_evlist[3]); ev_main_connection_state_changed = afb_daemon_make_event(cmd_evlist[4]); - command_event_list[0].name = cmd_evlist[0]; + command_event_list[0].name = strdup(cmd_evlist[0]); command_event_list[0].event = &ev_volume_changed; - command_event_list[1].name = cmd_evlist[1]; + command_event_list[1].name = strdup(cmd_evlist[1]); command_event_list[1].event = &ev_new_connection; - command_event_list[2].name = cmd_evlist[2]; + command_event_list[2].name = strdup(cmd_evlist[2]); command_event_list[2].event = &ev_removed_main_connection; - command_event_list[3].name = cmd_evlist[3]; + command_event_list[3].name = strdup(cmd_evlist[3]); command_event_list[3].event = &ev_sink_mute_state_changed; - command_event_list[4].name = cmd_evlist[4]; + command_event_list[4].name = strdup(cmd_evlist[4]); command_event_list[4].event = &ev_main_connection_state_changed; /* create routing event */ @@ -1250,89 +1152,72 @@ int sm_init() ev_async_connect = afb_daemon_make_event(route_evlist[2]); ev_async_set_source_state = afb_daemon_make_event(route_evlist[3]); ev_async_disconnect = afb_daemon_make_event(route_evlist[4]); +#ifdef ENABLE_AGL_AHL + ev_stream_state_event = afb_daemon_make_event(route_evlist[5]); +#endif - routing_event_list[0].name = route_evlist[0]; + routing_event_list[0].name = strdup(route_evlist[0]); routing_event_list[0].event = &ev_set_routing_ready; - routing_event_list[1].name = route_evlist[1]; + routing_event_list[1].name = strdup(route_evlist[1]); routing_event_list[1].event = &ev_set_routing_rundown; - routing_event_list[2].name = route_evlist[2]; + routing_event_list[2].name = strdup(route_evlist[2]); routing_event_list[2].event = &ev_async_connect; - routing_event_list[3].name = route_evlist[3]; + routing_event_list[3].name = strdup(route_evlist[3]); routing_event_list[3].event = &ev_async_set_source_state; - routing_event_list[4].name = route_evlist[4]; + routing_event_list[4].name = strdup(route_evlist[4]); routing_event_list[4].event = &ev_async_disconnect; - /*for(size_t i = 0; i < size; ++i) - { - struct afb_event afbev = afb_daemon_make_event(afbitf->daemon, cmd_evlist[i])); - size_t afbev_size = sizeof afbev; - size_t key_size = sizeof cmd_evlist[i]; - - struct event ev = {cmd_evlist[i],afbev}; - command_event_list[i] = malloc(key_size + afbev_size); - command_event_list[i] = ev; - search_result = hsearch(entry, FIND); - if(search_result) - AFB_NOTICE( "event name is %s", search_result->key); - }*/ - - /* Initialize dbus event thread */ - if(!am_cmd_bus || !am_route_bus) - { - goto ev_init_out; - } - /* initialize signal from audio manager command interface */ - 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); +#ifdef ENABLE_AGL_AHL + routing_event_list[5].name = strdup(route_evlist[5]); + routing_event_list[5].event = &ev_stream_state_event; +#endif + + am_event callback = { + .on_new_main_connection = on_new_main_connection, + .on_removed_main_connection = on_removed_main_connection, + .on_main_connection_state_changed = on_main_connection_state_changed, + .on_volume_changed = on_volume_changed, + .on_sink_mute_state_changed = on_sink_mute_state_changed, + .on_set_routing_ready = on_set_routing_ready, + .on_set_routing_rundown = on_set_routing_rundown + }; + set_event_callback(&callback); /* Get soundmanager adapter bus */ - 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); - ret = create_adapter(); - if(ret != 0) - { - goto ev_init_out; + am_instruction instruction = { + .on_async_abort = on_async_abort, + .on_async_connect = on_async_connect, + .on_async_disconnect = on_async_disconnect, + .on_async_set_sink_volume = on_async_set_sink_volume, + .on_async_set_source_state = on_async_set_source_state + }; + ec = open_soundmanager_interface(&instruction); + if(ec != OK){ + AFB_ERROR("Failed to create sound manager interface"); + return -1; } - ret = registerDomain(); - if(ret != 0) - { - AFB_ERROR("registerDomain error: %s",get_response_audiomanager_massage_error(ret)); - goto ev_init_out; + GError* err = NULL; + struct domain_data ddata = { + .domainID = DYNAMIC_DOMAIN_ID, + .name = "SoundManager", + .busname = SOUND_MANAGER_BUS_NAME, + .nodename = "soundmanager", + .early = FALSE, + .complete = TRUE, + .state = DS_CONTROLLED + }; + ec = am_proxy_register_domain(create_domain_data(&ddata) , &SOUNDMANAGER_DOMAIN_ID); + if(!SEND_RESULT_NO_RESP(ec)){ + return -1; } + if(ec != OK){ + AFB_ERROR("Failed to registerDomain : %s", get_response_audiomanager_massage_error(ec)); + return -1; + } + AFB_DEBUG("domainID : %d", SOUNDMANAGER_DOMAIN_ID); - AFB_INFO("Finish Initialize event receive setting"); + set_default_sink(); return 0; - -ev_init_out: - AFB_WARNING( "DBus connection is not created"); - return -1; } void onevent(const char *event, struct json_object *object) diff --git a/src/soundmanager.h b/src/soundmanager.h index e9e65ea..f79643b 100644 --- a/src/soundmanager.h +++ b/src/soundmanager.h @@ -13,23 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * @file soundmanager.h - * @brief Sound Manager API - */ #ifndef SOUNDMANAGER_H #define SOUNDMANAGER_H #define _GNU_SOURCE #define AFB_BINDING_VERSION 2 #include <afb/afb-binding.h> -#include "dbus/audio_manager_interface.h" - -struct event{ - char* name; - struct afb_event* event; - }; /* ********** Method of Sound Manager (API) ********** @@ -315,6 +304,8 @@ void subscribe(struct afb_req request); */ void unsubscribe(struct afb_req request); +#ifdef ENABLE_AGL_AHL + /** * Application High Level API for AGL * This function opens "stream". @@ -337,7 +328,7 @@ void unsubscribe(struct afb_req request); * #### Note * TODO : write note */ -void streamOpen(struct afb_req req); +void stream_open(struct afb_req req); /** * Application High Level API for AGL @@ -353,28 +344,30 @@ void streamOpen(struct afb_req req); * #### Note * TODO : write note */ -void streamClose(struct afb_req req); +void stream_close(struct afb_req req); /** * Application High Level API for AGL * This function set stream state. - * This function set the availability and calls connect function of Audio Manager - * and returns the result of policy check. + * This function set the availability and calls connect function of Audio Manager. + * Policy check result will be notified by event.. * * #### Parameters * - stream_id : Stream id which is returned in stream_open. - * - mute : Stream state as int + * - mute : Stream state as int. 0 is unmute, and 1 is mute. Sound manager set this parameter as unmute as default * #### Return * - error : Error status number. If error is 0, it means the request is accepted, otherwise error message is attached with error code in reply message. * #### Note - * TODO : write note + * After set unmute, then 'asyncSetSourceState' and 'stream_state_event' is pushed. These events contains information of state judged by AudioManager. */ -void setStreamState(struct afb_req req); +void set_stream_state(struct afb_req req); /* ********** Event list from Sound Manager ********** */ +#endif + /* ********** Application Framework Imprement ********** @@ -384,13 +377,15 @@ void setStreamState(struct afb_req req); * array of the verbs exported to afb-daemon */ const struct afb_verb_v2 binding_verbs[]= { +#ifdef ENABLE_AGL_AHL // High Level API of AGL -{ .verb = "stream_open", .callback = streamOpen, .auth = NULL, - .info = "Open stream." , .session = AFB_SESSION_NONE}, -{ .verb = "stream_close", .callback = streamClose, .auth = NULL, +{ .verb = "stream_open", .callback = stream_open, .auth = NULL, + .info = "Open stream." , .session = AFB_SESSION_NONE}, +{ .verb = "stream_close", .callback = stream_close, .auth = NULL, .info = "Close stream" , .session = AFB_SESSION_NONE}, -{ .verb = "set_stream_state", .callback = setStreamState, .auth = NULL, - .info = "Set stream state" , .session = AFB_SESSION_NONE}, +{ .verb = "set_stream_state", .callback = set_stream_state, .auth = NULL, + .info = "Set stream state" , .session = AFB_SESSION_NONE}, +#endif // Adaption API of Audio Manager { .verb = "connect", .callback = connect, .auth = NULL, .info = "Connect source id and sink id" , .session = AFB_SESSION_NONE}, @@ -407,11 +402,11 @@ const struct afb_verb_v2 binding_verbs[]= { { .verb = "getListMainSinks", .callback = getListMainSinks, .auth = NULL, .info = "Get MainSink List" , .session = AFB_SESSION_NONE}, { .verb = "getListMainSources", .callback = getListMainSources, .auth = NULL, - .info = "Get MainSource List" , .session = AFB_SESSION_NONE}, + .info = "Get MainSource List" , .session = AFB_SESSION_NONE}, { .verb = "registerSource", .callback = registerSource, .auth = NULL, - .info = "Register autio role" , .session = AFB_SESSION_NONE}, + .info = "Register autio role" , .session = AFB_SESSION_NONE}, { .verb = "deregisterSource", .callback = deregisterSource, .auth = NULL, - .info = "Deregister audio role" , .session = AFB_SESSION_NONE}, + .info = "Deregister audio role" , .session = AFB_SESSION_NONE}, { .verb = "ackConnect", .callback = ackConnect, .auth = NULL, .info = "Acknowledge of asyncConnect" , .session = AFB_SESSION_NONE}, { .verb = "ackDisconnect", .callback = ackDisconnect, .auth = NULL, @@ -437,4 +432,4 @@ const struct afb_binding_v2 afbBindingV2 = { .onevent = onevent }; -#endif //SOUNDMANAGER_H +#endif //SOUNDMANAGER_H
\ No newline at end of file |