/* * 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 "audiomanager_proxy.h" #include "sm-def.h" #include "sm-error.h" #include "sm-helper.h" struct event{ char* name; struct afb_event* event; }; struct pending{ int sourceID; struct afb_req request; bool use_ahl; struct pending* next; }; static struct pending* pending_list = NULL; static bool add_pending(int source_id, bool use_ahl, struct afb_req request){ struct pending* pd = malloc(sizeof(struct pending)); if(NULL == pd){ AFB_WARNING("memory allocation error"); return false; } pd->sourceID = source_id; pd->request = request; pd->use_ahl = use_ahl; pd->next = NULL; if(pending_list == NULL){ pending_list = pd; } struct pending* list = pending_list; while(list->next != NULL){ list = list->next; } list->next = pd; return true; } static struct pending* get_pending(int source_id){ struct pending* pd = pending_list; while(pd && (pd->sourceID == source_id)){ pd = pd->next; } return pd; } static bool del_peding(int source_id){ struct pending* pd = get_pending(source_id); if(pd != NULL){ return true; } return false; } static int 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; /* 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) ********** */ void connect (struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); guint16 source_id = 0, sink_id = 0; 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. 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; } ErrorCode ec = am_proxy_connect(source_id, source_id, &main_connectionID); 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", ec, KEY_MAIN_CONNECTION_ID, main_connectionID); const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } void disconnect (struct afb_req request) { AFB_DEBUG("call %s", __FUNCTION__); guint16 main_connection_id; REQ_ERROR req_err; GError *err = NULL; 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; } ErrorCode ec = am_proxy_disconnect(main_connection_id); AFB_DEBUG( "ret = %d", ec); 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, ec); const char* info = get_response_audiomanager_massage_error(ec); 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; 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; } ErrorCode ec = am_proxy_set_volume(sink_id, vol); AFB_DEBUG( "ret = %d", ec); 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", ec); const char* info = get_response_audiomanager_massage_error(ec); 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; 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; } ErrorCode ec = am_proxy_volume_step(sink_id, vol); AFB_DEBUG( "ret = %d", ec); 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", ec); const char* info = get_response_audiomanager_massage_error(ec); 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; 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; } ErrorCode ec = am_proxy_set_sink_mute_state(sink_id, mute); AFB_DEBUG( "ret = %d", ec); 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", ec); const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res_obj, info); /* return error num as status */ } void getListMainConnections(struct afb_req request) { AFB_DEBUG("call getListMainConnections"); GVariant* mainConnectionList; GError *err = NULL; ErrorCode ec = am_proxy_get_list_main_connections(mainConnectionList); if(!SEND_RESULT(ec, request)) 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__); GVariant* mainSourceList; GError *err = NULL; ErrorCode ec = am_proxy_get_list_main_sources(mainSourceList); if(!SEND_RESULT(ec, request)) 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__); GVariant* mainSinkList; GError *err = NULL; ErrorCode ec = am_proxy_get_list_main_sinks(mainSinkList); if(!SEND_RESULT(ec, request)) 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; 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; } ErrorCode ec = am_proxy_ack_connect(handle, connection_id, error); 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); const 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; } ErrorCode ec = am_proxy_ack_disconnect(handle, connection_id, error); 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); const 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; } ErrorCode ec = am_proxy_ack_set_source_state(handle, error); 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, 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 */ 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 */ 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); ErrorCode ec = am_proxy_register_source(sourceData, &acquire_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__, 4, KEY_ERROR, ec, KEY_SOURCE_ID, acquire_source_id); const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } void deregisterSource(struct afb_req request) { guint16 source_id; GError *err = NULL; if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){ afb_req_fail(request, "wrong-request", NULL); } 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, ec); const char* info = get_response_audiomanager_massage_error(ec); 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); const 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); const 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){ 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; } // 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_SOURCE){ AFB_WARNING("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(request); json_object *response = json_object_new_object(); json_object_object_add(jreq, KEY_APPNAME, json_object_new_string(audio_role)); 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); // requestSurface 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, NULL, "Failed streamOpen"); json_object_put(response); return; } json_object *res = json_object_new_object(); sm_add_object_to_json_object_func(res, __FUNCTION__, 4, KEY_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); afb_req_success(request, res, info); } void streamClose(struct afb_req request){ ErrorCode ec; smClientCtxt* ctxt = afb_req_context_get(request); if(NULL == ctxt){ AFB_ERROR("stream is not created"); afb_req_fail(request,NULL, "stream is not created"); return; } if(ctxt->source.mainConnectionID > 0){ ec = am_proxy_disconnect(ctxt->source.mainConnectionID); SEND_RESULT_NO_RESP(ec); ctxt->source.mainConnectionID = -1; } int source_id; REQ_ERROR req_err = get_value_uint16(request, KEY_SOURCE_ID, &source_id); if(ctxt->source.sourceID != source_id){ AFB_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID); afb_req_fail(request,"wrong request", NULL); return; } ec = am_proxy_deregister_source(ctxt->source.sourceID); 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, ec); const char* info = get_response_audiomanager_massage_error(ec); afb_req_success(request, res, info); } void setStreamState(struct afb_req request){ int source_id = 0, main_connection_id = -1; ErrorCode ec; smClientCtxt* ctxt = afb_req_context_get(request); if(NULL == ctxt){ AFB_ERROR("Context is not registered"); afb_req_fail(request, NULL, "call stream_open at first"); return; } ctxt->source.mainConnectionID = main_connection_id; // 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_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID); 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; } ec = am_proxy_connect(source_id, ctxt->sink.sinkID, &main_connection_id); if(!SEND_RESULT(ec, request)) return; ctxt->source.mainConnectionID = main_connection_id; afb_req_addref(request); add_peding(source_id, request); } #endif /* ********** Callback Function invoked by Audio Manager ********** */ static void on_new_main_connection(void* closure, int mainConnectioID, int sourceID, int sinkID, int delay, int connectionState) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); sm_add_object_to_json_object(res_obj,10, KEY_MAIN_CONNECTION_ID, mainConnectioID, KEY_SOURCE_ID, sourceID, KEY_SINK_ID, sinkID, KEY_DELAY, delay, KEY_CONNECTION_STATE, connectionState); 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(void* closure, 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); afb_event_push(ev_removed_main_connection, res_obj); } static void on_main_connection_state_changed(void* closure, int connectionID, int 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(void* closure, int sinkID, int 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(void* closure, int sinkID, int 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(void* closure) { AFB_DEBUG("%s is called",__FUNCTION__); afb_event_push(ev_set_routing_ready, NULL); } static void on_set_routing_rundown(void* closure) { 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 void on_async_abort(void *closure, int handle) { AFB_DEBUG( "%s called", __FUNCTION__); /* Nothing To Do. If it is better to implement something, I will implement */ } static void on_async_connect(void *closure, 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, 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); } static void on_async_disconnect(void *closure, 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, handle, KEY_CONNECTION_ID, connectionID); afb_event_push(ev_async_disconnect, ev_obj); } static void on_async_set_sink_volume(void *closure, int handle, int sinkID, int volume, int ramp, int time) { AFB_DEBUG( "%s called", __FUNCTION__); } static void on_async_set_source_state(void *closure, int handle, int sourceID, int sourceState) { AFB_DEBUG( "%s called", __FUNCTION__); struct pending* pd = get_pending(sourceID); if((pd != NULL) && (pd->use_ahl)){ AFB_DEBUG("Call ackSetSourceState in for the application"); am_proxy_ack_set_source_state(handle, 0); del_peding(sourceID); return; } struct json_object* ev_obj = json_object_new_object(); const char* ss_key = get_source_state_key(sourceState); sm_add_object_to_json_object(ev_obj, 4, KEY_HANDLE, handle, KEY_SOURCE_ID, 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, handle, NULL, NULL, &err);*/ } /* * ********** Internal Function used by Sound Manager ********** * */ 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? } 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); } else{ strncpy(ctxt->appname, appid, MAX_LENGTH_STR); } ctxt->source.sourceID = source_id; ctxt->sink.endpointID = sink_id; ctxt->sink.sinkID = sink_id; ctxt->sink.endpointType = endpoint_type; ctxt->events.asyncSetSourceState = afb_daemon_make_event("asyncSetSourceState"); afb_req_context_set(request, ctxt, on_client_context_terminated); } int preinit() { AFB_INFO("Initialize Dbus object"); /* Initialize Dbus interface */ ErrorCode err = initialize_proxy(); if(err != OK){ AFB_ERROR("Failed to initialize"); return -1; } AFB_NOTICE( "Finish Initialize"); return 0; } int sm_init() { AFB_NOTICE("Initialize event receive setting"); /* 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); }*/ am_event callback = { .on_new_main_connection = on_new_main_connection, .on_removed_main_connection = on_removed_main_connection, .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 */ 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 }; ErrorCode ec = open_soundmanager_interface(&instruction); if(ec != OK){ AFB_ERROR("Failed to create sound manager interface"); return -1; } 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); return 0; } void onevent(const char *event, struct json_object *object) { AFB_NOTICE("on_event %s", event); }