/* * 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" #include "sm-pending.h" struct event{ char* name; struct afb_event* event; }; static struct pending* pending_list = NULL; 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; 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) ********** */ 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; 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, sink_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; 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; 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; 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; 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; ErrorCode ec = am_proxy_get_list_main_connections(&mainConnectionList); if(!SEND_RESULT(ec, request)) return; /* create response */ struct json_object *response = json_object_new_object(); gsize size = g_variant_n_children(mainConnectionList); AFB_DEBUG("mainConnectionList size is %u",(uint16_t)size); 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; 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); } json_object_object_add(response, "connections", array_res); } 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__); GVariant* mainSourceList; 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, "sources", 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; 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; 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; 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__); 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 {\"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)){ 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 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; } // 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); // 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; } 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); 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 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); } 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; } // 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; } 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{ 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 /* ********** 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__); 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_event_push(ev_new_connection, res_obj); } static void on_removed_main_connection(int mainConnectionID) { AFB_DEBUG("%s is called",__FUNCTION__); struct json_object* res_obj = json_object_new_object(); 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(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(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(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) { 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(void) { 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(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(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(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(int handle, int sinkID, int volume, int ramp, int time) { AFB_DEBUG( "%s called", __FUNCTION__); } static void on_async_set_source_state(int handle, int sourceID, int sourceState) { 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(); 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)); #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, 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; afb_req_context_set(request, ctxt, on_client_context_terminated); } void set_default_sink(){ GVariant *mainSinkList; ErrorCode ec = am_proxy_get_list_main_sinks(&mainSinkList); if(ec != OK){ return; } 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; } 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); set_default_sinkID(sinkid); } int preinit() { AFB_INFO("Initialize Dbus object"); /* Initialize Dbus interface */ ErrorCode ec = initialize_proxy(); if(ec == NOT_INITIALIZED){ 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; ErrorCode ec; /*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 = strdup(cmd_evlist[0]); command_event_list[0].event = &ev_volume_changed; command_event_list[1].name = strdup(cmd_evlist[1]); command_event_list[1].event = &ev_new_connection; command_event_list[2].name = strdup(cmd_evlist[2]); command_event_list[2].event = &ev_removed_main_connection; command_event_list[3].name = strdup(cmd_evlist[3]); command_event_list[3].event = &ev_sink_mute_state_changed; command_event_list[4].name = strdup(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]); #ifdef ENABLE_AGL_AHL ev_stream_state_event = afb_daemon_make_event(route_evlist[5]); #endif routing_event_list[0].name = strdup(route_evlist[0]); routing_event_list[0].event = &ev_set_routing_ready; routing_event_list[1].name = strdup(route_evlist[1]); routing_event_list[1].event = &ev_set_routing_rundown; routing_event_list[2].name = strdup(route_evlist[2]); routing_event_list[2].event = &ev_async_connect; routing_event_list[3].name = strdup(route_evlist[3]); routing_event_list[3].event = &ev_async_set_source_state; routing_event_list[4].name = strdup(route_evlist[4]); routing_event_list[4].event = &ev_async_disconnect; #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 */ 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; } 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); set_default_sink(); return 0; } void onevent(const char *event, struct json_object *object) { AFB_NOTICE("on_event %s", event); }