summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/sm-def.h21
-rw-r--r--src/sm-helper.h21
-rw-r--r--src/sm-pending.c76
-rw-r--r--src/sm-pending.h38
-rw-r--r--src/soundmanager.c149
-rw-r--r--src/soundmanager.h24
7 files changed, 289 insertions, 41 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f157b7d..66e640f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -26,6 +26,7 @@ set(binding_sm_sources
soundmanager.c
sm-helper.c
sm-error.c
+ sm-pending.c
audiomanager_proxy.c
dbus/audio_manager_interface.c)
diff --git a/src/sm-def.h b/src/sm-def.h
index 0bab88d..bd565d5 100644
--- a/src/sm-def.h
+++ b/src/sm-def.h
@@ -53,7 +53,7 @@
#define KEY_DOMAIN_ID "domainID"
#define KEY_HANDLE "handle"
-#define KEY_APPNAME "appname"
+#define KEY_APPNAME "audio_role"
#define KEY_RAMP "ramp"
#define KEY_TIME "time"
#define KEY_SOURCE_STATE "sourceState"
@@ -72,11 +72,30 @@
#define KEY_RESPONSE "response"
+#define SM_EVENT_VOLUME_CHANGED "volumeChanged"
+#define SM_EVENT_NEW_MAIN_CONNECTION "newMainConnection"
+#define SM_EVENT_REMOVED_MAIN_CONNECTION "removedMainConnection"
+#define SM_EVENT_SINK_MUTE_STATE_CHANGED "sinkMuteStateChanged"
+#define SM_EVENT_MAIN_CONNECTION_STATE_CHANGED "mainConnectionStateChanged"
+/* Routing event*/
+#define SM_EVENT_SET_ROUTING_READY "setRoutingReady"
+#define SM_EVENT_SET_ROUTING_RUNDOWN "setRoutingRundown"
+#define SM_EVENT_ASYNC_CONNECT "asyncConnect"
+#define SM_EVENT_ASYNC_SET_SOURCE_STATE "asyncSetSourceState"
+#define SM_EVENT_ASYNC_DISCONNECT "asyncDisconnect"
+#define SM_EVENT_STREAM_STATE_EVENT "stream_state_event"
+
#ifdef ENABLE_AGL_AHL
#define KEY_AHL_AUDIO_ROLE "audio_role"
#define KEY_AHL_ENDPOINT_ID "endpoint_id"
#define KEY_AHL_ENDPOINT_TYPE "endpoint_type"
#define KEY_AHL_REP_STREAM_ID "stream_id"
+#define KEY_AHL_EVENT_NAME "event_name"
+#define KEY_AHL_STATE_EVENT "state_event"
+#define AHL_EVENT_NAME "ahl_stream_state_event"
+#define KEY_AHL_MUTE "mute"
+#define AHL_STREAM_UNMUTE 0
+#define AHL_STREAM_MUTE 1
typedef enum {
ENDPOINT_SINK,
diff --git a/src/sm-helper.h b/src/sm-helper.h
index a6d09f1..ec35ad2 100644
--- a/src/sm-helper.h
+++ b/src/sm-helper.h
@@ -27,20 +27,21 @@
#define SEND_RESULT_NO_RESP(...) send_result_no_resp(__VA_ARGS__, __FUNCTION__)
static const char* cmd_evlist[] = {
- "volumeChanged",
- "newMainConnection",
- "removedMainConnection",
- "sinkMuteStateChanged",
- "mainConnectionStateChanged"
+ SM_EVENT_VOLUME_CHANGED,
+ SM_EVENT_NEW_MAIN_CONNECTION,
+ SM_EVENT_REMOVED_MAIN_CONNECTION,
+ SM_EVENT_SINK_MUTE_STATE_CHANGED,
+ SM_EVENT_MAIN_CONNECTION_STATE_CHANGED
};
static const char* route_evlist[] = {
/* Routing event*/
- "setRoutingReady",
- "setRoutingRundown",
- "asyncConnect",
- "asyncSetSourceState",
- "asyncDisconnect"
+ SM_EVENT_SET_ROUTING_READY,
+ SM_EVENT_SET_ROUTING_RUNDOWN,
+ SM_EVENT_ASYNC_CONNECT,
+ SM_EVENT_ASYNC_SET_SOURCE_STATE,
+ SM_EVENT_ASYNC_DISCONNECT,
+ SM_EVENT_STREAM_STATE_EVENT
};
REQ_ERROR get_value_uint16(const struct afb_req request, const char *source, uint16_t *out_id);
diff --git a/src/sm-pending.c b/src/sm-pending.c
new file mode 100644
index 0000000..28a2382
--- /dev/null
+++ b/src/sm-pending.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdlib.h>
+#include "sm-pending.h"
+
+struct pending* add_pending(struct pending *list, int source_id)
+{
+ struct pending* pd;
+
+ if(list == NULL){
+ pd = malloc(sizeof(struct pending));
+ if(NULL == pd){
+ AFB_WARNING("memory allocation error");
+ return NULL;
+ }
+ pd->source.sourceID = source_id;
+ pd->next = NULL;
+ return pd;
+ }
+ else{
+ list->next = add_pending(list->next, source_id);
+ return list;
+ }
+}
+
+struct pending* get_pending(struct pending *list, int source_id){
+ if(list == NULL){
+ return NULL;
+ }
+ if(list->source.sourceID == source_id){
+ return list;
+ }
+ else{
+ struct pending* pd = get_pending(list->next, source_id);
+ return pd;
+ }
+}
+
+struct pending* del_pending(struct pending* list, int source_id){
+ struct pending* tmp;
+ if(list == NULL){
+ return NULL;
+ }
+
+ if(list->source.sourceID == source_id){
+ tmp = list->next;
+ free(list);
+ return tmp;
+ }
+ else{
+ list->next = del_pending(list->next, source_id);
+ return list;
+ }
+}
+
+void del_all_pendings(struct pending *list){
+ struct pending* tmp;
+ if(list != NULL){
+ tmp = list->next;
+ free(list);
+ del_all_pendings(tmp);
+ }
+} \ No newline at end of file
diff --git a/src/sm-pending.h b/src/sm-pending.h
new file mode 100644
index 0000000..ab753cd
--- /dev/null
+++ b/src/sm-pending.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOUNDMANAGER_PENDING_H
+#define SOUNDMANAGER_PENDING_H
+
+#define _GNU_SOURCE
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+struct pending_source{
+ int sourceID;
+};
+struct pending{
+ struct pending_source source;
+ struct pending* next;
+};
+
+
+struct pending* add_pending(struct pending *list, int source_id);
+struct pending* get_pending(struct pending *list, int source_id);
+struct pending* del_pending(struct pending* list, int source_id);
+void del_all_pendings(struct pending *list);
+
+#endif //SOUNDMANAGER_PENDING_H \ No newline at end of file
diff --git a/src/soundmanager.c b/src/soundmanager.c
index 1d10a1e..cb2815d 100644
--- a/src/soundmanager.c
+++ b/src/soundmanager.c
@@ -26,12 +26,15 @@
#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];
@@ -48,7 +51,7 @@ 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 {
@@ -531,8 +534,8 @@ void registerSource(struct afb_req request)
const gchar* name = afb_req_value(request, KEY_APPNAME); /* s */
if(!name)
{
- char* info = "Must specify the name. Please input json arg such as {\"appname\":\"radio\"}";
- afb_req_fail(request, NULL, info);
+ char* info = "Must specify the name. Please input json arg such as {\"audio_role\":\"radio\"}";
+ afb_req_fail(request, "wrong-request", info);
return;
}
if(REQ_OK != get_value_uint16(request, KEY_SOURCE_CLASS_ID, &source_class_id)){
@@ -698,7 +701,7 @@ void unsubscribe(struct afb_req request)
#ifdef ENABLE_AGL_AHL
-void streamOpen(struct afb_req request){
+void stream_open(struct afb_req request){
AFB_DEBUG("call %s", __FUNCTION__);
// register audio role and endpoint
// get audio_role
@@ -734,7 +737,7 @@ void streamOpen(struct afb_req request){
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.
+ // 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);
@@ -742,7 +745,7 @@ void streamOpen(struct afb_req request){
json_object_put(j_err);
json_object_put(response);
}else {
- afb_req_fail(request, NULL, "Failed streamOpen");
+ afb_req_fail(request, "unknown-error", "Failed stream_open");
json_object_put(response);
return;
}
@@ -753,22 +756,112 @@ void streamOpen(struct afb_req request){
KEY_AHL_REP_STREAM_ID, sid);
const char* info = get_response_audiomanager_massage_error(ret);
create_client_context(request, sid, endpoint_id, endpoint_type);
+ int index = sm_search_routing_event_name_index(SM_EVENT_STREAM_STATE_EVENT);
+ afb_req_subscribe(request, *routing_event_list[index].event);
afb_req_success(request, res, info);
}
-void streamClose(struct afb_req request){
-// TODO : wtite function
-/* smClientCtxt* ctxt = afb_req_context_get(request);
+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){
- json_object* jreq = json_object_new_object();
- json_object_object_add(jreq, KEY_MAIN_CONNECTION_ID, ctxt->source.mainConnectionID);
- afb_service_call_sync("soundmanager", "disconnect", jreq, &response);
- json_object_object_get_ex(response, KEY_RESPONSE, &j_resp);
- } */
+ 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 setStreamState(struct afb_req request){
-// TODO : wtite function
+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
@@ -909,13 +1002,27 @@ static void on_async_set_sink_volume(int handle, int sinkID,
static void on_async_set_source_state(int handle, int sourceID, int sourceState)
{
- AFB_DEBUG( "%s called", __FUNCTION__);
+ AFB_INFO( "%s called. handle : %d, sourceID: %d, state: %s", __FUNCTION__, handle, sourceID, get_source_state_key(sourceState));
struct json_object* ev_obj = json_object_new_object();
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(
@@ -962,7 +1069,6 @@ static void create_client_context(afb_req request, guint16 source_id, guint16 si
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);
}
@@ -1045,6 +1151,9 @@ int sm_init()
ev_async_connect = afb_daemon_make_event(route_evlist[2]);
ev_async_set_source_state = afb_daemon_make_event(route_evlist[3]);
ev_async_disconnect = afb_daemon_make_event(route_evlist[4]);
+#ifdef ENABLE_AGL_AHL
+ ev_stream_state_event = afb_daemon_make_event(route_evlist[5]);
+#endif
routing_event_list[0].name = strdup(route_evlist[0]);
routing_event_list[0].event = &ev_set_routing_ready;
@@ -1056,6 +1165,10 @@ int sm_init()
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,
diff --git a/src/soundmanager.h b/src/soundmanager.h
index 3666473..f79643b 100644
--- a/src/soundmanager.h
+++ b/src/soundmanager.h
@@ -328,7 +328,7 @@ void unsubscribe(struct afb_req request);
* #### Note
* TODO : write note
*/
-void streamOpen(struct afb_req req);
+void stream_open(struct afb_req req);
/**
* Application High Level API for AGL
@@ -344,23 +344,23 @@ void streamOpen(struct afb_req req);
* #### Note
* TODO : write note
*/
-void streamClose(struct afb_req req);
+void stream_close(struct afb_req req);
/**
* Application High Level API for AGL
* This function set stream state.
- * This function set the availability and calls connect function of Audio Manager
- * and returns the result of policy check.
+ * This function set the availability and calls connect function of Audio Manager.
+ * Policy check result will be notified by event..
*
* #### Parameters
* - stream_id : Stream id which is returned in stream_open.
- * - mute : Stream state as int
+ * - mute : Stream state as int. 0 is unmute, and 1 is mute. Sound manager set this parameter as unmute as default
* #### Return
* - error : Error status number. If error is 0, it means the request is accepted, otherwise error message is attached with error code in reply message.
* #### Note
- * TODO : write note
+ * After set unmute, then 'asyncSetSourceState' and 'stream_state_event' is pushed. These events contains information of state judged by AudioManager.
*/
-void setStreamState(struct afb_req req);
+void set_stream_state(struct afb_req req);
/*
********** Event list from Sound Manager **********
@@ -379,12 +379,12 @@ void setStreamState(struct afb_req req);
const struct afb_verb_v2 binding_verbs[]= {
#ifdef ENABLE_AGL_AHL
// High Level API of AGL
-{ .verb = "stream_open", .callback = streamOpen, .auth = NULL,
- .info = "Open stream." , .session = AFB_SESSION_NONE},
-{ .verb = "stream_close", .callback = streamClose, .auth = NULL,
+{ .verb = "stream_open", .callback = stream_open, .auth = NULL,
+ .info = "Open stream." , .session = AFB_SESSION_NONE},
+{ .verb = "stream_close", .callback = stream_close, .auth = NULL,
.info = "Close stream" , .session = AFB_SESSION_NONE},
-{ .verb = "set_stream_state", .callback = setStreamState, .auth = NULL,
- .info = "Set stream state" , .session = AFB_SESSION_NONE},
+{ .verb = "set_stream_state", .callback = set_stream_state, .auth = NULL,
+ .info = "Set stream state" , .session = AFB_SESSION_NONE},
#endif
// Adaption API of Audio Manager
{ .verb = "connect", .callback = connect, .auth = NULL,