/* * Copyright (c) 2017 TOYOTA MOTOR CORPORATION * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "soundmanager.h" #include "sm-def.h" #include "sm-error.h" #include "sm-helper.h" struct event{ char* name; struct afb_event* event; }; 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; static guint16 SOUNDMANAGER_DOMAIN_ID; static struct event command_event_list[COMMAND_EVENT_NUM]; static struct event routing_event_list[ROUTING_EVENT_NUM]; static struct afb_event ev_new_connection; static struct afb_event ev_removed_main_connection; static struct afb_event ev_volume_changed; static struct afb_event ev_sink_mute_state_changed; static struct afb_event ev_main_connection_state_changed; /* Routing interface event */ static struct afb_event ev_set_routing_ready; 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; /* ********** Method of Sound Manager (API) ********** */ 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; 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. select appname(speaker) or sourceID(sinkID). If appname is desired, it changes to sourceID(sinkID) */ const char* default_sink = afb_req_value (request, KEY_SINK_ID); if(default_sink != NULL){ if((strlen("default") == strlen(default_sink)) && (0 == strncmp("default", default_sink, strlen("default")))){ sink_id = DEFAULT_SINK; req_err2 = REQ_OK; } else{ req_err2 = get_value_uint16(request, KEY_SINK_ID, &sink_id); } } if((req_err1 != REQ_OK) || (req_err2 != REQ_OK)) { AFB_INFO("get_value_uint16 source ret = %d,sink ret = %d", source_id, sink_id); AFB_NOTICE("wrong request"); afb_req_fail(request,"wrong-request",NULL); return; } audiomanager_commandinterface_call_connect_sync( am_cmd_bus, source_id, sink_id, &ret, &main_connectionID, NULL, &err); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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, KEY_MAIN_CONNECTION_ID, main_connectionID); char *info = get_response_audiomanager_massage_error(ret); afb_req_success(request, res, info); } void disconnect (struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); guint16 id; gint16 ret; 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); 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); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res_obj, info); /* return error num as status */ } 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); AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_VOLUME, vol); if((req_err1 != REQ_OK) || (req_err2 != REQ_OK)) { afb_req_fail(request,"wrong-request", NULL); return; } audiomanager_commandinterface_call_set_volume_sync( am_cmd_bus, sink_id, vol, &ret, NULL, &err); AFB_DEBUG( "ret = %d", ret); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res_obj, info); /* return error num as status */ } 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); AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_VOLUME_STEP, vol); if((req_err1 != REQ_OK) || (req_err2 != REQ_OK)) { afb_req_fail(request,"wrong-request", NULL); return; } audiomanager_commandinterface_call_volume_step_sync( am_cmd_bus, sink_id, vol, &ret, NULL, &err); AFB_DEBUG( "ret = %d", ret); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res_obj, info); /* return error num as status */ } 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); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res_obj, info); /* return error num as status */ } 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 ); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); return; } /* create response */ struct json_object *array_res = json_object_new_array(); 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); if(size <= 0) { AFB_NOTICE( "mainConnectionList size is 0"); } else{ for(int i = 0; i < size; ++i) { guint16 mcid, srcid, sinkid; gint16 delay, constate; g_variant_get_child( mainConnectionList,i,"(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_DELAY, delay, KEY_CONNECTION_STATE, constate ); json_object_array_add(array_res,res_obj); } } AFB_DEBUG("json object :%s:",json_object_to_json_string(array_res)); afb_req_success(request, array_res, "Success to get main connection list"); } 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 ); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); return; } /* create response */ struct json_object *response = json_object_new_object(); gsize size = g_variant_n_children(mainSourceList); AFB_DEBUG( "%s size is %u",__FUNCTION__, (uint16_t)size); sm_add_object_to_json_object_func(response, __FUNCTION__, 0); if(size <= 0) { AFB_NOTICE("%s size is 0", __FUNCTION__); } else{ struct json_object *array_res = json_object_new_array(); for(int i = 0; i < size; ++i) { guint16 sourceid, sourceclassid; gchar* sourcename; gint16 av; gint16 avr; GVariant* child = g_variant_get_child_value(mainSourceList, i); g_variant_get( child,"(qs(nn)q)", &sourceid, &sourcename, &av, &avr, &sourceclassid); AFB_DEBUG( "sourceID: %d, sourceName: %s, availability: %d, availableReason: %d, sourceClassID: %d", sourceid, sourcename, av, avr, sourceclassid); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj, 2, KEY_SOURCE_ID, sourceid); json_object_object_add(res_obj, KEY_SINK_NAME, json_object_new_string(sourcename)); sm_add_object_to_json_object(res_obj,6, KEY_AVAILABILITY, av, KEY_AVAILABILITY_REASON, avr, KEY_SOURCE_CLASS_ID, sourceclassid); json_object_array_add(array_res,res_obj); g_variant_unref(child); } json_object_object_add(response, "sinks", array_res); } afb_req_success(request, response, "Success to get main source list"); g_variant_unref(mainSourceList); } 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 ); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); return; } /* create response */ struct json_object *response = json_object_new_object(); gsize size = g_variant_n_children(mainSinkList); AFB_DEBUG( "%s size is %u",__FUNCTION__, (uint16_t)size); sm_add_object_to_json_object_func(response, __FUNCTION__, 0); if(size <= 0) { AFB_NOTICE("%s size is 0", __FUNCTION__); } else{ struct json_object *array_res = json_object_new_array(); for(int i = 0; i < size; ++i) { guint16 sinkid, sinkclassid; gchar* sinkname; gint16 av; gint16 avr; gint16 volume, mutestate; GVariant* child = g_variant_get_child_value(mainSinkList, i); 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); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj,2,KEY_SINK_ID, sinkid); json_object_object_add(res_obj, KEY_SINK_NAME, json_object_new_string(sinkname)); sm_add_object_to_json_object(res_obj,10, KEY_AVAILABILITY, av, KEY_AVAILABILITY_REASON, avr, KEY_VOLUME, volume, KEY_MUTE_STATE, mutestate, KEY_SINK_CLASS_ID, sinkclassid); json_object_array_add(array_res,res_obj); g_variant_unref(child); } json_object_object_add(response, "sinks", array_res); } afb_req_success(request, response, "Success to get main sink list"); g_variant_unref(mainSinkList); } /* * ****** Routing Interface method(API) *********** * */ void ackConnect(struct afb_req request) { /* This function will be deprecated */ AFB_DEBUG("call %s", __FUNCTION__); 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); req_err3 = get_value_uint16(request, KEY_ERROR, &error); if((req_err1 != REQ_OK) || (req_err2 != REQ_OK) || (req_err3 != REQ_OK)) { afb_req_fail(request,"wrong-request", NULL); return; } if(connection_id == 0) { afb_req_fail(request,"wrong-request", "connectionID is more than 0"); return; } audiomanager_routinginterface_call_ack_connect_sync( am_route_bus, handle, connection_id, error, NULL, &err); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res, info); } void ackDisconnect(struct afb_req request) { /* This function will be deprecated */ AFB_DEBUG("call %s", __FUNCTION__); 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); req_err3 = get_value_uint16(request, KEY_ERROR, &error); if((req_err1 != REQ_OK) || (req_err2 != REQ_OK) || (req_err3 != REQ_OK)) { afb_req_fail(request,"wrong-request", "connectionID is more than 0"); return; } if(connection_id == 0) { afb_req_fail(request,"wrong-request", "connectionID is more than 0"); return; } audiomanager_routinginterface_call_ack_disconnect_sync( am_route_bus, handle, connection_id, error, NULL, &err); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res, info); } void ackSetSourceState(struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); 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); if((req_err1 != REQ_OK) || (req_err2 != REQ_OK)) { AFB_DEBUG("wrong request"); afb_req_fail(request,"wrong-request", NULL); return; } audiomanager_routinginterface_call_ack_set_source_state_sync( am_route_bus, handle, error, NULL, &err); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); 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 */ guint16 source_class_id; /* q */ gint32 source_state; /* i */ gint16 volume; /* n */ if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){ source_id = DYNAMIC_SOURCE_ID; /* if 0, dynamic source id will be applied */ } REQ_ERROR req_err = get_value_uint16(request, KEY_DOMAIN_ID, &domain_id); if( req_err != REQ_OK){ if(req_err == REQ_FAIL) { domain_id = SOUNDMANAGER_DOMAIN_ID; /* default in AGL */ } else{ afb_req_fail(request,"wrong-request", "Please input domainID as uint16, otherwise no value is OK"); return; } } if(domain_id == 0) { afb_req_fail(request,"wrong-request", "domainID should be more than 0"); return; } 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); return; } if(REQ_OK != get_value_uint16(request, KEY_SOURCE_CLASS_ID, &source_class_id)){ source_class_id = DEFAULT_SOURCE_CLASS_ID; /* BASE */ } if(REQ_OK != get_value_int32(request, KEY_SOURCE_STATE, &source_state)){ source_state = DEFAULT_SOURCE_STATE; /* SS_OFF */ } if(REQ_OK != get_value_int16(request, KEY_VOLUME, &volume)){ volume = DEFAULT_VOLUME; } gboolean visible = TRUE; /* b */ struct availability_s available; /* (ii) */ available.availability = DEFAULT_AVAILABLES; /* A_UNKNOWN */ available.avalilable_reason = 0; /* AR_UNKNOWN */ guint16 interrupt; if(REQ_OK != get_value_int16(request, KEY_INTERRUPT, &interrupt)){ interrupt = DEFAULT_INTERRUPT; /* q IS_OFF */ } struct sound_property_s sound_property_list; /* a(in) */ sound_property_list.type = 0; sound_property_list.value = 0; /* in reality, this is array of struct */ gint32 connection_format_list = DEFAULT_CONNECTION_FORMAT; /* ai */ struct main_sound_property_s main_property_list; /* a(in) */ main_property_list.type = 0; main_property_list.value = 0; struct notification_config_s nconf_routing; struct notification_config_s nconf_command; /* a(iin)a(iin) */ nconf_routing.type = 0; nconf_routing.status = 0; nconf_routing.parameter = 0; nconf_command.type = 0; nconf_command.status = 0; nconf_command.parameter = 0; /* acquire data */ guint16 acquire_source_id; guint16 ret; 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); if(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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_SOURCE_ID, acquire_source_id); char *info = get_response_audiomanager_massage_error(ret); 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(err != NULL) { afb_req_fail_f(request, "failed", "Unable to call %s", __FUNCTION__); 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); afb_req_success(request, res, info); } void subscribe(struct afb_req request) { const char *value = afb_req_value(request, KEY_EVENT); AFB_DEBUG( "%s %s", __FUNCTION__, value); int ret = 0; if(value) { int index = sm_search_event_name_index(value); if(index < 0) { index = sm_search_routing_event_name_index(value); if(index < 0) { AFB_NOTICE( "dedicated event doesn't exist"); ret = EVENT_SUBSCRIBE_ERROR_CODE; } else { afb_req_subscribe(request, *routing_event_list[index].event); } } else { afb_req_subscribe(request, *command_event_list[index].event); } } else{ AFB_NOTICE( "Please input event name"); ret = EVENT_SUBSCRIBE_ERROR_CODE; } /*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); afb_req_success(request, res, info); } void unsubscribe(struct afb_req request) { const char *value = afb_req_value(request, KEY_EVENT); AFB_DEBUG( "%s %s", __FUNCTION__, value); int ret = 0; if(value) { int index = sm_search_event_name_index(value); if(index < 0) { index = sm_search_routing_event_name_index(value); if(index < 0) { AFB_NOTICE( "dedicated event doesn't exist"); ret = EVENT_SUBSCRIBE_ERROR_CODE; } else { afb_req_unsubscribe(request, *routing_event_list[index].event); } } else { afb_req_unsubscribe(request, *command_event_list[index].event); } } else{ AFB_NOTICE( "Please input event name"); ret = EVENT_SUBSCRIBE_ERROR_CODE; } /*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); afb_req_success(request, res, info); } /* * ****** High Level API *********** * */ #ifdef ENABLE_AGL_AHL void streamOpen(struct afb_req request){ // TODO : wtite function } void streamClose(struct afb_req request){ // TODO : wtite function } void setStreamState(struct afb_req request){ // TODO : wtite function } #endif /* ********** Callback Function invoked by Audio Manager ********** */ 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); 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_DELAY, delay, KEY_CONNECTION_STATE, constate ); AFB_DEBUG("json object :%s:",json_object_to_json_string(res_obj)); afb_event_push(ev_new_connection, res_obj); } static void on_removed_main_connection( AudiomanagerCommandinterface* interface, guint16 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); afb_event_push(ev_removed_main_connection, res_obj); } static void on_main_connection_state_changed( AudiomanagerCommandinterface* interface, guint16 connectionID, gint16 connectionState) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj, 4, KEY_CONNECTION_ID, connectionID, KEY_CONNECTION_STATE, connectionState); afb_event_push(ev_main_connection_state_changed, res_obj); } static void on_volume_changed( AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 volume) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj, 4, KEY_SINK_ID, sinkID, KEY_VOLUME, volume); afb_event_push(ev_volume_changed, res_obj); } static void on_sink_mute_state_changed( AudiomanagerCommandinterface* interface, guint16 sinkID, gint16 mute) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj, 4, KEY_SINK_ID, sinkID, KEY_MUTE_STATE, mute); afb_event_push(ev_sink_mute_state_changed, res_obj); } /* ********** Callback Function invoked by Audio Manager Routing Interface********** */ static void on_set_routing_ready( AudiomanagerRoutinginterface* interface) { AFB_DEBUG("%s is called",__FUNCTION__); afb_event_push(ev_set_routing_ready, NULL); } static void on_set_routing_rundown( AudiomanagerRoutinginterface* interface) { AFB_DEBUG("%s is called",__FUNCTION__); afb_event_push(ev_set_routing_ready, NULL); } /* ********** Callback Function invoked by Sound Manager Adapter Interface********** * * For now, there may be no need to send events to applications from these invocation. * Sound Manager just sends ack to Audio Manager in charge of applications. * */ static gboolean on_async_abort( AudiomanagerRoutingSoundmanager *object, GDBusMethodInvocation *invocation, guint16 arg_handle) { AFB_DEBUG( "%s called", __FUNCTION__); /* 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) { 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); 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) { 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); 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) { 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) { AFB_DEBUG( "%s called", __FUNCTION__); struct json_object* ev_obj = json_object_new_object(); char* ss_key = get_source_state_key(arg_sourceState); sm_add_object_to_json_object(ev_obj, 4, KEY_HANDLE, arg_handle, KEY_SOURCE_ID, arg_sourceID); json_object_object_add(ev_obj, KEY_SOURCE_STATE, json_object_new_string(ss_key)); 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, NULL, NULL, &err);*/ } /* * ********** Internal Function used by Sound Manager ********** * */ 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; 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; } if(error != 0) { AFB_ERROR( "Failed to register domain"); return error; } SOUNDMANAGER_DOMAIN_ID = domain_id; AFB_NOTICE( "Complete registered domain id:%d",SOUNDMANAGER_DOMAIN_ID); return 0; } 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; } 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; } return 0; } static void on_name_lost(GDBusServer *server, GDBusConnection *conn, gpointer data) { // TODO: when the dbus name is lost, what should we do? AFB_WARNING("%s called", __FUNCTION__); } 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; } 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; /*create event*/ /*ToDo Hash table is better. And event should be created in the loop I would like to change */ ev_volume_changed = afb_daemon_make_event(cmd_evlist[0]); ev_new_connection = afb_daemon_make_event(cmd_evlist[1]); 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].event = &ev_volume_changed; command_event_list[1].name = cmd_evlist[1]; command_event_list[1].event = &ev_new_connection; command_event_list[2].name = cmd_evlist[2]; command_event_list[2].event = &ev_removed_main_connection; command_event_list[3].name = 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].event = &ev_main_connection_state_changed; /* create routing event */ ev_set_routing_ready = afb_daemon_make_event(route_evlist[0]); ev_set_routing_rundown = afb_daemon_make_event(route_evlist[1]); 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]); routing_event_list[0].name = route_evlist[0]; routing_event_list[0].event = &ev_set_routing_ready; routing_event_list[1].name = route_evlist[1]; routing_event_list[1].event = &ev_set_routing_rundown; routing_event_list[2].name = route_evlist[2]; routing_event_list[2].event = &ev_async_connect; routing_event_list[3].name = 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].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); /* 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; } ret = registerDomain(); if(ret != 0) { AFB_ERROR("registerDomain error: %s",get_response_audiomanager_massage_error(ret)); goto ev_init_out; } AFB_INFO("Finish Initialize event receive setting"); return 0; ev_init_out: AFB_WARNING( "DBus connection is not created"); return -1; } void onevent(const char *event, struct json_object *object) { AFB_NOTICE("on_event %s", event); }