summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--ahl-binding/CMakeLists.txt2
-rw-r--r--ahl-binding/ahl-apidef.h251
-rw-r--r--ahl-binding/ahl-apidef.json160
-rw-r--r--ahl-binding/ahl-binding.c951
-rw-r--r--ahl-binding/ahl-binding.h36
-rw-r--r--ahl-binding/ahl-config.c18
-rw-r--r--ahl-binding/ahl-deviceenum.c63
-rw-r--r--ahl-binding/ahl-json.c296
-rw-r--r--ahl-binding/ahl-json.h26
-rw-r--r--ahl-policy/ahl-interface.h3
-rw-r--r--ahl-policy/ahl-policy.c572
-rw-r--r--ahl-policy/ahl-policy.h20
-rwxr-xr-x[-rw-r--r--]ahl-utilities/ahl-policy-utils.c259
-rwxr-xr-x[-rw-r--r--]ahl-utilities/ahl-policy-utils.h61
-rw-r--r--conf.d/project/ahl-audiok4a-config.json8
-rw-r--r--htdocs/audiohl.html21
17 files changed, 1287 insertions, 1464 deletions
diff --git a/README.md b/README.md
index 3a940b3..046c2e7 100644
--- a/README.md
+++ b/README.md
@@ -8,10 +8,6 @@
```
# Initial clone with submodules
git clone https://github.com/Audiokinetic-Automotive/afb-audiohighlevel.git
-<<<<<<< HEAD
-cd afb-audiohighlevel
-=======
->>>>>>> 8a584f01b46d251fdc5de8b071eff755d99f0090
```
diff --git a/ahl-binding/CMakeLists.txt b/ahl-binding/CMakeLists.txt
index 44944e5..0dee304 100644
--- a/ahl-binding/CMakeLists.txt
+++ b/ahl-binding/CMakeLists.txt
@@ -20,7 +20,7 @@
PROJECT_TARGET_ADD(audiohighlevel)
# Define project Targets
- ADD_LIBRARY(${TARGET_NAME} MODULE ahl-binding.c ahl-deviceenum.c ahl-config.c)
+ ADD_LIBRARY(${TARGET_NAME} MODULE ahl-binding.c ahl-deviceenum.c ahl-config.c ahl-json.c)
# Binder exposes a unique public entry point
SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
diff --git a/ahl-binding/ahl-apidef.h b/ahl-binding/ahl-apidef.h
index 9002c6f..2c77827 100644
--- a/ahl-binding/ahl-apidef.h
+++ b/ahl-binding/ahl-apidef.h
@@ -36,113 +36,86 @@ static const char _afb_description_v2_ahl_4a[] =
"200\":{\"description\":\"A complex object array response\",\"content\":{"
"\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/afb-re"
"ply\"}}}},\"400\":{\"description\":\"Invalid arguments\"}}},\"paths\":{\""
- "/get_sources\":{\"description\":\"Retrieve array of available audio sour"
- "ces\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"audio_role\""
- ",\"required\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"2"
- "00\":{\"$ref\":\"#/components/responses/200\",\"response\":{\"descriptio"
- "n\":\"Array of endpoint info structures\",\"type\":\"array\",\"items\":{"
- "\"$ref\":\"#/components/schemas/endpoint_info\"}}},\"400\":{\"$ref\":\"#"
- "/components/responses/400\"}}}},\"/get_sinks\":{\"description\":\"Retrie"
- "ve array of available audio sinks\",\"get\":{\"parameters\":[{\"in\":\"q"
- "uery\",\"name\":\"audio_role\",\"required\":true,\"schema\":{\"type\":\""
- "string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/20"
- "0\",\"response\":{\"description\":\"Array of endpoint info structures\","
- "\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/endpoint_i"
- "nfo\"}}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/stream_"
- "open\":{\"description\":\"Request opening a stream\",\"get\":{\"x-permis"
- "sions\":{\"$ref\":\"#/components/x-permissions/audiostream\"},\"paramete"
- "rs\":[{\"in\":\"query\",\"name\":\"audio_role\",\"required\":true,\"sche"
- "ma\":{\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"endpoint_type\""
- ",\"required\":true,\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"n"
- "ame\":\"endpoint_id\",\"required\":false,\"schema\":{\"type\":\"int\"}}]"
- ",\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\",\"respo"
- "nse\":{\"description\":\"Stream information structure\",\"$ref\":\"#/com"
- "ponents/schemas/stream_info\"}},\"400\":{\"$ref\":\"#/components/respons"
- "es/400\"}}}},\"/stream_close\":{\"description\":\"Request closing a stre"
- "am\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/a"
- "udiostream\"},\"parameters\":[{\"in\":\"query\",\"name\":\"stream_id\",\""
- "required\":true,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{"
- "\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/component"
- "s/responses/400\"}}}},\"/set_stream_state\":{\"description\":\"Change st"
- "ream active state\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/"
- "x-permissions/streamcontrol\"},\"parameters\":[{\"in\":\"query\",\"name\""
- ":\"stream_id\",\"required\":true,\"schema\":{\"type\":\"int\"}},{\"in\":"
- "\"query\",\"name\":\"state\",\"required\":true,\"schema\":{\"type\":\"in"
- "t\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},"
- "\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/set_stream_mute\""
- ":{\"description\":\"Change stream mute state\",\"get\":{\"x-permissions\""
- ":{\"$ref\":\"#/components/x-permissions/streamcontrol\"},\"parameters\":"
- "[{\"in\":\"query\",\"name\":\"stream_id\",\"required\":true,\"schema\":{"
- "\"type\":\"int\"}},{\"in\":\"query\",\"name\":\"mute\",\"required\":true"
- ",\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$ref\":\"#/co"
- "mponents/responses/200\"},\"400\":{\"$ref\":\"#/components/responses/400"
- "\"}}}},\"/get_stream_info\":{\"description\":\"Retrieve stream informati"
- "on\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"stream_id\",\""
- "required\":true,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{"
- "\"$ref\":\"#/components/responses/200\",\"response\":{\"description\":\""
- "Stream information structure\",\"$ref\":\"#/components/schemas/stream_in"
- "fo\"}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/set_volum"
- "e\":{\"description\":\"Set volume on endpoint\",\"get\":{\"x-permissions"
+ "/get_endpoints\":{\"description\":\"Retrieve array of available audio en"
+ "dpoints\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"audio_ro"
+ "le\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query"
+ "\",\"name\":\"endpoint_type\",\"required\":true,\"schema\":{\"type\":\"e"
+ "num\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\""
+ ",\"response\":{\"description\":\"Array of endpoint info structures\",\"t"
+ "ype\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/endpoint_info"
+ "\"}}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/stream_ope"
+ "n\":{\"description\":\"Request opening a stream\",\"get\":{\"x-permissio"
+ "ns\":{\"$ref\":\"#/components/x-permissions/audiostream\"},\"parameters\""
+ ":[{\"in\":\"query\",\"name\":\"audio_role\",\"required\":true,\"schema\""
+ ":{\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"endpoint_type\",\"r"
+ "equired\":true,\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"name\""
+ ":\"endpoint_id\",\"required\":false,\"schema\":{\"type\":\"int\"}}],\"re"
+ "sponses\":{\"200\":{\"$ref\":\"#/components/responses/200\",\"response\""
+ ":{\"description\":\"Stream information structure\",\"$ref\":\"#/componen"
+ "ts/schemas/stream_info\"}},\"400\":{\"$ref\":\"#/components/responses/40"
+ "0\"}}}},\"/stream_close\":{\"description\":\"Request closing a stream\","
+ "\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/audios"
+ "tream\"},\"parameters\":[{\"in\":\"query\",\"name\":\"stream_id\",\"requ"
+ "ired\":false,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$"
+ "ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/components/r"
+ "esponses/400\"}}}},\"/set_stream_state\":{\"description\":\"Change strea"
+ "m active and/or mute state\",\"get\":{\"x-permissions\":{\"$ref\":\"#/co"
+ "mponents/x-permissions/streamcontrol\"},\"parameters\":[{\"in\":\"query\""
+ ",\"name\":\"stream_id\",\"required\":false,\"schema\":{\"type\":\"int\"}"
+ "},{\"in\":\"query\",\"name\":\"state\",\"required\":false,\"schema\":{\""
+ "type\":\"int\"}},{\"in\":\"query\",\"name\":\"mute\",\"required\":false,"
+ "\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$ref\":\"#/com"
+ "ponents/responses/200\"},\"400\":{\"$ref\":\"#/components/responses/400\""
+ "}}}},\"/get_stream_info\":{\"description\":\"Retrieve stream information"
+ "\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"stream_id\",\"r"
+ "equired\":true,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\""
+ "$ref\":\"#/components/responses/200\",\"response\":{\"description\":\"St"
+ "ream information structure\",\"$ref\":\"#/components/schemas/stream_info"
+ "\"}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/volume\":{\""
+ "description\":\"Set or get volume on endpoint\",\"get\":{\"x-permissions"
"\":{\"$ref\":\"#/components/x-permissions/endpointcontrol\"},\"parameter"
"s\":[{\"in\":\"query\",\"name\":\"endpoint_type\",\"required\":true,\"sc"
"hema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"name\":\"endpoint_id\",\""
"required\":true,\"schema\":{\"type\":\"int\"}},{\"in\":\"query\",\"name\""
- ":\"volume\",\"required\":true,\"schema\":{\"type\":\"string\"}}],\"respo"
- "nses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$re"
- "f\":\"#/components/responses/400\"}}}},\"/get_volume\":{\"description\":"
- "\"Get endpoint volume\",\"get\":{\"parameters\":[{\"in\":\"query\",\"nam"
- "e\":\"endpoint_type\",\"required\":true,\"schema\":{\"type\":\"enum\"}},"
- "{\"in\":\"query\",\"name\":\"endpoint_id\",\"required\":true,\"schema\":"
- "{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/res"
- "ponses/200\",\"response\":{\"description\":\"Endpoint volume value\",\"t"
- "ype\":\"double\"}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},"
- "\"/get_endpoint_info\":{\"description\":\"Retrieve endpoint information "
- "including its properties\",\"get\":{\"parameters\":[{\"in\":\"query\",\""
- "name\":\"endpoint_type\",\"required\":true,\"schema\":{\"type\":\"enum\""
- "}},{\"in\":\"query\",\"name\":\"endpoint_id\",\"required\":false,\"schem"
- "a\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components"
- "/responses/200\"},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\""
- "/set_property\":{\"description\":\"Set endpoint property value\",\"get\""
- ":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/endpointcontr"
- "ol\"},\"parameters\":[{\"in\":\"query\",\"name\":\"endpoint_type\",\"req"
- "uired\":true,\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"name\":"
- "\"endpoint_id\",\"required\":false,\"schema\":{\"type\":\"int\"}},{\"in\""
- ":\"query\",\"name\":\"property_name\",\"required\":true,\"schema\":{\"ty"
- "pe\":\"string\"}},{\"in\":\"query\",\"name\":\"value\",\"required\":true"
- ",\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#"
- "/components/responses/200\"},\"400\":{\"$ref\":\"#/components/responses/"
- "400\"}}}},\"/get_property\":{\"description\":\"Get endpoint property val"
- "ue\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"endpoint_type"
- "\",\"required\":true,\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\""
- "name\":\"endpoint_id\",\"required\":false,\"schema\":{\"type\":\"int\"}}"
- ",{\"in\":\"query\",\"name\":\"property_name\",\"required\":true,\"schema"
- "\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/componen"
- "ts/responses/200\",\"response\":{\"description\":\"Property value\",\"ty"
- "pe\":\"double\"}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\""
- "/get_list_actions\":{\"description\":\"Retrieve a list of supported acti"
- "ons for a particular audio role\",\"get\":{\"parameters\":[{\"in\":\"que"
- "ry\",\"name\":\"audio_role\",\"required\":true,\"schema\":{\"type\":\"st"
- "ring\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\""
- "},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/post_action\":"
- "{\"description\":\"Post sound or audio device related action event (exte"
- "ndable mechanism)\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/"
- "x-permissions/soundevent\"},\"parameters\":[{\"in\":\"query\",\"name\":\""
- "action_name\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\""
- ":\"query\",\"name\":\"audio_role\",\"required\":true,\"schema\":{\"type\""
- ":\"string\"}},{\"in\":\"query\",\"name\":\"media_name\",\"required\":fal"
- "se,\"schema\":{\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"action"
- "_context\",\"required\":false,\"schema\":{\"type\":\"object\"}}],\"respo"
- "nses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$re"
- "f\":\"#/components/responses/400\"}}}},\"/subscribe\":{\"description\":\""
- "Subscribe to audio high level events\",\"get\":{\"parameters\":[{\"in\":"
- "\"query\",\"name\":\"events\",\"required\":true,\"schema\":{\"type\":\"a"
- "rray\",\"items\":{\"type\":\"string\"}}}],\"responses\":{\"200\":{\"$ref"
- "\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/components/resp"
- "onses/400\"}}}},\"/unsubscribe\":{\"description\":\"Unubscribe to audio "
- "high level events\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":"
- "\"events\",\"required\":true,\"schema\":{\"type\":\"array\",\"items\":{\""
- "type\":\"string\"}}}],\"responses\":{\"200\":{\"$ref\":\"#/components/re"
- "sponses/200\"},\"400\":{\"$ref\":\"#/components/responses/400\"}}}}}}"
+ ":\"volume\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"resp"
+ "onses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$r"
+ "ef\":\"#/components/responses/400\"}}}},\"/get_endpoint_info\":{\"descri"
+ "ption\":\"Retrieve endpoint information including its properties\",\"get"
+ "\":{\"parameters\":[{\"in\":\"query\",\"name\":\"endpoint_type\",\"requi"
+ "red\":true,\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"name\":\""
+ "endpoint_id\",\"required\":true,\"schema\":{\"type\":\"int\"}}],\"respon"
+ "ses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref"
+ "\":\"#/components/responses/400\"}}}},\"/property\":{\"description\":\"S"
+ "et/get endpoint property value\",\"get\":{\"x-permissions\":{\"$ref\":\""
+ "#/components/x-permissions/endpointcontrol\"},\"parameters\":[{\"in\":\""
+ "query\",\"name\":\"endpoint_type\",\"required\":true,\"schema\":{\"type\""
+ ":\"enum\"}},{\"in\":\"query\",\"name\":\"endpoint_id\",\"required\":true"
+ ",\"schema\":{\"type\":\"int\"}},{\"in\":\"query\",\"name\":\"property_na"
+ "me\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query"
+ "\",\"name\":\"value\",\"required\":false,\"schema\":{\"type\":\"string\""
+ "}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"4"
+ "00\":{\"$ref\":\"#/components/responses/400\"}}}},\"/get_list_actions\":"
+ "{\"description\":\"Retrieve a list of supported actions for a particular"
+ " audio role\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"audi"
+ "o_role\",\"required\":true,\"schema\":{\"type\":\"string\"}}],\"response"
+ "s\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\""
+ ":\"#/components/responses/400\"}}}},\"/post_action\":{\"description\":\""
+ "Post sound or audio device related action event (extendable mechanism)\""
+ ",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/sound"
+ "event\"},\"parameters\":[{\"in\":\"query\",\"name\":\"action_name\",\"re"
+ "quired\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query\",\"name"
+ "\":\"audio_role\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\""
+ "in\":\"query\",\"name\":\"media_name\",\"required\":false,\"schema\":{\""
+ "type\":\"string\"}},{\"in\":\"query\",\"name\":\"action_context\",\"requ"
+ "ired\":false,\"schema\":{\"type\":\"object\"}}],\"responses\":{\"200\":{"
+ "\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/component"
+ "s/responses/400\"}}}},\"/event_subscription\":{\"description\":\"Subscri"
+ "be to audio high level events\",\"get\":{\"parameters\":[{\"in\":\"query"
+ "\",\"name\":\"events\",\"required\":true,\"schema\":{\"type\":\"array\","
+ "\"items\":{\"type\":\"string\"}}},{\"in\":\"query\",\"name\":\"subscribe"
+ "\",\"required\":true,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"20"
+ "0\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/comp"
+ "onents/responses/400\"}}}}}}"
;
static const struct afb_auth _afb_auths_v2_ahl_4a[] = {
@@ -152,36 +125,24 @@ static const struct afb_auth _afb_auths_v2_ahl_4a[] = {
{ .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:soundevent" }
};
- void audiohlapi_get_sources(struct afb_req req);
- void audiohlapi_get_sinks(struct afb_req req);
+ void audiohlapi_get_endpoints(struct afb_req req);
void audiohlapi_stream_open(struct afb_req req);
void audiohlapi_stream_close(struct afb_req req);
void audiohlapi_set_stream_state(struct afb_req req);
- void audiohlapi_set_stream_mute(struct afb_req req);
void audiohlapi_get_stream_info(struct afb_req req);
- void audiohlapi_set_volume(struct afb_req req);
- void audiohlapi_get_volume(struct afb_req req);
+ void audiohlapi_volume(struct afb_req req);
void audiohlapi_get_endpoint_info(struct afb_req req);
- void audiohlapi_set_property(struct afb_req req);
- void audiohlapi_get_property(struct afb_req req);
+ void audiohlapi_property(struct afb_req req);
void audiohlapi_get_list_actions(struct afb_req req);
void audiohlapi_post_action(struct afb_req req);
- void audiohlapi_subscribe(struct afb_req req);
- void audiohlapi_unsubscribe(struct afb_req req);
+ void audiohlapi_event_subscription(struct afb_req req);
static const struct afb_verb_v2 _afb_verbs_v2_ahl_4a[] = {
{
- .verb = "get_sources",
- .callback = audiohlapi_get_sources,
- .auth = NULL,
- .info = "Retrieve array of available audio sources",
- .session = AFB_SESSION_NONE_V2
- },
- {
- .verb = "get_sinks",
- .callback = audiohlapi_get_sinks,
+ .verb = "get_endpoints",
+ .callback = audiohlapi_get_endpoints,
.auth = NULL,
- .info = "Retrieve array of available audio sinks",
+ .info = "Retrieve array of available audio endpoints",
.session = AFB_SESSION_NONE_V2
},
{
@@ -202,14 +163,7 @@ static const struct afb_verb_v2 _afb_verbs_v2_ahl_4a[] = {
.verb = "set_stream_state",
.callback = audiohlapi_set_stream_state,
.auth = &_afb_auths_v2_ahl_4a[1],
- .info = "Change stream active state",
- .session = AFB_SESSION_NONE_V2
- },
- {
- .verb = "set_stream_mute",
- .callback = audiohlapi_set_stream_mute,
- .auth = &_afb_auths_v2_ahl_4a[1],
- .info = "Change stream mute state",
+ .info = "Change stream active and/or mute state",
.session = AFB_SESSION_NONE_V2
},
{
@@ -220,17 +174,10 @@ static const struct afb_verb_v2 _afb_verbs_v2_ahl_4a[] = {
.session = AFB_SESSION_NONE_V2
},
{
- .verb = "set_volume",
- .callback = audiohlapi_set_volume,
+ .verb = "volume",
+ .callback = audiohlapi_volume,
.auth = &_afb_auths_v2_ahl_4a[2],
- .info = "Set volume on endpoint",
- .session = AFB_SESSION_NONE_V2
- },
- {
- .verb = "get_volume",
- .callback = audiohlapi_get_volume,
- .auth = NULL,
- .info = "Get endpoint volume",
+ .info = "Set or get volume on endpoint",
.session = AFB_SESSION_NONE_V2
},
{
@@ -241,17 +188,10 @@ static const struct afb_verb_v2 _afb_verbs_v2_ahl_4a[] = {
.session = AFB_SESSION_NONE_V2
},
{
- .verb = "set_property",
- .callback = audiohlapi_set_property,
+ .verb = "property",
+ .callback = audiohlapi_property,
.auth = &_afb_auths_v2_ahl_4a[2],
- .info = "Set endpoint property value",
- .session = AFB_SESSION_NONE_V2
- },
- {
- .verb = "get_property",
- .callback = audiohlapi_get_property,
- .auth = NULL,
- .info = "Get endpoint property value",
+ .info = "Set/get endpoint property value",
.session = AFB_SESSION_NONE_V2
},
{
@@ -269,20 +209,13 @@ static const struct afb_verb_v2 _afb_verbs_v2_ahl_4a[] = {
.session = AFB_SESSION_NONE_V2
},
{
- .verb = "subscribe",
- .callback = audiohlapi_subscribe,
+ .verb = "event_subscription",
+ .callback = audiohlapi_event_subscription,
.auth = NULL,
.info = "Subscribe to audio high level events",
.session = AFB_SESSION_NONE_V2
},
{
- .verb = "unsubscribe",
- .callback = audiohlapi_unsubscribe,
- .auth = NULL,
- .info = "Unubscribe to audio high level events",
- .session = AFB_SESSION_NONE_V2
- },
- {
.verb = NULL,
.callback = NULL,
.auth = NULL,
diff --git a/ahl-binding/ahl-apidef.json b/ahl-binding/ahl-apidef.json
index 81d410c..59f7a32 100644
--- a/ahl-binding/ahl-apidef.json
+++ b/ahl-binding/ahl-apidef.json
@@ -137,8 +137,8 @@
}
},
"paths": {
- "/get_sources": {
- "description": "Retrieve array of available audio sources",
+ "/get_endpoints": {
+ "description": "Retrieve array of available audio endpoints",
"get": {
"parameters": [
{
@@ -146,30 +146,12 @@
"name": "audio_role",
"required": true,
"schema": { "type": "string" }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/200",
- "response": {
- "description": "Array of endpoint info structures",
- "type": "array",
- "items": { "$ref": "#/components/schemas/endpoint_info"}
- }
},
- "400": { "$ref": "#/components/responses/400" }
- }
- }
- },
- "/get_sinks": {
- "description": "Retrieve array of available audio sinks",
- "get": {
- "parameters": [
{
"in": "query",
- "name": "audio_role",
+ "name": "endpoint_type",
"required": true,
- "schema": { "type": "string" }
+ "schema": { "type": "enum" }
}
],
"responses": {
@@ -229,7 +211,7 @@
{
"in": "query",
"name": "stream_id",
- "required": true,
+ "required": false,
"schema": { "type": "int" }
}
],
@@ -240,7 +222,7 @@
}
},
"/set_stream_state": {
- "description": "Change stream active state",
+ "description": "Change stream active and/or mute state",
"get": {
"x-permissions": {
"$ref": "#/components/x-permissions/streamcontrol"
@@ -249,39 +231,19 @@
{
"in": "query",
"name": "stream_id",
- "required": true,
+ "required": false,
"schema": {"type": "int"}
},
{
"in": "query",
"name": "state",
- "required": true,
- "schema": {"type": "int"}
- }
- ],
- "responses": {
- "200": { "$ref": "#/components/responses/200" },
- "400": { "$ref": "#/components/responses/400" }
- }
- }
- },
- "/set_stream_mute": {
- "description": "Change stream mute state",
- "get": {
- "x-permissions": {
- "$ref": "#/components/x-permissions/streamcontrol"
- },
- "parameters": [
- {
- "in": "query",
- "name": "stream_id",
- "required": true,
+ "required": false,
"schema": {"type": "int"}
},
{
"in": "query",
"name": "mute",
- "required": true,
+ "required": false,
"schema": {"type": "int"}
}
],
@@ -314,8 +276,8 @@
}
}
},
- "/set_volume": {
- "description": "Set volume on endpoint",
+ "/volume": {
+ "description": "Set or get volume on endpoint",
"get": {
"x-permissions": { "$ref": "#/components/x-permissions/endpointcontrol" },
"parameters": [
@@ -334,7 +296,7 @@
{
"in": "query",
"name": "volume",
- "required": true,
+ "required": false,
"schema": { "type": "string" }
}
],
@@ -344,35 +306,6 @@
}
}
},
- "/get_volume": {
- "description": "Get endpoint volume",
- "get": {
- "parameters": [
- {
- "in": "query",
- "name": "endpoint_type",
- "required": true,
- "schema": { "type": "enum" }
- },
- {
- "in": "query",
- "name": "endpoint_id",
- "required": true,
- "schema": { "type": "int" }
- }
- ],
- "responses": {
- "200": {
- "$ref": "#/components/responses/200",
- "response": {
- "description": "Endpoint volume value",
- "type": "double"
- }
- },
- "400": { "$ref": "#/components/responses/400" }
- }
- }
- },
"/get_endpoint_info": {
"description": "Retrieve endpoint information including its properties",
"get": {
@@ -386,7 +319,7 @@
{
"in": "query",
"name": "endpoint_id",
- "required": false,
+ "required": true,
"schema": { "type": "int" }
}
],
@@ -396,8 +329,8 @@
}
}
},
- "/set_property": {
- "description": "Set endpoint property value",
+ "/property": {
+ "description": "Set/get endpoint property value",
"get": {
"x-permissions": { "$ref": "#/components/x-permissions/endpointcontrol" },
"parameters": [
@@ -410,7 +343,7 @@
{
"in": "query",
"name": "endpoint_id",
- "required": false,
+ "required": true,
"schema": { "type": "int" }
},
{
@@ -422,47 +355,12 @@
{
"in": "query",
"name": "value",
- "required": true,
- "schema": { "type": "string" }
- }
- ],
- "responses": {
- "200": { "$ref": "#/components/responses/200" },
- "400": { "$ref": "#/components/responses/400" }
- }
- }
- },
- "/get_property": {
- "description": "Get endpoint property value",
- "get": {
- "parameters": [
- {
- "in": "query",
- "name": "endpoint_type",
- "required": true,
- "schema": { "type": "enum" }
- },
- {
- "in": "query",
- "name": "endpoint_id",
"required": false,
- "schema": { "type": "int" }
- },
- {
- "in": "query",
- "name": "property_name",
- "required": true,
"schema": { "type": "string" }
}
],
"responses": {
- "200": {
- "$ref": "#/components/responses/200",
- "response": {
- "description": "Property value",
- "type": "double"
- }
- },
+ "200": { "$ref": "#/components/responses/200" },
"400": { "$ref": "#/components/responses/400" }
}
}
@@ -520,7 +418,7 @@
}
}
},
- "/subscribe": {
+ "/event_subscription": {
"description": "Subscribe to audio high level events",
"get": {
"parameters": [
@@ -531,28 +429,12 @@
"schema": { "type": "array",
"items": { "type": "string" }
}
- }
- ],
- "responses": {
- "200": { "$ref": "#/components/responses/200" },
- "400": { "$ref": "#/components/responses/400" }
- }
- }
- },
- "/unsubscribe": {
- "description": "Unubscribe to audio high level events",
- "get": {
- "parameters": [
+ },
{
"in": "query",
- "name": "events",
+ "name": "subscribe",
"required": true,
- "schema": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
+ "schema": { "type": "int" }
}
],
"responses": {
diff --git a/ahl-binding/ahl-binding.c b/ahl-binding/ahl-binding.c
index 264930f..c205c8e 100644
--- a/ahl-binding/ahl-binding.c
+++ b/ahl-binding/ahl-binding.c
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
@@ -22,12 +21,11 @@
#include "ahl-apidef.h" // Generated from JSON OpenAPI
#include "wrap-json.h"
#include "ahl-policy.h"
-#include "ahl-policy-utils.h"
+#include "ahl-json.h"
// Global high-level binding context
AHLCtxT g_AHLCtx;
-// TODO: Helpers that could be common
static EndpointTypeT EndpointTypeToEnum(char * in_pEndpointTypeStr)
{
if (in_pEndpointTypeStr == NULL) {
@@ -76,108 +74,6 @@ static StreamMuteT StreamMuteToEnum(char * in_pStreamMuteStr)
return STREAM_MUTE_MAXVALUE;
}
-static char * DeviceURITypeEnumToStr(DeviceURITypeT in_eDeviceURIType) {
- switch(in_eDeviceURIType) {
- case DEVICEURITYPE_ALSA_HW: // Alsa hardware device URI
- return AHL_DEVICEURITYPE_ALSA_HW;
- case DEVICEURITYPE_ALSA_DMIX: // Alsa Dmix device URI (only for playback devices)
- return AHL_DEVICEURITYPE_ALSA_DMIX;
- case DEVICEURITYPE_ALSA_DSNOOP: // Alsa DSnoop device URI (only for capture devices)
- return AHL_DEVICEURITYPE_ALSA_DSNOOP;
- case DEVICEURITYPE_ALSA_SOFTVOL: // Alsa softvol device URI
- return AHL_DEVICEURITYPE_ALSA_SOFTVOL;
- case DEVICEURITYPE_ALSA_PLUG: // Alsa plug device URI
- return AHL_DEVICEURITYPE_ALSA_PLUG;
- case DEVICEURITYPE_ALSA_OTHER: // Alsa domain URI device of unspecified type
- return AHL_DEVICEURITYPE_ALSA_OTHER;
- case DEVICEURITYPE_NOT_ALSA: // Unknown (not ALSA domain)
- return AHL_DEVICEURITYPE_NOT_ALSA;
- default:
- return "Unknown";
- }
-}
-
-static char * StreamStateEnumToStr(StreamStateT in_eStreamState) {
- switch(in_eStreamState) {
- case STREAM_STATE_IDLE:
- return AHL_STREAM_STATE_IDLE;
- case STREAM_STATE_RUNNING:
- return AHL_STREAM_STATE_RUNNING;
- case STREAM_STATE_PAUSED:
- return AHL_STREAM_STATE_PAUSED;
- default:
- return "Unknown";
- }
-}
-
-static char * StreamMuteEnumToStr(StreamMuteT in_eStreamMute) {
- switch(in_eStreamMute) {
- case STREAM_UNMUTED:
- return AHL_STREAM_UNMUTED;
- case STREAM_MUTED:
- return AHL_STREAM_MUTED;
- default:
- return "Unknown";
- }
-}
-
-static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * pAudioFormat)
-{
- wrap_json_pack(audioFormatJ, "{s:i,s:i,s:i}",
- "sample_rate", pAudioFormat->sampleRate,
- "num_channels", pAudioFormat->numChannels,
- "sample_type", pAudioFormat->sampleType);
-}
-
-// Package only information that can useful to application clients when selecting endpoint
-static void EndpointInfoStructToJSON(json_object **endpointInfoJ, EndpointInfoT * pEndpointInfo)
-{
- json_object *formatInfoJ = NULL;
- wrap_json_pack(endpointInfoJ, "{s:i,s:s,s:s,s:s,s:s,s:s,s:s}",
- "endpoint_id", pEndpointInfo->endpointID,
- "endpoint_type", (pEndpointInfo->type == ENDPOINTTYPE_SOURCE) ? AHL_ENDPOINTTYPE_SOURCE : AHL_ENDPOINTTYPE_SINK,
- "device_name", pEndpointInfo->gsDeviceName,
- "display_name", pEndpointInfo->gsDisplayName,
- "audio_role", pEndpointInfo->pRoleName,
- "device_domain",pEndpointInfo->gsDeviceDomain,
- "device_uri_type", DeviceURITypeEnumToStr(pEndpointInfo->deviceURIType));
- AudioFormatStructToJSON(&formatInfoJ,&pEndpointInfo->format);
- json_object_object_add(*endpointInfoJ,"format",formatInfoJ);
-
- // Properties
- if (pEndpointInfo->pPropTable) {
- json_object *pPropTableJ = json_object_new_array();
-
- GHashTableIter iter;
- gpointer key, value;
- g_hash_table_iter_init (&iter, pEndpointInfo->pPropTable);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- if((key!=NULL) && (value!=NULL))
- {
- json_object *pPropertyJ = NULL;
- json_object_get((json_object*)value); // Don't let the framework free our object when the request is done
- wrap_json_pack(&pPropertyJ, "{s:s,s:o}","property_name", (char*)key, "property_value", (json_object*)value);
- json_object_array_add(pPropTableJ, pPropertyJ);
- }
- }
- json_object_object_add(*endpointInfoJ,"properties",pPropTableJ);
- }
-}
-
-// Package only information that can useful to application clients when opening a stream
-static void StreamInfoStructToJSON(json_object **streamInfoJ, StreamInfoT * pStreamInfo)
-{
- json_object *endpointInfoJ = NULL;
- EndpointInfoStructToJSON(&endpointInfoJ,pStreamInfo->pEndpointInfo);
- wrap_json_pack(streamInfoJ, "{s:i,s:s,s:s,s:s}",
- "stream_id", pStreamInfo->streamID,
- "state", StreamStateEnumToStr(pStreamInfo->streamState),
- "mute", StreamMuteEnumToStr(pStreamInfo->streamMute),
- "device_uri",pStreamInfo->pEndpointInfo->gsDeviceURI); // Need to open a stream to have access to the device URI
- json_object_object_add(*streamInfoJ,"endpoint_info",endpointInfoJ);
-}
-
static streamID_t CreateNewStreamID()
{
streamID_t newID = g_AHLCtx.nextStreamID;
@@ -209,32 +105,6 @@ static EndpointInfoT * GetEndpointInfoWithRole(endpointID_t in_endpointID, Endpo
return pEndpointInfo;
}
-static int ReplaceEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole, EndpointInfoT * in_pNewEndpoint)
-{
- GPtrArray * pDeviceArray = NULL;
- if (in_endpointType == ENDPOINTTYPE_SOURCE){
- pDeviceArray = in_pRole->pSourceEndpoints;
- }
- else {
- pDeviceArray = in_pRole->pSinkEndpoints;
- }
- g_assert_nonnull(pDeviceArray);
-
- for (int j = 0; j < pDeviceArray->len; j++) {
- EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pDeviceArray,j);
- g_assert_nonnull(pCurEndpointInfo);
- if (pCurEndpointInfo->endpointID == in_endpointID) {
- g_ptr_array_insert(pDeviceArray,j,in_pNewEndpoint);
- g_ptr_array_remove_index(pDeviceArray,j+1);
- TermEndpointInfo(pCurEndpointInfo);
- // GLib automatically frees item upon array removal
- return AHL_SUCCESS;
- }
- }
-
- return AHL_FAIL;
-}
-
static EndpointInfoT * GetEndpointInfo(endpointID_t in_endpointID, EndpointTypeT in_endpointType)
{
EndpointInfoT * pEndpointInfo = NULL;
@@ -267,6 +137,79 @@ static RoleInfoT * GetRole(char * in_pAudioRoleName)
return g_hash_table_lookup(g_AHLCtx.policyCtx.pRoleInfo,in_pAudioRoleName);
}
+static int CloseStream(AHLClientCtxT * in_pClientCtx, streamID_t streamID,struct afb_req * pReq) {
+ StreamInfoT * pStreamInfo = GetStream(streamID);
+ if (pStreamInfo == NULL) {
+ AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID);
+ return AHL_FAIL;
+ }
+
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyStreamJ = NULL;
+ int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_POLICY_UTIL_FAIL)
+ {
+ AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream");
+ return AHL_FAIL;
+ }
+ int policyAllowed = Policy_CloseStream(pPolicyStreamJ);
+ if (policyAllowed == AHL_POLICY_REJECT)
+ {
+ AFB_ERROR("Close stream not allowed in current context");
+ return AHL_FAIL;
+ }
+#endif
+ // Unsubscribe client from stream events
+ if (pReq != NULL) {
+ char streamEventName[128];
+ snprintf(streamEventName,128,"ahl_streamstate_%d",streamID);
+ int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent);
+ if (iValid) {
+ err = afb_req_unsubscribe(*pReq,pStreamInfo->streamStateEvent);
+ if (err) {
+ AFB_ERROR("Could not unsubscribe to stream specific state change event");
+ return AHL_FAIL;
+ }
+ }
+ }
+
+ // Remove from stream list (if present)
+ if (g_AHLCtx.policyCtx.pStreams)
+ g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID));
+ free(pStreamInfo);
+ pStreamInfo = NULL;
+
+ // Find index for cases where there are multiple streams per client
+ // Remove from client context stream ID and endpoint ID access rights
+ if (in_pClientCtx->pStreamAccessList) {
+ for (int i = 0; i < in_pClientCtx->pStreamAccessList->len ; i++) {
+ streamID_t iID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,i);
+ if (iID == streamID) {
+ g_array_remove_index(in_pClientCtx->pStreamAccessList, i);
+ }
+ }
+ }
+
+ return AHL_SUCCESS;
+}
+
+static int CloseAllClientStreams(AHLClientCtxT * in_pClientCtx, struct afb_req * pReq)
+{
+ g_assert_nonnull(in_pClientCtx);
+ if (in_pClientCtx->pStreamAccessList != NULL) {
+ while( in_pClientCtx->pStreamAccessList->len )
+ {
+ streamID_t streamID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,0);
+ int err = CloseStream(in_pClientCtx,streamID,pReq);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ return AHL_SUCCESS;
+}
+
static AHLClientCtxT * AllocateClientContext()
{
AHLClientCtxT * pClientCtx = malloc(sizeof(AHLClientCtxT));
@@ -278,35 +221,13 @@ static void TerminateClientContext(void * ptr)
{
AHLClientCtxT * pClientCtx = (AHLClientCtxT *) ptr;
if (pClientCtx != NULL) {
-
- // Avoid having policy in bad state if client loses WS connection (e.g. app termination without close stream)
- // Force close streams in those cases.
-
- if (pClientCtx->pStreamAccessList != NULL) {
-#ifndef AHL_DISCONNECT_POLICY
- for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++)
- {
- streamID_t streamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
- // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
- StreamInfoT * pStreamInfo = GetStream(streamID);
- if (pStreamInfo == NULL) {
- AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID);
- return;
- }
-
- json_object *pPolicyStreamJ = NULL;
- int err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream");
- return;
- }
- Policy_CloseStream(pPolicyStreamJ);
- }
-#endif
+ CloseAllClientStreams(pClientCtx,NULL);
+
+ if (pClientCtx->pStreamAccessList) {
g_array_free( pClientCtx->pStreamAccessList, TRUE);
pClientCtx->pStreamAccessList = NULL;
}
+
free(pClientCtx);
}
}
@@ -327,30 +248,28 @@ static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t strea
static int CreateEvents()
{
- int err = 0;
-
g_AHLCtx.policyCtx.propertyEvent = afb_daemon_make_event(AHL_ENDPOINT_PROPERTY_EVENT);
- err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent);
+ int err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent);
if (err) {
AFB_ERROR("Could not create endpoint property change event");
- return err;
+ return AHL_FAIL;
}
g_AHLCtx.policyCtx.volumeEvent = afb_daemon_make_event(AHL_ENDPOINT_VOLUME_EVENT);
err = !afb_event_is_valid(g_AHLCtx.policyCtx.volumeEvent);
if (err) {
AFB_ERROR("Could not create endpoint volume change event");
- return err;
+ return AHL_FAIL;
}
g_AHLCtx.policyCtx.postActionEvent = afb_daemon_make_event(AHL_POST_ACTION_EVENT);
err = !afb_event_is_valid(g_AHLCtx.policyCtx.postActionEvent);
if (err) {
AFB_ERROR("Could not create post action event call event");
- return err;
+ return AHL_FAIL;
}
- return err;
+ return AHL_SUCCESS;
}
static void AhlBindingTerm()
@@ -434,42 +353,36 @@ static void AhlBindingTerm()
// Binding initialization
PUBLIC int AhlBindingInit()
{
- int err = 0;
-
memset(&g_AHLCtx,0,sizeof(g_AHLCtx));
// Register exit function
atexit(AhlBindingTerm);
- //Create AGL Events
- err=CreateEvents();
- if(err)
- {
- //Error messages already reported inside CreateEvents
- return err;
+ // Create AGL Events
+ int err = CreateEvents();
+ if(err) {
+ // Error messages already reported inside CreateEvents
+ return AHL_FAIL;
}
// Parse high-level binding JSON configuration file (will build device lists)
err = ParseHLBConfig();
- if(err)
- {
- //Error messages already reported inside ParseHLBConfig
- return err;
+ if(err) {
+ // Error messages already reported inside ParseHLBConfig
+ return AHL_FAIL;
}
#ifndef AHL_DISCONNECT_POLICY
// Policy initialization
err = Policy_Init();
- if(err == AHL_POLICY_REJECT)
- {
+ if(err == AHL_POLICY_REJECT) {
//Error messages already reported inside PolicyInit
- return err;
+ return AHL_FAIL;
}
- // for all audio Roles
+ // Call policy for initalization of all source + sink endpoints for all audio Roles
GHashTableIter iter;
gpointer key, value;
-
g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@@ -479,63 +392,73 @@ PUBLIC int AhlBindingInit()
for (int j = 0; j < pRoleInfo->pSourceEndpoints->len; j++) {
EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSourceEndpoints,j);
g_assert_nonnull(pCurEndpointInfo);
- json_object *pPolicyEndpointJ = NULL;
- err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
+ json_object *pInPolicyEndpointJ = NULL;
+ err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ);
+ if (err) {
AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err));
- return err;
+ return AHL_FAIL;
}
else
{
- err = Policy_Endpoint_Init(pPolicyEndpointJ);
+ json_object * pOutPolicyEndpointJ = NULL;
+ err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ);
if (err == AHL_POLICY_REJECT) {
- AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
- }
- //free pPolicyEndpointJ
- json_object_put(pPolicyEndpointJ);
- }
+ AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ // continue
+ }
+ json_object_put(pInPolicyEndpointJ);
+ err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ);
+ if (err) {
+ AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ return AHL_FAIL;
+ }
+ // json_object_put(pOutPolicyEndpointJ);
+ }
}
}
+
if (pRoleInfo->pSinkEndpoints){
// for all sink endpoints
for (int j = 0; j < pRoleInfo->pSinkEndpoints->len; j++) {
EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSinkEndpoints,j);
g_assert_nonnull(pCurEndpointInfo);
- json_object *pPolicyEndpointJ = NULL;
- err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
+ json_object *pInPolicyEndpointJ = NULL;
+ err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ);
+ if (err) {
AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err));
- return err;
+ return AHL_FAIL;
}
else
{
- err = Policy_Endpoint_Init(pPolicyEndpointJ);
- if (err== AHL_POLICY_REJECT) {
- AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ json_object *pOutPolicyEndpointJ = NULL;
+ err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ);
+ if (err == AHL_POLICY_REJECT) {
+ AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ // continue
}
- //free pPolicyEndpointJ
- json_object_put(pPolicyEndpointJ);
- }
-
+ json_object_put(pInPolicyEndpointJ);
+ err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ);
+ if (err) {
+ AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ return AHL_FAIL;
+ }
+ //json_object_put(pOutPolicyEndpointJ);
+ }
}
}
}
-#endif
+#endif // AHL_DISCONNECT_POLICY
// Initialize list of active streams
g_AHLCtx.policyCtx.pStreams = g_hash_table_new(g_int_hash, g_int_equal);
if(g_AHLCtx.policyCtx.pStreams == NULL)
{
AFB_ERROR("Unable to create Active Stream List");
- return err;
+ return AHL_FAIL;
}
- // TODO: Use AGL persistence framework to retrieve and set initial volumes/properties
-
AFB_DEBUG("Audio high-level Binding success");
- return err;
+ return AHL_SUCCESS;
}
PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ)
@@ -550,21 +473,22 @@ PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ)
#endif
}
-PUBLIC void audiohlapi_get_sources(struct afb_req req)
+PUBLIC void audiohlapi_get_endpoints(struct afb_req req)
{
json_object *devicesJ = NULL;
json_object *deviceJ = NULL;
json_object *queryJ = NULL;
char * audioRole = NULL;
+ char * pEndpointTypeStr = NULL;
+ EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role", &audioRole);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:s}", "audio_role", &audioRole,"endpoint_type",&pEndpointTypeStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
-
- AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
RoleInfoT * pRole = GetRole(audioRole);
if ( pRole == NULL )
@@ -575,61 +499,25 @@ PUBLIC void audiohlapi_get_sources(struct afb_req req)
else
{
devicesJ = json_object_new_array();
- GPtrArray * pDeviceArray = pRole->pSourceEndpoints;
+ GPtrArray * pDeviceArray = NULL;
+ if (endpointType == ENDPOINTTYPE_SOURCE)
+ pDeviceArray = pRole->pSourceEndpoints;
+ else
+ pDeviceArray = pRole->pSinkEndpoints;
if (pDeviceArray) {
int iNumberDevices = pDeviceArray->len;
for ( int j = 0 ; j < iNumberDevices; j++)
{
EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j);
if (pEndpointInfo) {
- EndpointInfoStructToJSON(&deviceJ, pEndpointInfo);
+ JSONPublicPackageEndpoint(pEndpointInfo,&deviceJ);
json_object_array_add(devicesJ, deviceJ);
}
}
}
}
- afb_req_success(req, devicesJ, "List of sources");
-}
-
-PUBLIC void audiohlapi_get_sinks(struct afb_req req)
-{
- json_object *devicesJ = NULL;
- json_object *deviceJ = NULL;
- json_object *queryJ = NULL;
- char * audioRole = NULL;
-
- queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role", &audioRole);
- if (err) {
- afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
- return;
- }
-
- AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole);
-
- RoleInfoT * pRole = GetRole(audioRole);
- if ( pRole == NULL )
- {
- afb_req_fail_f(req, "Invalid arguments", "Requested audio role does not exist in current configuration -> %s", json_object_get_string(queryJ));
- return;
- }
- else
- {
- devicesJ = json_object_new_array();
- GPtrArray * pDeviceArray = pRole->pSinkEndpoints;
- if (pDeviceArray) {
- int iNumberDevices = pDeviceArray->len;
- for ( int j = 0 ; j < iNumberDevices; j++)
- {
- EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j);
- EndpointInfoStructToJSON(&deviceJ, pEndpointInfo);
- json_object_array_add(devicesJ, deviceJ);
- }
- }
- }
-
- afb_req_success(req, devicesJ, "List of sinks");
+ afb_req_success(req, devicesJ, "List of endpoints");
}
PUBLIC void audiohlapi_stream_open(struct afb_req req)
@@ -650,7 +538,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req)
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = audio_role:%s endpoint_type:%s endpoint_id:%d", audioRole,endpointTypeStr,endpointID);
endpointType = EndpointTypeToEnum(endpointTypeStr);
// Check if there is already an existing context for this client
@@ -685,7 +572,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req)
// Assign a device based on configuration priority (first in the list for requested role and endpoint type)
pEndpointInfo = g_ptr_array_index(pDeviceArray,0);
endpointSelMode = ENDPOINTSELMODE_AUTO;
-
}
else{
endpointSelMode = ENDPOINTSELMODE_MANUAL;
@@ -699,7 +585,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req)
}
pEndpointInfo = NULL;
}
-
}
if (pEndpointInfo == NULL) {
@@ -724,8 +609,8 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req)
#ifndef AHL_DISCONNECT_POLICY
// Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
json_object *pPolicyStreamJ = NULL;
- err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
- if (err == AHL_POLICY_UTIL_FAIL)
+ err = StreamInfoToJSON(pStreamInfo,&pPolicyStreamJ);
+ if (err)
{
afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_OpenStream");
return;
@@ -762,7 +647,8 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req)
if (g_AHLCtx.policyCtx.pStreams)
g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo );
- StreamInfoStructToJSON(&streamInfoJ,pStreamInfo);
+ // Package and return stream information to client
+ JSONPublicPackageStream(pStreamInfo,&streamInfoJ);
afb_req_success(req, streamInfoJ, "Stream info structure");
}
@@ -773,19 +659,11 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
streamID_t streamID = AHL_UNDEFINED;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i}", "stream_id", &streamID);
+ int err = wrap_json_unpack(queryJ, "{s?i}", "stream_id", &streamID);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID);
-
-
- StreamInfoT * pStreamInfo = GetStream(streamID);
- if (pStreamInfo == NULL) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
- return;
- }
// Check if there is already an existing context for this client
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
@@ -795,150 +673,108 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
return;
}
- // Verify that this client can control the stream
- int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID );
- if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED)
- {
- afb_req_fail(req, "Access control denied", "Close stream not allowed in current client context");
- return;
- }
-
-#ifndef AHL_DISCONNECT_POLICY
- json_object *pPolicyStreamJ = NULL;
- err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_CloseStream");
- return;
- }
- // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
- int policyAllowed = Policy_CloseStream(pPolicyStreamJ);
- if (policyAllowed == AHL_POLICY_REJECT)
- {
- afb_req_fail(req, "Audio policy violation", "Close stream not allowed in current context");
- return;
- }
-#endif
-
- // Unsubscribe client from stream events
- char streamEventName[128];
- snprintf(streamEventName,128,"ahl_streamstate_%d",streamID);
- int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent);
- if (iValid) {
- err = afb_req_unsubscribe(req,pStreamInfo->streamStateEvent);
+ if (streamID == AHL_UNDEFINED) {
+ err = CloseAllClientStreams(pClientCtx,&req);
if (err) {
- afb_req_fail(req, "Stream event subscription failure", "Could not unsubscribe to stream specific state change event");
+ afb_req_fail(req, "Error closing streams", "Streams cannot close");
return;
}
}
-
- // Remove from stream list (if present)
- if (g_AHLCtx.policyCtx.pStreams)
- g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID));
- free(pStreamInfo);
- pStreamInfo = NULL;
-
- // Find index for cases where there are multiple streams per client
- // Remove from client context stream ID and endpoint ID access rights
- if (pClientCtx->pStreamAccessList) {
- for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) {
- streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
- if (iID == streamID) {
- g_array_remove_index(pClientCtx->pStreamAccessList, i);
- }
- }
-
- if (pClientCtx->pStreamAccessList->len == 0) {
- // If no more streams/endpoints owner, clear session
- afb_req_context_clear(req);
+ else {
+ err = CloseStream(pClientCtx,streamID,&req);
+ if (err) {
+ afb_req_fail_f(req, "Error closing stream", "Specified stream cannot close stream_id -> %d",streamID);
+ return;
}
}
-
+
afb_req_success(req, NULL, "Stream close completed");
}
- PUBLIC void audiohlapi_set_stream_state(struct afb_req req)
- {
- json_object *queryJ = NULL;
- streamID_t streamID = AHL_UNDEFINED;
- char * streamStateStr = NULL;
-
- queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"state",&streamStateStr);
- if (err) {
- afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
- return;
- }
- AFB_DEBUG("Parsed input arguments = stream_id:%d, state:%s", streamID,streamStateStr);
-
+static int SetStreamState(AHLClientCtxT * in_pClientCtx,struct afb_req * pReq, streamID_t streamID, char * pStreamStateStr, char * pMuteStr) {
+
StreamInfoT * pStreamInfo = GetStream(streamID);
if (pStreamInfo == NULL) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not found stream_id -> %d",streamID);
- return;
- }
-
- // Check if there is already an existing context for this client
- AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
- if (pClientCtx == NULL)
- {
- afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)");
- return;
+ afb_req_fail_f(*pReq, "Stream not found", "Specified stream not found stream_id -> %d",streamID);
+ return AHL_FAIL;
}
// Verify that this client can control the stream
- int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID );
+ int iStreamAccessControl = CheckStreamAccessControl( in_pClientCtx, streamID );
if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED)
{
- afb_req_fail(req, "Access control denied", "Set stream state not allowed in current client context");
- return;
+ afb_req_fail(*pReq, "Access control denied", "Set stream state not allowed in current client context");
+ return AHL_FAIL;
}
- StreamStateT streamState = StreamStateToEnum(streamStateStr);
+ if (pStreamStateStr != NULL) {
+ StreamStateT streamState = StreamStateToEnum(pStreamStateStr);
#ifndef AHL_DISCONNECT_POLICY
- json_object *pPolicyStreamJ = NULL;
- err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState");
- return;
- }
+ json_object *pPolicyStreamJ = NULL;
+ int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_POLICY_UTIL_FAIL)
+ {
+ afb_req_fail(*pReq, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState");
+ return AHL_FAIL;
+ }
+
+ json_object *paramJ= json_object_new_int(streamState);
+ json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ);
+
+ int policyAllowed = Policy_SetStreamState(pPolicyStreamJ);
+ if (policyAllowed == AHL_POLICY_REJECT)
+ {
+ afb_req_fail(*pReq, "Audio policy violation", "Change stream state not allowed in current context");
+ return AHL_FAIL;
+ }
+#else
+ // Simulate that policy returns target state (accepted)
+ pStreamInfo->streamState = streamState;
+#endif
+ }
- json_object *paramJ= json_object_new_int(streamState);
- json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ);
+ if (pMuteStr != NULL) {
+ StreamMuteT muteState = StreamMuteToEnum(pMuteStr);
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyStreamJ = NULL;
+ int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_POLICY_UTIL_FAIL)
+ {
+ afb_req_fail((*pReq), "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute");
+ return AHL_FAIL;
+ }
- int policyAllowed = Policy_SetStreamState(pPolicyStreamJ);
- if (policyAllowed == AHL_POLICY_REJECT)
- {
- afb_req_fail(req, "Audio policy violation", "Change stream state not allowed in current context");
- return;
- }
+ json_object *paramJ= json_object_new_int(muteState);
+ json_object_object_add(pPolicyStreamJ, "mute_state", paramJ);
+
+ int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ);
+ if (policyAllowed == AHL_POLICY_REJECT)
+ {
+ afb_req_fail(*pReq, "Audio policy violation", "Mute stream not allowed in current context");
+ return AHL_FAIL;
+ }
#else
- // Simulate that policy returns target state (accepted)
- pStreamInfo->streamState = streamState;
+ // Simulate that policy returns target state (accepted)
+ pStreamInfo->streamMute = muteState;
#endif
+ }
- afb_req_success(req, NULL, "Set stream state");
- }
+ return AHL_SUCCESS;
+}
- PUBLIC void audiohlapi_set_stream_mute(struct afb_req req)
+ PUBLIC void audiohlapi_set_stream_state(struct afb_req req)
{
json_object *queryJ = NULL;
streamID_t streamID = AHL_UNDEFINED;
+ char * streamStateStr = NULL;
char * pMuteStr = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"mute",&pMuteStr);
+ int err = wrap_json_unpack(queryJ, "{s?i,s?s,s?s}", "stream_id", &streamID,"state",&streamStateStr,"mute",&pMuteStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = stream_id:%d, mute:%s", streamID,pMuteStr);
-
- StreamInfoT * pStreamInfo = GetStream(streamID);
- if (pStreamInfo == NULL) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
- return;
- }
// Check if there is already an existing context for this client
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
@@ -948,40 +784,27 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
return;
}
- // Verify that this client can control the stream
- int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID );
- if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED)
- {
- afb_req_fail(req, "Access control denied", "Set stream mute state not allowed in current client context");
- return;
+ if (streamID == AHL_UNDEFINED) {
+ // All stream for this client
+ if (pClientCtx->pStreamAccessList != NULL) {
+ for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++)
+ {
+ streamID_t curStreamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
+ err = SetStreamState(pClientCtx,&req,curStreamID,streamStateStr,pMuteStr);
+ if (err) {
+ return;
+ }
+ }
+ }
}
-
-
- StreamMuteT muteState = StreamMuteToEnum(pMuteStr);
-#ifndef AHL_DISCONNECT_POLICY
- json_object *pPolicyStreamJ = NULL;
- err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute");
- return;
- }
-
- json_object *paramJ= json_object_new_int(muteState);
- json_object_object_add(pPolicyStreamJ, "mute_state", paramJ);
-
- int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ);
- if (policyAllowed == AHL_POLICY_REJECT)
- {
- afb_req_fail(req, "Audio policy violation", "Mute stream not allowed in current context");
- return;
+ else {
+ err = SetStreamState(pClientCtx,&req,streamID,streamStateStr,pMuteStr);
+ if (err) {
+ return;
+ }
}
-#else
- // Simulate that policy returns target state (accepted)
- pStreamInfo->streamMute = muteState;
-#endif
- afb_req_success(req, NULL, "Set stream mute completed");
+ afb_req_success(req, NULL, "Set stream state");
}
PUBLIC void audiohlapi_get_stream_info(struct afb_req req)
@@ -996,7 +819,6 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID);
StreamInfoT * pStreamInfo = GetStream(streamID);
if (pStreamInfo == NULL) {
@@ -1004,12 +826,12 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
return;
}
- StreamInfoStructToJSON(&streamInfoJ,pStreamInfo);
+ JSONPublicPackageStream(pStreamInfo,&streamInfoJ);
afb_req_success(req, streamInfoJ, "Get stream info completed");
}
-PUBLIC void audiohlapi_set_volume(struct afb_req req)
+PUBLIC void audiohlapi_volume(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
@@ -1018,12 +840,11 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req)
char * volumeStr = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i,s?s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d volume:%s", pEndpointTypeStr,endpointID,volumeStr);
endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
@@ -1033,62 +854,36 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req)
return;
}
+ if (volumeStr != NULL) {
#ifndef AHL_DISCONNECT_POLICY
- json_object *pPolicyEndpointJ = NULL;
- err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
- return;
- }
+ json_object *pPolicyEndpointJ = NULL;
+ err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_POLICY_UTIL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
+ return;
+ }
- json_object *paramJ= json_object_new_string(volumeStr);
- json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ);
+ json_object *paramJ= json_object_new_string(volumeStr);
+ json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ);
- int policyAllowed = Policy_SetVolume(pPolicyEndpointJ);
- if (!policyAllowed)
- {
- afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context");
- return;
- }
+ int policyAllowed = Policy_SetVolume(pPolicyEndpointJ);
+ if (!policyAllowed)
+ {
+ afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context");
+ return;
+ }
#else
- // Simulate that policy returns target state (accepted)
- pEndpointInfo->iVolume = atoi(volumeStr);
+ // Simulate that policy returns target state (accepted)
+ pEndpointInfo->iVolume = atoi(volumeStr);
#endif
-
- afb_req_success(req, NULL, "Set volume completed");
-}
-
-PUBLIC void audiohlapi_get_volume(struct afb_req req)
-{
- json_object *queryJ = NULL;
- endpointID_t endpointID = AHL_UNDEFINED;
- char * pEndpointTypeStr = NULL;
- EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
- json_object * volumeJ = NULL;
-
- queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:i}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID);
- if (err) {
- afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
- return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID);
- endpointType = EndpointTypeToEnum(pEndpointTypeStr);
- EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
- if (pEndpointInfo == NULL)
- {
- afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType);
- return;
- }
-
- volumeJ = json_object_new_int(pEndpointInfo->iVolume);
-
- afb_req_success(req, volumeJ, "Retrieved volume value");
+ json_object * volumeJ = json_object_new_int(pEndpointInfo->iVolume);
+
+ afb_req_success(req, volumeJ, "Set/get volume completed");
}
-// Properties
PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req)
{
json_object *queryJ = NULL;
@@ -1102,7 +897,6 @@ PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req)
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID);
endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
@@ -1113,12 +907,12 @@ PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req)
}
json_object *endpointInfoJ = NULL;
- EndpointInfoStructToJSON(&endpointInfoJ,pEndpointInfo);
+ EndpointInfoToJSON(pEndpointInfo,&endpointInfoJ);
afb_req_success(req, endpointInfoJ, "Retrieved endpoint information and properties");
}
-PUBLIC void audiohlapi_set_property(struct afb_req req)
+PUBLIC void audiohlapi_property(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
@@ -1128,12 +922,11 @@ PUBLIC void audiohlapi_set_property(struct afb_req req)
json_object * propValueJ = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s:o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s?o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName);
endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
@@ -1143,59 +936,32 @@ PUBLIC void audiohlapi_set_property(struct afb_req req)
return;
}
-#ifndef AHL_DISCONNECT_POLICY
- json_object *pPolicyEndpointJ = NULL;
- err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
- return;
- }
-
- json_object *paramJ= json_object_new_string(propertyName);
- json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ);
- json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ);
-
- // Call policy to allow custom policy actions in current context
- int policyAllowed = Policy_SetProperty(pPolicyEndpointJ);
- if (!policyAllowed)
- {
- afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context");
- return;
- }
-#else
- // Simulate that policy returns target state (accepted)
- if (pEndpointInfo->pPropTable)
- g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ);
-#endif
-
- //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,queryJ);
+ if (propValueJ != NULL) {
+ #ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyEndpointJ = NULL;
+ err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_POLICY_UTIL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
+ return;
+ }
- afb_req_success(req, NULL, "Set property completed");
-}
+ json_object *paramJ= json_object_new_string(propertyName);
+ json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ);
+ json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ);
-PUBLIC void audiohlapi_get_property(struct afb_req req)
-{
- json_object *queryJ = NULL;
- endpointID_t endpointID = AHL_UNDEFINED;
- char * pEndpointTypeStr = NULL;
- EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
- char * propertyName = NULL;
-
- queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName);
- if (err) {
- afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
- return;
- }
- AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName);
- endpointType = EndpointTypeToEnum(pEndpointTypeStr);
-
- EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
- if (pEndpointInfo == NULL)
- {
- afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType);
- return;
+ // Call policy to allow custom policy actions in current context
+ int policyAllowed = Policy_SetProperty(pPolicyEndpointJ);
+ if (!policyAllowed)
+ {
+ afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context");
+ return;
+ }
+ #else
+ // Simulate that policy returns target state (accepted)
+ if (pEndpointInfo->pPropTable)
+ g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ);
+ #endif
}
// Retrieve cached property value
@@ -1206,14 +972,10 @@ PUBLIC void audiohlapi_get_property(struct afb_req req)
}
json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object
- //AFB_WARNING("properties %s", json_object_get_string(propertyValJ));
- //json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object
- afb_req_success(req, propertyValJ, "Retrieved property value");
+ afb_req_success(req, propertyValJ, "Set/get property completed");
}
-// Audio related events
-
PUBLIC void audiohlapi_get_list_actions(struct afb_req req)
{
json_object *queryJ = NULL;
@@ -1226,7 +988,6 @@ PUBLIC void audiohlapi_get_list_actions(struct afb_req req)
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = audio_role:%s",audioRole);
// Build and return list of actions for specific audio role
RoleInfoT * pRole = GetRole(audioRole);
@@ -1264,7 +1025,6 @@ PUBLIC void audiohlapi_post_action(struct afb_req req)
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = action_name:%s audio_role:%s", actionName,audioRole);
// Verify if known action for audio role
RoleInfoT * pRole = GetRole(audioRole);
@@ -1296,7 +1056,14 @@ PUBLIC void audiohlapi_post_action(struct afb_req req)
#ifndef AHL_DISCONNECT_POLICY
// Call policy to allow custom policy actions in current context (e.g. cancel playback)
- int policyAllowed = Policy_PostAction(queryJ);
+ json_object * pActionInfo = NULL;
+ err = wrap_json_pack(&pActionInfo, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext);
+ if (err) {
+ afb_req_fail_f(req, "Invalid arguments", "Could not create action JSON object arguments");
+ return;
+ }
+ json_object_get(pActionInfo);
+ int policyAllowed = Policy_PostAction(pActionInfo);
if (!policyAllowed)
{
afb_req_fail(req, "Audio policy violation", "Post sound action not allowed in current context");
@@ -1304,63 +1071,17 @@ PUBLIC void audiohlapi_post_action(struct afb_req req)
}
#endif
- //afb_event_push(g_AHLCtx.policyCtx.postEvent,queryJ);
-
afb_req_success(req, NULL, "Posted sound action");
}
-
-// Monitoring
-PUBLIC void audiohlapi_subscribe(struct afb_req req)
-{
- json_object *queryJ = NULL;
- json_object * eventArrayJ = NULL;
-
- queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:o}", "events", &eventArrayJ);
- if (err) {
- afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
- return;
- }
-
- int iNumEvents = json_object_array_length(eventArrayJ);
- for (int i = 0; i < iNumEvents; i++)
- {
- char * pEventName = NULL;
- json_object * jEvent = json_object_array_get_idx(eventArrayJ,i);
- pEventName = (char *)json_object_get_string(jEvent);
- if(pEventName == NULL) {
- afb_req_fail(req, "failed", "Invalid event");
- return;
- }
- else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
- afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent);
- AFB_DEBUG("Client subscribed to endpoint property events");
- }
- else if(!strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)) {
- afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent);
- AFB_DEBUG("Client subscribed to endpoint volume events");
- }
- else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) {
- afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent);
- AFB_DEBUG("Client subscribed to post event calls events");
- }
- else {
- afb_req_fail(req, "failed", "Invalid event");
- return;
- }
- }
-
- afb_req_success(req, NULL, "Subscribe to events finished");
-}
-
-PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
+PUBLIC void audiohlapi_event_subscription(struct afb_req req)
{
json_object *queryJ = NULL;
json_object * eventArrayJ = NULL;
+ int iSubscribe = 1;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:o}", "events", &eventArrayJ);
+ int err = wrap_json_unpack(queryJ, "{s:o,s:i}", "events", &eventArrayJ,"subscribe",&iSubscribe);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
@@ -1377,16 +1098,22 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
return;
}
else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
- afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent);
- AFB_DEBUG("Client unsubscribed to endpoint property events");
+ if (iSubscribe)
+ afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent);
+ else
+ afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent);
}
else if(!strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)) {
- afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent);
- AFB_DEBUG("Client unsubscribed to endpoint volume events");
+ if (iSubscribe)
+ afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent);
+ else
+ afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent);
}
else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) {
- afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent);
- AFB_DEBUG("Client unsubscribed to post event calls events");
+ if (iSubscribe)
+ afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent);
+ else
+ afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent);
}
else {
afb_req_fail(req, "failed", "Invalid event");
@@ -1394,7 +1121,7 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
}
}
- afb_req_success(req, NULL, "Unsubscribe to events finished");
+ afb_req_success(req, NULL, "Event subscription update finished");
}
// Since the policy is currently in the same binding, it cannot raise events on its own
@@ -1411,42 +1138,7 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
return;
}
- if(strcasecmp(pEventName, AHL_ENDPOINT_INIT_EVENT)==0) {
- char * pAudioRole = NULL;
- endpointID_t endpointID = AHL_UNDEFINED;
- EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
- int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s}",
- "endpoint_id", &endpointID,
- "endpoint_type", &endpointType,
- "audio_role", &pAudioRole);
- if(err)
- {
- AFB_ERROR("Unable to unpack property init event");
- return;
- }
-
- RoleInfoT * pRole = GetRole(pAudioRole);
- if ( pRole == NULL ){
- AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole);
- return;
- }
-
- EndpointInfoT * pEndpointInfo = InitEndpointInfo();
- g_assert_nonnull(pEndpointInfo);
- PolicyCtxJSONToEndpoint(pEventDataJ,pEndpointInfo);
-
- err = ReplaceEndpointInfoWithRole(endpointID,endpointType,pRole,pEndpointInfo);
- if(err == AHL_FAIL)
- {
- AFB_ERROR("Can't update EndpointInfo aborting");
- return;
- }
-
- // Remove event name from object
- // json_object_object_del(pEventDataJ,"event_name");
- //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ); // Not broadcasted to application at this time
- }
- else if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) {
+ if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) {
char * pAudioRole = NULL;
char * pPropertyName = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
@@ -1470,18 +1162,18 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
}
EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole);
// update property value
- if (pEndpointInfo->pPropTable)
+ if ((pEndpointInfo!=NULL) && (pEndpointInfo->pPropTable!=NULL))
{
json_type jType = json_object_get_type(propValueJ);
switch (jType) {
case json_type_double:
- Add_Endpoint_Property_Double(pEndpointInfo,pPropertyName,json_object_get_double(propValueJ));
+ g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_double(json_object_get_double(propValueJ)));
break;
case json_type_int:
- Add_Endpoint_Property_Int(pEndpointInfo,pPropertyName,json_object_get_int(propValueJ));
+ g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_int(json_object_get_int(propValueJ)));
break;
case json_type_string:
- Add_Endpoint_Property_String(pEndpointInfo,pPropertyName,json_object_get_string(propValueJ));
+ g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_string(json_object_get_string(propValueJ)));
break;
default:
AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(propValueJ));
@@ -1512,9 +1204,16 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole);
return;
}
- EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole);
+ EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole);
// update volume value
- pEndpointInfo->iVolume = iVolume;
+ if(pEndpointInfo)
+ {
+ pEndpointInfo->iVolume = iVolume;
+ }
+ else
+ {
+ AFB_ERROR("Unable to find endpoint");
+ }
// Remove event name from object
json_object_object_del(pEventDataJ,"event_name");
afb_event_push(g_AHLCtx.policyCtx.volumeEvent,pEventDataJ);
@@ -1522,6 +1221,7 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
else if(strcasecmp(pEventName, AHL_POST_ACTION_EVENT)==0) {
// Remove event name from object
json_object_object_del(pEventDataJ,"event_name");
+ // BUG: This crashes...
afb_event_push(g_AHLCtx.policyCtx.postActionEvent,pEventDataJ);
}
else if(strcasecmp(pEventName, AHL_STREAM_STATE_EVENT)==0) {
@@ -1568,7 +1268,6 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
// Remove event name from object
json_object_object_del(pEventDataJ,"event_name");
- AFB_ERROR("pEventDataJ=%s", json_object_get_string(pEventDataJ));
afb_event_push(pStreamInfo->streamStateEvent,pEventDataJ);
}
else {
diff --git a/ahl-binding/ahl-binding.h b/ahl-binding/ahl-binding.h
index 9b4c37e..405144d 100644
--- a/ahl-binding/ahl-binding.h
+++ b/ahl-binding/ahl-binding.h
@@ -17,18 +17,15 @@
#ifndef AHL_BINDING_INCLUDE
#define AHL_BINDING_INCLUDE
-#define AFB_BINDING_VERSION 2
-
//#define AHL_DISCONNECT_POLICY // define for debugging HLB in standalone only
#include <json-c/json.h>
#include <glib.h>
-
+#define AFB_BINDING_VERSION 2
#include <afb/afb-binding.h>
#include "ahl-interface.h"
#include "ahl-policy-utils.h"
-
#ifndef PUBLIC
#define PUBLIC
#endif
@@ -39,9 +36,36 @@
#define AHL_ACCESS_CONTROL_GRANTED 1
#define AHL_ACCESS_CONTROL_DENIED 0
-#define AHL_UNDEFINED -1
#define AHL_STR_MAX_LENGTH 256
-
+
+typedef struct EndpointInfo
+{
+ endpointID_t endpointID; // Unique endpoint ID (per type)
+ EndpointTypeT type; // Source or sink device
+ char * gsDeviceName; // Unique device card name
+ char * gsDisplayName; // Application display name
+ char * gsDeviceURI; // Associated URI
+ char * gsDeviceDomain; // Device URI domain (e.g. alsa or pulse)
+ char * pRoleName; // Role assigned to this endpoint
+ DeviceURITypeT deviceURIType; // Device URI type (includes audio domain information)
+ char * gsHALAPIName; // HAL associated with the device (for volume control)
+ AlsaDeviceInfoT alsaInfo; // ALSA specific device information
+ AudioFormatT format; // Preferred audio format supported (later could be array of supported formats)
+ int iVolume; // Storage for current endpoint volume (policy effected).
+ GHashTable * pPropTable; // Storage for array of properties (policy effected)
+} EndpointInfoT;
+
+typedef struct StreamInfo {
+ streamID_t streamID; // Stream unique ID
+ EndpointInfoT * pEndpointInfo; // Associated endpoint information (reference)
+ StreamStateT streamState; // Stream activity state
+ StreamMuteT streamMute; // Stream mute state
+ struct afb_event streamStateEvent; // Stream specific event for stream state changes
+ EndpointSelectionModeT endpointSelMode; // Automatic (priority based) or manual endpoint selection
+ char * pRoleName; // Role string identifier (from role config but could be programatically overriden later)
+ int iPriority; // Role normalized priority (0-100) (from role config but could be programatically overriden later)
+ InterruptBehaviorT eInterruptBehavior; // Role behavior when interrupting lower priority streams (from role config but could be programatically overriden later)
+} StreamInfoT;
typedef struct RoleInfo {
char * pRoleName; // Role string identifier
diff --git a/ahl-binding/ahl-config.c b/ahl-binding/ahl-config.c
index 2a61b5e..c60cb9c 100644
--- a/ahl-binding/ahl-config.c
+++ b/ahl-binding/ahl-config.c
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <json-c/json.h>
@@ -85,7 +84,7 @@ static char* CtlConfigSearch(const char *dirList, const char *prefix) {
int ParseHLBConfig() {
char * versionStr = NULL;
- json_object * jAudioRoles = NULL;
+ json_object * jAudioRoles = NUL L;
json_object * jHALList = NULL;
char * policyModule = NULL;
@@ -105,13 +104,13 @@ int ParseHLBConfig() {
if(config_JFile == NULL)
{
AFB_ERROR("Error: Can't open configuration file -> %s",configfile_path);
- return 1;
+ return AHL_FAIL;
}
int err = wrap_json_unpack(config_JFile, "{s:s,s:s,s:o,s:o}", "version", &versionStr,"policy_module", &policyModule,"audio_roles",&jAudioRoles,"hal_list",&jHALList);
if (err) {
AFB_ERROR("Invalid configuration file -> %s", configfile_path);
- return 1;
+ return AHL_FAIL;
}
AFB_INFO("High-level audio API version: %s", "1.0.0");
AFB_INFO("Config version: %s", versionStr);
@@ -136,7 +135,7 @@ int ParseHLBConfig() {
if( err != 0 )
{
AFB_ERROR("Audio high level API could not set dependency on API: %s",pHAL);
- return 1;
+ return AHL_FAIL;
}
}
}
@@ -165,7 +164,7 @@ int ParseHLBConfig() {
);
if (err) {
AFB_ERROR("Invalid audio role configuration : %s", json_object_to_json_string(jAudioRole));
- return 1;
+ return AHL_FAIL;
}
if (jOutputDevices)
@@ -198,7 +197,7 @@ int ParseHLBConfig() {
err = EnumerateDevices(jInputDevices,pRoleName,ENDPOINTTYPE_SOURCE,pRoleInfo->pSourceEndpoints);
if (err) {
AFB_ERROR("Invalid input devices : %s", json_object_to_json_string(jInputDevices));
- return 1;
+ return AHL_FAIL;
}
}
// Sinks
@@ -207,15 +206,14 @@ int ParseHLBConfig() {
err = EnumerateDevices(jOutputDevices,pRoleName,ENDPOINTTYPE_SINK,pRoleInfo->pSinkEndpoints);
if (err) {
AFB_ERROR("Invalid output devices : %s", json_object_to_json_string(jOutputDevices));
- return 1;
+ return AHL_FAIL;
}
}
g_hash_table_insert(g_AHLCtx.policyCtx.pRoleInfo, pRoleInfo->pRoleName, pRoleInfo);
-
}
// Build lists of all device URI referenced in config file (input/output)
AFB_DEBUG ("Audio high-level - Parse high-level audio configuration done");
- return 0;
+ return AHL_SUCCESS;
}
diff --git a/ahl-binding/ahl-deviceenum.c b/ahl-binding/ahl-deviceenum.c
index 7e67d7a..763b2ca 100644
--- a/ahl-binding/ahl-deviceenum.c
+++ b/ahl-binding/ahl-deviceenum.c
@@ -14,16 +14,9 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
#include <alsa/asoundlib.h>
#include <alsa/pcm.h>
-#include <json-c/json.h>
-#include "wrap-json.h"
-
#include "ahl-binding.h"
-#include "ahl-policy.h"
extern AHLCtxT g_AHLCtx;
@@ -59,7 +52,7 @@ static int SeparateDomainFromDeviceURI( char * in_pDeviceURI, char ** out_pDomai
AFB_ERROR("Error tokenizing device URI -> %s",in_pDeviceURI);
return 1;
}
- return 0;
+ return AHL_SUCCESS;
}
static int IsAlsaDomain(const char * in_pDomainStr)
@@ -90,7 +83,6 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
snd_pcm_info_t * pPcmInfo = NULL;
int iAlsaRet = 0;
const char * pCardName = NULL;
- int retVal = 0;
snd_ctl_t * ctlHandle = NULL;
snd_ctl_card_info_t * ctlInfo = NULL;
@@ -121,7 +113,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
if (iAlsaRet < 0)
{
AFB_WARNING("Error retrieving PCM device info");
- return 1;
+ return AHL_FAIL;
}
// get card number
@@ -129,7 +121,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
if ( out_pEndpointInfo->alsaInfo.cardNum < 0 )
{
AFB_WARNING("No Alsa card number available");
- return 1;
+ return AHL_FAIL;
}
// get device number
@@ -137,7 +129,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
if ( out_pEndpointInfo->alsaInfo.deviceNum < 0 )
{
AFB_WARNING("No Alsa device number available");
- return 1;
+ return AHL_FAIL;
}
// get sub-device number
@@ -145,7 +137,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
if ( out_pEndpointInfo->alsaInfo.subDeviceNum < 0 )
{
AFB_WARNING("No Alsa subdevice number available");
- return 1;
+ return AHL_FAIL;
}
char cardName[32];
@@ -154,7 +146,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
if ( iAlsaRet < 0 )
{
AFB_WARNING("Could not open ALSA card control");
- return 1;
+ return AHL_FAIL;
}
iAlsaRet = snd_ctl_card_info(ctlHandle, ctlInfo);
@@ -162,7 +154,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
{
AFB_WARNING("Could not retrieve ALSA card info");
snd_ctl_close(ctlHandle);
- return 1;
+ return AHL_FAIL;
}
// Populate unique target card name
@@ -171,13 +163,13 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp
{
AFB_WARNING("No Alsa card name available");
snd_ctl_close(ctlHandle);
- return 1;
+ return AHL_FAIL;
}
- out_pEndpointInfo->gsDeviceName = g_strdup(pCardName);
+ g_strlcpy(out_pEndpointInfo->gsDeviceName,pCardName,AHL_STR_MAX_LENGTH);
snd_ctl_close(ctlHandle);
- return retVal;
+ return AHL_SUCCESS;
}
EndpointInfoT * InitEndpointInfo()
@@ -193,6 +185,20 @@ EndpointInfoT * InitEndpointInfo()
pEndpointInfo->format.sampleRate = AHL_UNDEFINED;
pEndpointInfo->format.numChannels = AHL_UNDEFINED;
pEndpointInfo->format.sampleType = AHL_FORMAT_UNKNOWN;
+ // Assigned by device enumeration
+ pEndpointInfo->gsDeviceName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->gsDeviceName,0,AHL_STR_MAX_LENGTH*sizeof(char));
+ pEndpointInfo->gsDeviceDomain = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->gsDeviceDomain,0,AHL_STR_MAX_LENGTH*sizeof(char));
+ pEndpointInfo->pRoleName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->pRoleName,0,AHL_STR_MAX_LENGTH*sizeof(char));
+ pEndpointInfo->gsDeviceURI = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->gsDeviceURI,0,AHL_STR_MAX_LENGTH*sizeof(char));
+ // Assigned by policy initialization
+ pEndpointInfo->gsDisplayName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->gsDisplayName,0,AHL_STR_MAX_LENGTH*sizeof(char));
+ pEndpointInfo->gsHALAPIName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
+ memset(pEndpointInfo->gsHALAPIName,0,AHL_STR_MAX_LENGTH*sizeof(char));
pEndpointInfo->pPropTable = g_hash_table_new(g_str_hash, g_str_equal);
return pEndpointInfo;
}
@@ -200,12 +206,12 @@ EndpointInfoT * InitEndpointInfo()
void TermEndpointInfo( EndpointInfoT * out_pEndpointInfo )
{
#define SAFE_FREE(__ptr__) if(__ptr__) g_free(__ptr__); __ptr__ = NULL;
- SAFE_FREE(out_pEndpointInfo->gsDeviceName);
- SAFE_FREE(out_pEndpointInfo->gsDisplayName);
+ SAFE_FREE(out_pEndpointInfo->gsDeviceName);
SAFE_FREE(out_pEndpointInfo->gsDeviceDomain);
SAFE_FREE(out_pEndpointInfo->pRoleName);
SAFE_FREE(out_pEndpointInfo->gsDeviceURI);
SAFE_FREE(out_pEndpointInfo->gsHALAPIName);
+ SAFE_FREE(out_pEndpointInfo->gsDisplayName);
if (out_pEndpointInfo->pPropTable) {
// Free json_object for all property values
@@ -236,7 +242,7 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi
char * pDeviceURIDomain = NULL;
char * pFullDeviceURI = NULL;
char * pDeviceURIPCM = NULL;
- int err = 0;
+ int err = AHL_SUCCESS;
json_object * jDevice = json_object_array_get_idx(in_jDeviceArray,i);
if (jDevice == NULL) {
@@ -258,10 +264,10 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi
// non ALSA URI are simply passed to application (no validation) at this time
// In Non ALSA case devices in config are assumed to be available, if not application can fallback on explicit device selection
- pEndpointInfo->gsDeviceName = g_strdup(pDeviceURIPCM);
- pEndpointInfo->gsDeviceDomain = g_strdup(pDeviceURIDomain);
- pEndpointInfo->gsDeviceURI = g_strdup(pDeviceURIPCM);
- pEndpointInfo->pRoleName = g_strdup(in_pAudioRole);
+ g_strlcpy(pEndpointInfo->gsDeviceName,pDeviceURIPCM,AHL_STR_MAX_LENGTH);
+ g_strlcpy(pEndpointInfo->gsDeviceDomain,pDeviceURIDomain,AHL_STR_MAX_LENGTH);
+ g_strlcpy(pEndpointInfo->gsDeviceURI,pDeviceURIPCM,AHL_STR_MAX_LENGTH);
+ g_strlcpy(pEndpointInfo->pRoleName ,in_pAudioRole,AHL_STR_MAX_LENGTH);
g_free(pFullDeviceURICopy);
pFullDeviceURICopy = NULL;
@@ -315,11 +321,6 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi
pEndpointInfo->endpointID = in_deviceType == ENDPOINTTYPE_SOURCE ? CreateNewSourceID() : CreateNewSinkID();
pEndpointInfo->type = in_deviceType;
- // Assigned by policy initialization
- pEndpointInfo->gsDisplayName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
- memset(pEndpointInfo->gsDisplayName,0,AHL_STR_MAX_LENGTH*sizeof(char));
- pEndpointInfo->gsHALAPIName = malloc(AHL_STR_MAX_LENGTH*sizeof(char));
- memset(pEndpointInfo->gsDisplayName,0,AHL_STR_MAX_LENGTH*sizeof(char));
// add to structure to list of available devices
g_ptr_array_add(out_pEndpointArray, pEndpointInfo);
@@ -327,5 +328,5 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi
} // for all devices
AFB_DEBUG ("Audio high-level - Enumerate devices done");
- return 0;
+ return AHL_SUCCESS;
} \ No newline at end of file
diff --git a/ahl-binding/ahl-json.c b/ahl-binding/ahl-json.c
new file mode 100644
index 0000000..5e8bf97
--- /dev/null
+++ b/ahl-binding/ahl-json.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2017 "Audiokinetic Inc"
+ *
+ * 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.
+ */
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+#include "wrap-json.h"
+#include <json-c/json.h>
+#include <glib.h>
+#include "ahl-binding.h"
+
+static char * DeviceURITypeEnumToStr(DeviceURITypeT in_eDeviceURIType) {
+ switch(in_eDeviceURIType) {
+ case DEVICEURITYPE_ALSA_HW: // Alsa hardware device URI
+ return AHL_DEVICEURITYPE_ALSA_HW;
+ case DEVICEURITYPE_ALSA_DMIX: // Alsa Dmix device URI (only for playback devices)
+ return AHL_DEVICEURITYPE_ALSA_DMIX;
+ case DEVICEURITYPE_ALSA_DSNOOP: // Alsa DSnoop device URI (only for capture devices)
+ return AHL_DEVICEURITYPE_ALSA_DSNOOP;
+ case DEVICEURITYPE_ALSA_SOFTVOL: // Alsa softvol device URI
+ return AHL_DEVICEURITYPE_ALSA_SOFTVOL;
+ case DEVICEURITYPE_ALSA_PLUG: // Alsa plug device URI
+ return AHL_DEVICEURITYPE_ALSA_PLUG;
+ case DEVICEURITYPE_ALSA_OTHER: // Alsa domain URI device of unspecified type
+ return AHL_DEVICEURITYPE_ALSA_OTHER;
+ case DEVICEURITYPE_NOT_ALSA: // Unknown (not ALSA domain)
+ return AHL_DEVICEURITYPE_NOT_ALSA;
+ default:
+ return "Unknown";
+ }
+}
+
+static char * StreamStateEnumToStr(StreamStateT in_eStreamState) {
+ switch(in_eStreamState) {
+ case STREAM_STATE_IDLE:
+ return AHL_STREAM_STATE_IDLE;
+ case STREAM_STATE_RUNNING:
+ return AHL_STREAM_STATE_RUNNING;
+ case STREAM_STATE_PAUSED:
+ return AHL_STREAM_STATE_PAUSED;
+ default:
+ return "Unknown";
+ }
+}
+
+static char * StreamMuteEnumToStr(StreamMuteT in_eStreamMute) {
+ switch(in_eStreamMute) {
+ case STREAM_UNMUTED:
+ return AHL_STREAM_UNMUTED;
+ case STREAM_MUTED:
+ return AHL_STREAM_MUTED;
+ default:
+ return "Unknown";
+ }
+}
+
+static int EndpointPropTableToJSON(GHashTable * pPropTable, json_object **ppProptableJ)
+{
+ if(pPropTable == NULL)
+ {
+ AFB_ERROR("Invalid EndpointPropTableToJSON arguments");
+ return AHL_FAIL;
+ }
+
+ // Create json object for PropTable
+ *ppProptableJ = json_object_new_array();
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init (&iter, pPropTable);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if ( key != NULL && value != NULL) {
+ json_object *pPropertyJ = NULL;
+ json_object_get(value);
+ int err = wrap_json_pack(&pPropertyJ, "{s:s,s:o}",
+ "property_name", (char*)key,
+ "property_value", value
+ );
+ if(err)
+ {
+ AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+ json_object_array_add(*ppProptableJ, pPropertyJ);
+ }
+ }
+
+ return AHL_SUCCESS;
+}
+
+int EndpointInfoToJSON(EndpointInfoT * pEndpointInfo, json_object **ppEndpointInfoJ)
+{
+ if(pEndpointInfo == NULL || pEndpointInfo->pPropTable == NULL)
+ {
+ AFB_ERROR("Invalid EndpointInfoToJSON arguments");
+ return AHL_FAIL;
+ }
+
+ json_object * pPropTableJ = NULL;
+ int err = EndpointPropTableToJSON(pEndpointInfo->pPropTable,&pPropTableJ);
+ if (err) {
+ return AHL_FAIL;
+ }
+
+ // Create json object for EndpointInfo
+ err = wrap_json_pack(ppEndpointInfoJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:o}",
+ "endpoint_id", pEndpointInfo->endpointID,
+ "endpoint_type", pEndpointInfo->type,
+ "device_name", pEndpointInfo->gsDeviceName,
+ "display_name", pEndpointInfo->gsDisplayName,
+ "device_uri", pEndpointInfo->gsDeviceURI,
+ "device_domain", pEndpointInfo->gsDeviceDomain,
+ "audio_role",pEndpointInfo->pRoleName,
+ "device_uri_type", pEndpointInfo->deviceURIType,
+ "hal_api_name", pEndpointInfo->gsHALAPIName,
+ "alsa_cardNum", pEndpointInfo->alsaInfo.cardNum,
+ "alsa_deviceNum", pEndpointInfo->alsaInfo.deviceNum,
+ "alsa_subDeviceNum", pEndpointInfo->alsaInfo.subDeviceNum,
+ "format_samplerate", pEndpointInfo->format.sampleRate,
+ "format_numchannels", pEndpointInfo->format.numChannels,
+ "format_sampletype",pEndpointInfo->format.sampleType,
+ "volume", pEndpointInfo->iVolume,
+ "property_table", pPropTableJ
+ );
+ if (err) {
+ AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+
+ return AHL_SUCCESS;
+}
+
+int StreamInfoToJSON(StreamInfoT * pStreamInfo, json_object **ppStreamInfoJ)
+{
+ if(pStreamInfo == NULL)
+ {
+ AFB_ERROR("Invalid arguments to StreamInfoToJSON");
+ return AHL_FAIL;
+ }
+
+ json_object * pEndpointInfoJ = NULL;
+ int err = EndpointInfoToJSON(pStreamInfo->pEndpointInfo, &pEndpointInfoJ);
+ if (err) {
+ return AHL_FAIL;
+ }
+
+ // Create json object for stream
+ err = wrap_json_pack(ppStreamInfoJ, "{s:i,s:i,s:i,s:I,s:i,s:s,s:i,s:i,s:o}",
+ "stream_id", pStreamInfo->streamID,
+ "stream_state", pStreamInfo->streamState,
+ "stream_mute", pStreamInfo->streamMute,
+ "stream_state_event", &pStreamInfo->streamStateEvent,
+ "endpoint_sel_mod", pStreamInfo->endpointSelMode,
+ "role_name", pStreamInfo->pRoleName,
+ "priority", pStreamInfo->iPriority,
+ "interrupt_behavior", pStreamInfo->eInterruptBehavior,
+ "endpoint_info", pEndpointInfoJ
+ );
+ if (err) {
+ AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+
+ return AHL_SUCCESS;
+}
+
+static int UpdatePropertyList(GHashTable * pPropTable, json_object * pPropTableJ) {
+ if (pPropTable == NULL || pPropTableJ == NULL) {
+ AFB_ERROR("Invalid arguments to UpdatePropertyList");
+ return AHL_FAIL;
+ }
+ // Unpack prop table
+ int nbProperties = json_object_array_length(pPropTableJ);
+ for(int i = 0; i < nbProperties; i++)
+ {
+ json_object * propJ = json_object_array_get_idx(pPropTableJ,i);
+ if (propJ) {
+ char * pPropertyName = NULL;
+ json_object * pPropertyValueJ = NULL;
+ int err = wrap_json_unpack(propJ, "{s:s,s:o}",
+ "property_name", &pPropertyName,
+ "property_value", &pPropertyValueJ);
+ if (err) {
+ AFB_ERROR("Unable to unpack JSON property, = %s", wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+
+ // Object type detection for property value (string = state, numeric = property)
+ json_type jType = json_object_get_type(pPropertyValueJ);
+ switch (jType) {
+ case json_type_double:
+ g_hash_table_insert(pPropTable, pPropertyName, json_object_new_double(json_object_get_double(pPropertyValueJ)));
+ break;
+ case json_type_int:
+ g_hash_table_insert(pPropTable, pPropertyName, json_object_new_int(json_object_get_int(pPropertyValueJ)));
+ break;
+ case json_type_string:
+ g_hash_table_insert(pPropTable, pPropertyName, json_object_new_string(json_object_get_string(pPropertyValueJ)));
+ break;
+ default:
+ AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(pPropertyValueJ));
+ return AHL_FAIL;
+ }
+ }
+ }
+
+ return AHL_SUCCESS;
+}
+
+int UpdateEndpointInfo(EndpointInfoT * pEndpoint, json_object * pEndpointInfoJ) {
+
+ if(pEndpoint == NULL || pEndpointInfoJ == NULL)
+ {
+ AFB_ERROR("Invalid arguments to UpdateEndpointInfo");
+ return AHL_FAIL;
+ }
+
+ // Push information to endpoint info struct
+ json_object * pPropTableJ = NULL;
+ char * pDisplayName = NULL;
+ char * pHALName = NULL;
+ int err = wrap_json_unpack(pEndpointInfoJ,"{s:i,s:s,s:s,s:o}",
+ "init_volume",&pEndpoint->iVolume,
+ "display_name",&pDisplayName,
+ "hal_name", &pHALName,
+ "property_table",&pPropTableJ);
+ if (err) {
+ AFB_ERROR("Unable to create Endpoint Json object error:%s ",wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+ g_strlcpy(pEndpoint->gsDisplayName,pDisplayName,AHL_STR_MAX_LENGTH);
+ g_strlcpy(pEndpoint->gsHALAPIName,pHALName,AHL_STR_MAX_LENGTH);
+
+ if (pEndpoint->pPropTable && pPropTableJ) {
+ err = UpdatePropertyList(pEndpoint->pPropTable,pPropTableJ);
+ if (err) {
+ AFB_ERROR("Unable to update property table Json object error:%s ",wrap_json_get_error_string(err));
+ return AHL_FAIL;
+ }
+ }
+
+ return AHL_SUCCESS;
+}
+
+static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * pAudioFormat)
+{
+ wrap_json_pack(audioFormatJ, "{s:i,s:i,s:i}",
+ "sample_rate", pAudioFormat->sampleRate,
+ "num_channels", pAudioFormat->numChannels,
+ "sample_type", pAudioFormat->sampleType);
+}
+
+// Package only information that can useful to application clients when selecting endpoint
+void JSONPublicPackageEndpoint(EndpointInfoT * pEndpointInfo,json_object **endpointInfoJ)
+{
+ json_object *formatInfoJ = NULL;
+ wrap_json_pack(endpointInfoJ, "{s:i,s:s,s:s,s:s,s:s,s:s,s:s}",
+ "endpoint_id", pEndpointInfo->endpointID,
+ "endpoint_type", (pEndpointInfo->type == ENDPOINTTYPE_SOURCE) ? AHL_ENDPOINTTYPE_SOURCE : AHL_ENDPOINTTYPE_SINK,
+ "device_name", pEndpointInfo->gsDeviceName,
+ "display_name", pEndpointInfo->gsDisplayName,
+ "audio_role", pEndpointInfo->pRoleName,
+ "device_domain",pEndpointInfo->gsDeviceDomain,
+ "device_uri_type", DeviceURITypeEnumToStr(pEndpointInfo->deviceURIType));
+ AudioFormatStructToJSON(&formatInfoJ,&pEndpointInfo->format);
+ json_object_object_add(*endpointInfoJ,"format",formatInfoJ);
+
+ json_object *pPropTableJ = NULL;
+ EndpointPropTableToJSON(pEndpointInfo->pPropTable,&pPropTableJ);
+ json_object_object_add(*endpointInfoJ,"properties",pPropTableJ);
+}
+
+// Package only information that can useful to application clients when opening a stream
+void JSONPublicPackageStream(StreamInfoT * pStreamInfo,json_object **streamInfoJ)
+{
+ json_object *endpointInfoJ = NULL;
+ JSONPublicPackageEndpoint(pStreamInfo->pEndpointInfo,&endpointInfoJ);
+ wrap_json_pack(streamInfoJ, "{s:i,s:s,s:s,s:s}",
+ "stream_id", pStreamInfo->streamID,
+ "state", StreamStateEnumToStr(pStreamInfo->streamState),
+ "mute", StreamMuteEnumToStr(pStreamInfo->streamMute),
+ "device_uri",pStreamInfo->pEndpointInfo->gsDeviceURI); // Need to open a stream to have access to the device URI
+ json_object_object_add(*streamInfoJ,"endpoint_info",endpointInfoJ);
+} \ No newline at end of file
diff --git a/ahl-binding/ahl-json.h b/ahl-binding/ahl-json.h
new file mode 100644
index 0000000..ffd683a
--- /dev/null
+++ b/ahl-binding/ahl-json.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 "Audiokinetic Inc"
+ *
+ * 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 AHL_POLICY_JSON_INCLUDE
+#define AHL_POLICY_JSON_INCLUDE
+
+int EndpointInfoToJSON(EndpointInfoT * pEndpointInfo, json_object **ppEndpointInfoJ);
+int StreamInfoToJSON(StreamInfoT * pStreamInfo, json_object **ppStreamInfoJ);
+int UpdateEndpointInfo(EndpointInfoT * pEndpoint,json_object * pEndpointInfoJ);
+void JSONPublicPackageEndpoint(EndpointInfoT * pEndpointInfo,json_object **endpointInfoJ);
+void JSONPublicPackageStream(StreamInfoT * pStreamInfo,json_object **streamInfoJ);
+
+#endif // AHL_POLICY_JSON_INCLUDE
diff --git a/ahl-policy/ahl-interface.h b/ahl-policy/ahl-interface.h
index 0488e96..fc0ac68 100644
--- a/ahl-policy/ahl-interface.h
+++ b/ahl-policy/ahl-interface.h
@@ -35,11 +35,8 @@
// Property/Volume/Action events
#define AHL_ENDPOINT_PROPERTY_EVENT "ahl_endpoint_property_event"
#define AHL_ENDPOINT_VOLUME_EVENT "ahl_endpoint_volume_event"
-#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event"
#define AHL_POST_ACTION_EVENT "ahl_post_action"
#define AHL_STREAM_STATE_EVENT "ahl_stream_state_event"
-#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event"
-
// Stream state event types
#define AHL_STREAM_EVENT_START "start" // Stream is inactive
diff --git a/ahl-policy/ahl-policy.c b/ahl-policy/ahl-policy.c
index 5d2e324..4a34ed8 100644
--- a/ahl-policy/ahl-policy.c
+++ b/ahl-policy/ahl-policy.c
@@ -14,15 +14,38 @@
* limitations under the License.
*/
-#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+#include <glib.h>
#include "wrap-json.h"
#include "ahl-policy-utils.h"
#include "ahl-interface.h"
#include "ahl-policy.h"
+#ifndef AHL_DISCONNECT_POLICY
+
+#define AK_POLICY_DEMO //For Audiokinetic demo only
+
+typedef struct StreamPolicyInfo {
+ streamID_t streamID;
+ int RolePriority;
+ char * pAudioRole;
+ InterruptBehaviorT interruptBehavior;
+ int iDuckVolume; //duck Volume
+} StreamPolicyInfoT;
+
+typedef struct EndPointPolicyInfo {
+ endpointID_t endpointID;
+ EndpointTypeT type;
+ DeviceURITypeT deviceType;
+ char * pDeviceName;
+ char * pHalApiName;
+ int iVolume; //Current Volume
+ GArray * streamInfo; //List of playing or duck stream at a given endpoint
+} EndPointPolicyInfoT;
typedef enum SystemState {
SYSTEM_STARTUP = 0, // Startup
@@ -32,7 +55,6 @@ typedef enum SystemState {
SYSTEM_MAXVALUE // Enum count, keep at the end
} SystemStateT;
-
typedef struct HalInfo {
char *pDevID;
char *pAPIName;
@@ -53,12 +75,9 @@ typedef struct PolicyLocalCtx {
SystemStateT systemState;
} PolicyLocalCtxT;
-#ifndef AHL_DISCONNECT_POLICY
-
-// Global Context
+// Policy context
PolicyLocalCtxT g_PolicyCtx;
-
// Helper Functions
static int getStreamConfig(char *pAudioRole, StreamConfigT *pStreamConfig)
{
@@ -120,7 +139,7 @@ static int getStreamConfig(char *pAudioRole, StreamConfigT *pStreamConfig)
static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName, char *AudioRole, DeviceURITypeT deviceType, int iVolume, bool bMute)
{
- if(pHalApiName == NULL)
+ if(pHalApiName == NULL || (strcasecmp(pHalApiName, AHL_POLICY_UNDEFINED_HALNAME) == 0))
{
AFB_WARNING("SetVolume cannot be accomplished without proper HAL association");
return POLICY_FAIL;
@@ -156,15 +175,14 @@ static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
}
break;
default:
- //Set volume to zero for display purpose only.
- //Not support yet
+ // Not supported yet
AFB_WARNING("Device Type %i is not support and can't set volume on HalName %s",deviceType, pHalApiName);
return POLICY_FAIL;
break;
}
// Set endpoint volume using HAL services (leveraging ramps etc.)
- json_object *j_response, *j_query = NULL;
+ json_object *j_response = NULL, *j_query = NULL;
// Package query
int err = wrap_json_pack(&j_query,"{s:s,s:i}","label",gsHALControlName->str, "val",iVolume);
@@ -174,7 +192,7 @@ static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
return POLICY_FAIL;
}
- //TODO implement Volume limitation based on policy
+ // TODO: implement Volume limitation based on policy
// Set the volume using the HAL
err = afb_service_call_sync(pHalApiName, "ctlset", j_query, &j_response);
@@ -216,7 +234,7 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
case DEVICEURITYPE_ALSA_PLUG:
case DEVICEURITYPE_ALSA_SOFTVOL:
gsHALControlName = g_string_new(AudioRole);
- g_string_append(gsHALControlName,"_Vol"); // Or _Vol for direct control (no ramping)
+ g_string_append(gsHALControlName,"_Vol"); // Return target value
break;
default:
// Set volume to zero for display purpose only.
@@ -237,8 +255,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
return POLICY_FAIL;
}
- //TODO implement Volume limitation based on policy
-
// Get the volume using the HAL
err = afb_service_call_sync(pHalApiName, "ctlget", j_query, &j_response);
if (err)
@@ -262,8 +278,7 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
if (err) {
AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal));
return POLICY_FAIL;
- }
-
+ }
}
else
{
@@ -272,7 +287,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal));
return POLICY_FAIL;
}
-
}
*pVolume = val1;
@@ -293,7 +307,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName
static void PolicyPostStateEvent(int iStreamID, StreamEventT eventState)
{
-
json_object * eventDataJ = NULL;
int err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i}","event_name", AHL_STREAM_STATE_EVENT,"stream_id",iStreamID, "state_event",eventState);
if (err)
@@ -332,23 +345,22 @@ static EndPointPolicyInfoT *PolicySearchEndPoint(EndpointTypeT type, char *pDevi
return NULL;
}
-
-static int PolicyAddEndPoint(StreamInfoT *pStreamInfo)
+static int PolicyAddEndPoint(StreamInterfaceInfoT *pStreamInfo)
{
- EndPointPolicyInfoT *pPolicyEndPoint = PolicySearchEndPoint(pStreamInfo->pEndpointInfo->type, pStreamInfo->pEndpointInfo->gsDeviceName);
+ EndPointPolicyInfoT *pPolicyEndPoint = PolicySearchEndPoint(pStreamInfo->endpoint.type, pStreamInfo->endpoint.gsDeviceName);
if(pPolicyEndPoint == NULL)
{
//create EndPoint and add playing stream
EndPointPolicyInfoT newEndPointPolicyInfo;
- newEndPointPolicyInfo.endpointID = pStreamInfo->pEndpointInfo->endpointID;
- newEndPointPolicyInfo.type = pStreamInfo->pEndpointInfo->type;
- newEndPointPolicyInfo.deviceType = pStreamInfo->pEndpointInfo->deviceURIType;
- newEndPointPolicyInfo.pDeviceName = strdup(pStreamInfo->pEndpointInfo->gsDeviceName);
- newEndPointPolicyInfo.pHalApiName = strdup(pStreamInfo->pEndpointInfo->gsHALAPIName);
- newEndPointPolicyInfo.iVolume = pStreamInfo->pEndpointInfo->iVolume;
- newEndPointPolicyInfo.streamInfo = g_array_new(FALSE, TRUE, sizeof(StreamPolicyInfoT));;
-
- if(pStreamInfo->pEndpointInfo->type == ENDPOINTTYPE_SINK)
+ newEndPointPolicyInfo.endpointID = pStreamInfo->endpoint.endpointID;
+ newEndPointPolicyInfo.type = pStreamInfo->endpoint.type;
+ newEndPointPolicyInfo.deviceType = pStreamInfo->endpoint.deviceURIType;
+ newEndPointPolicyInfo.pDeviceName = strdup(pStreamInfo->endpoint.gsDeviceName);
+ newEndPointPolicyInfo.pHalApiName = strdup(pStreamInfo->endpoint.gsHALAPIName);
+ newEndPointPolicyInfo.iVolume = pStreamInfo->endpoint.iVolume;
+ newEndPointPolicyInfo.streamInfo = g_array_new(FALSE, TRUE, sizeof(StreamPolicyInfoT));
+
+ if(pStreamInfo->endpoint.type == ENDPOINTTYPE_SINK)
{
g_array_append_val(g_PolicyCtx.pSinkEndpoints, newEndPointPolicyInfo);
}
@@ -361,8 +373,7 @@ static int PolicyAddEndPoint(StreamInfoT *pStreamInfo)
return POLICY_SUCCESS;
}
-
-static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInfoT *pStreamInfo)
+static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInterfaceInfoT *pStreamInfo)
{
StreamPolicyInfoT newStreamPolicyInfo;
@@ -375,16 +386,15 @@ static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInfoT
return POLICY_SUCCESS;
}
-static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,StreamInfoT * pStreamInfo)
+static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,StreamInterfaceInfoT * pStreamInfo)
{
int err=0;
if(pCurrEndPointPolicy == NULL || pCurrEndPointPolicy->streamInfo->len == 0)
{
- //Remove endpoint
- AFB_ERROR("StreamID not found in active Endpoint when Running to Idle transition is request");
+ AFB_ERROR("StreamID not found in active endpoint when running to idle transition is requested");
return POLICY_FAIL;
}
- //Search for the matching stream
+ // Search for the matching stream
for(int i=0; i<pCurrEndPointPolicy->streamInfo->len; i++)
{
StreamPolicyInfoT currentPolicyStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,i);
@@ -400,7 +410,7 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
{
case INTERRUPTBEHAVIOR_CONTINUE:
//unduck and set Volume back to original value
- err= PolicySetVolume(pCurrEndPointPolicy->endpointID,
+ err = PolicySetVolume(pCurrEndPointPolicy->endpointID,
pCurrEndPointPolicy->type,
pCurrEndPointPolicy->pHalApiName,
HighPriorityStreamInfo.pAudioRole,
@@ -413,21 +423,15 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
}
return POLICY_SUCCESS;
- break;
case INTERRUPTBEHAVIOR_PAUSE:
- //pInterruptStreamInfo->streamState = STREAM_STATE_RUNNING;
PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_RESUME);
return POLICY_SUCCESS;
- break;
-
case INTERRUPTBEHAVIOR_CANCEL:
PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_START);
return POLICY_SUCCESS;
- break;
default:
AFB_ERROR("Unsupported Intterupt Behavior");
return POLICY_FAIL;
- break;
}
}
}
@@ -435,7 +439,7 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
return POLICY_SUCCESS;
}
-static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInfoT * pStreamInfo)
+static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInterfaceInfoT * pStreamInfo)
{
int err=0;
if(pCurrEndPointPolicy->streamInfo == NULL)
@@ -459,7 +463,7 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
{
case INTERRUPTBEHAVIOR_CONTINUE:
//Save the current Volume and set the docking volume
- pCurrentActiveStreamInfo->iDuckVolume = pStreamInfo->pEndpointInfo->iVolume;
+ pCurrentActiveStreamInfo->iDuckVolume = pStreamInfo->endpoint.iVolume;
StreamConfigT StreamConfig;
err = getStreamConfig(pStreamInfo->pRoleName, &StreamConfig);
if(err == POLICY_FAIL)
@@ -467,7 +471,7 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
AFB_ERROR("Error getting stream configuration for audiorole: %s", pStreamInfo->pRoleName);
return POLICY_FAIL;
}
- err= PolicySetVolume(pCurrEndPointPolicy->endpointID,
+ err = PolicySetVolume(pCurrEndPointPolicy->endpointID,
pCurrEndPointPolicy->type,
pCurrEndPointPolicy->pHalApiName,
pCurrentActiveStreamInfo->pAudioRole,
@@ -483,7 +487,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
case INTERRUPTBEHAVIOR_PAUSE:
PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_PAUSE);
break;
-
case INTERRUPTBEHAVIOR_CANCEL:
PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_STOP);
g_array_remove_index(pCurrEndPointPolicy->streamInfo, pCurrEndPointPolicy->streamInfo->len-1);
@@ -491,8 +494,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
default:
AFB_ERROR("Unsupported Intterupt Behavior");
return AHL_POLICY_REJECT;
- break;
-
}
//Add the playing stream at last
@@ -503,9 +504,7 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
//Higher Priority Stream is playing
AFB_ERROR("Higher Priority Stream is playing");
return POLICY_FAIL;
- }
-
-
+ }
}
return POLICY_SUCCESS;
@@ -513,7 +512,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,
static void PolicySpeedModify(int speed)
{
-
for(int i=0; i<g_PolicyCtx.pSinkEndpoints->len; i++)
{
EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSinkEndpoints,EndPointPolicyInfoT,i);
@@ -545,8 +543,11 @@ static void PolicySpeedModify(int speed)
}
}
-static int RetrieveAssociatedHALAPIName(EndpointInfoT * io_pEndpointInfo)
+static int RetrieveAssociatedHALAPIName(int iAlsaCardNumber,char ** out_pDisplayName,char ** out_pHALName)
{
+ *out_pDisplayName = NULL;
+ *out_pHALName = NULL;
+
if(g_PolicyCtx.pHALList)
{
for(int i=0; i<g_PolicyCtx.pHALList->len; i++)
@@ -554,25 +555,21 @@ static int RetrieveAssociatedHALAPIName(EndpointInfoT * io_pEndpointInfo)
HalInfoT *pHalInfo = g_ptr_array_index(g_PolicyCtx.pHALList, i);
// Retrieve card number (e.g. hw:0)
int iCardNum = atoi(pHalInfo->pDevID+3);
- if (iCardNum == io_pEndpointInfo->alsaInfo.cardNum) {
- io_pEndpointInfo->gsHALAPIName=strdup(pHalInfo->pAPIName);
- io_pEndpointInfo->gsDisplayName=strdup(pHalInfo->pDisplayName);
+ if (iCardNum == iAlsaCardNumber) {
+ *out_pDisplayName = pHalInfo->pDisplayName;
+ *out_pHALName = pHalInfo->pAPIName;
return POLICY_SUCCESS;
}
}
}
- io_pEndpointInfo->gsHALAPIName=strdup(AHL_POLICY_UNDEFINED_HALNAME);
- io_pEndpointInfo->gsDisplayName=strdup(AHL_POLICY_UNDEFINED_DISPLAYNAME);
-
return POLICY_FAIL;
}
static int GetHALList(void)
{
- json_object *j_response, *j_query = NULL;
- int err;
- err = afb_service_call_sync("alsacore", "hallist", j_query, &j_response);
+ json_object *j_response = NULL, *j_query = NULL;
+ int err = afb_service_call_sync("alsacore", "hallist", j_query, &j_response);
if (err) {
AFB_ERROR("Could not retrieve list of HAL from ALSA core");
return POLICY_FAIL;
@@ -616,16 +613,14 @@ static int GetHALList(void)
//
// Policy API Functions
//
-int Policy_OpenStream(json_object *pPolicyStreamJ)
+int Policy_OpenStream(json_object *pStreamJ)
{
- StreamInfoT PolicyStream;
- EndpointInfoT EndpointInfo;
- PolicyStream.pEndpointInfo =&EndpointInfo;
+ StreamInterfaceInfoT Stream;
- int err = PolicyCtxJSONToStream(pPolicyStreamJ, &PolicyStream);
+ int err = JSONToStream(pStreamJ, &Stream);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
// Example rule -> when system is in shutdown or low power mode, no audio stream can be opened (return AHL_POLICY_REJECT)
@@ -636,26 +631,27 @@ int Policy_OpenStream(json_object *pPolicyStreamJ)
}
StreamConfigT StreamConfig;
- err = getStreamConfig(PolicyStream.pRoleName, &StreamConfig);
+ err = getStreamConfig(Stream.pRoleName, &StreamConfig);
if(err == POLICY_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
- if(PolicyStream.pEndpointInfo->deviceURIType != DEVICEURITYPE_NOT_ALSA) {
- err=PolicyGetVolume(PolicyStream.pEndpointInfo->endpointID,
- PolicyStream.pEndpointInfo->type,
- PolicyStream.pEndpointInfo->gsHALAPIName,
- PolicyStream.pEndpointInfo->pRoleName,
- PolicyStream.pEndpointInfo->deviceURIType,
- &PolicyStream.pEndpointInfo->iVolume);
+ // Volume support only possible through ALSA
+ if(Stream.endpoint.deviceURIType != DEVICEURITYPE_NOT_ALSA) {
+ err = PolicyGetVolume(Stream.endpoint.endpointID,
+ Stream.endpoint.type,
+ Stream.endpoint.gsHALAPIName,
+ Stream.endpoint.pRoleName,
+ Stream.endpoint.deviceURIType,
+ &Stream.endpoint.iVolume);
if(err == POLICY_FAIL)
{
return AHL_POLICY_REJECT;
}
}
- err = PolicyAddEndPoint(&PolicyStream);
+ err = PolicyAddEndPoint(&Stream);
if(err == POLICY_FAIL)
{
return AHL_POLICY_REJECT;
@@ -663,291 +659,298 @@ int Policy_OpenStream(json_object *pPolicyStreamJ)
return AHL_POLICY_ACCEPT;
}
-int Policy_CloseStream(json_object *pPolicyStreamJ)
+int Policy_CloseStream(json_object *pStreamJ)
{
- //TODO remove Endpoint when there is no stream
- StreamInfoT PolicyStream;
- EndpointInfoT EndpointInfo;
- PolicyStream.pEndpointInfo =&EndpointInfo;
- int err = PolicyCtxJSONToStream(pPolicyStreamJ, &PolicyStream);
+ StreamInterfaceInfoT Stream;
+ int err = JSONToStream(pStreamJ, &Stream);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
return AHL_POLICY_ACCEPT;
}
-int Policy_SetStreamState(json_object *pPolicyStreamJ)
-{
- //TODO
- // Optional: Mute endpoint before activation, unmute afterwards (after a delay?) to avoid noises
- StreamInfoT PolicyStream;
- EndpointInfoT EndpointInfo;
- PolicyStream.pEndpointInfo =&EndpointInfo;
-
+int Policy_SetStreamState(json_object *pStreamJ)
+{
+ // Optional TODO: Could mute endpoint before activation, unmute afterwards (after a delay?) to avoid noises
StreamStateT streamState = 0;
- StreamInfoT * pPolicyStream = &PolicyStream;
- int err = PolicyCtxJSONToStream(pPolicyStreamJ, pPolicyStream);
+ StreamInterfaceInfoT Stream;
+
+ int err = JSONToStream(pStreamJ, &Stream);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
- json_object *streamStateJ=NULL;
+ json_object *streamStateJ = NULL;
- if(!json_object_object_get_ex(pPolicyStreamJ, "arg_stream_state", &streamStateJ))
+ if(!json_object_object_get_ex(pStreamJ, "arg_stream_state", &streamStateJ))
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
streamState = (StreamStateT)json_object_get_int(streamStateJ);
- //Change of state
- if(pPolicyStream->streamState != streamState)
+ // Change of state
+ if(Stream.streamState != streamState)
{
//seach corresponding endpoint and gather information on it
- EndPointPolicyInfoT *pCurrEndPointPolicy = PolicySearchEndPoint(pPolicyStream->pEndpointInfo->type , pPolicyStream->pEndpointInfo->gsDeviceName);
+ EndPointPolicyInfoT *pCurrEndPointPolicy = PolicySearchEndPoint(Stream.endpoint.type , Stream.endpoint.gsDeviceName);
- switch(pPolicyStream->streamState)
+ switch(Stream.streamState)
{
case STREAM_STATE_IDLE:
switch(streamState)
{
case STREAM_STATE_RUNNING:
- err = PolicyIdleRunningTransition(pCurrEndPointPolicy, pPolicyStream);
+ err = PolicyIdleRunningTransition(pCurrEndPointPolicy, &Stream);
if(err)
{
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_START);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_START);
break;
case STREAM_STATE_PAUSED:
- err = PolicyIdleRunningTransition(pCurrEndPointPolicy, pPolicyStream);
+ err = PolicyIdleRunningTransition(pCurrEndPointPolicy, &Stream);
if(err)
{
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_PAUSE);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_PAUSE);
break;
default:
return AHL_POLICY_REJECT;
- break;
}
break;
case STREAM_STATE_RUNNING:
switch(streamState)
{
case STREAM_STATE_IDLE:
- err = PolicyRunningIdleTransition(pCurrEndPointPolicy, pPolicyStream);
+ err = PolicyRunningIdleTransition(pCurrEndPointPolicy, &Stream);
if(err)
{
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_STOP);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_STOP);
break;
case STREAM_STATE_PAUSED:
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_PAUSE);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_PAUSE);
break;
default:
return AHL_POLICY_REJECT;
- break;
}
break;
case STREAM_STATE_PAUSED:
switch(streamState)
{
case STREAM_STATE_IDLE:
- err = PolicyRunningIdleTransition(pCurrEndPointPolicy, pPolicyStream);
+ err = PolicyRunningIdleTransition(pCurrEndPointPolicy, &Stream);
if(err)
{
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_STOP);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_STOP);
break;
case STREAM_STATE_RUNNING:
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_RESUME);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_RESUME);
break;
default:
return AHL_POLICY_REJECT;
- break;
}
break;
default:
return AHL_POLICY_REJECT;
- break;
}
}
return AHL_POLICY_ACCEPT;
}
-int Policy_SetStreamMute(json_object *pPolicyStreamJ)
+int Policy_SetStreamMute(json_object *pStreamJ)
{
+ // Note: stream mute currently implemented directly using ALSA volume. It should later be implemented with a distinct mute switch control instead
StreamMuteT streamMute = 0;
- StreamInfoT PolicyStream;
- EndpointInfoT EndpointInfo;
- PolicyStream.pEndpointInfo =&EndpointInfo;
- StreamInfoT * pPolicyStream = &PolicyStream;
+ StreamInterfaceInfoT Stream;
- int err = PolicyCtxJSONToStream(pPolicyStreamJ, pPolicyStream);
+ int err = JSONToStream(pStreamJ, &Stream);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
json_object *streamMuteJ=NULL;
- if(!json_object_object_get_ex(pPolicyStreamJ, "mute_state", &streamMuteJ))
+ if(!json_object_object_get_ex(pStreamJ, "mute_state", &streamMuteJ))
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
streamMute = (StreamMuteT)json_object_get_int(streamMuteJ);
- if(streamMute != pPolicyStream->streamMute)
+ if(streamMute != Stream.streamMute)
{
if(streamMute == STREAM_MUTED)
{
-
- err= PolicySetVolume(pPolicyStream->pEndpointInfo->endpointID,
- pPolicyStream->pEndpointInfo->type,
- pPolicyStream->pEndpointInfo->gsHALAPIName,
- pPolicyStream->pRoleName,
- pPolicyStream->pEndpointInfo->deviceURIType,
- 0,
- true);
+ err = PolicySetVolume(Stream.endpoint.endpointID,
+ Stream.endpoint.type,
+ Stream.endpoint.gsHALAPIName,
+ Stream.pRoleName,
+ Stream.endpoint.deviceURIType,
+ 0, // mute volume
+ true); // no ramp and no volume event
if(err)
{
- AFB_ERROR("StreamID:%i Set Volume return with errorcode%i",pPolicyStream->streamID, err);
+ AFB_ERROR("StreamID:%i Set Volume return with errorcode%i",Stream.streamID, err);
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_MUTED);
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_MUTED);
}
else
{
- err= PolicySetVolume(pPolicyStream->pEndpointInfo->endpointID,
- pPolicyStream->pEndpointInfo->type,
- pPolicyStream->pEndpointInfo->gsHALAPIName,
- pPolicyStream->pRoleName,
- pPolicyStream->pEndpointInfo->deviceURIType,
- pPolicyStream->pEndpointInfo->iVolume,
- true);
+ err = PolicySetVolume(Stream.endpoint.endpointID,
+ Stream.endpoint.type,
+ Stream.endpoint.gsHALAPIName,
+ Stream.pRoleName,
+ Stream.endpoint.deviceURIType,
+ Stream.endpoint.iVolume, // restore volume
+ true); // no ramp and no volume event
if(err)
{
- AFB_ERROR("Endpoint:%i Set Volume return with errorcode%i",pPolicyStream->streamID, err);
+ AFB_ERROR("Endpoint:%i Set Volume return with errorcode%i",Stream.streamID, err);
return AHL_POLICY_REJECT;
}
- PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_UNMUTED);
-
+ PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_UNMUTED);
}
-
- pPolicyStream->streamMute = streamMute;
}
return AHL_POLICY_ACCEPT;
}
-int Policy_SetVolume(json_object *pPolicyEndpointJ)
+int Policy_SetVolume(json_object *pEndpointJ)
{
char *volumeStr = NULL;
- EndpointInfoT EndpointInfo;
+ EndPointInterfaceInfoT Endpoint;
- int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo);
+ int err = JSONToEndpoint(pEndpointJ, &Endpoint);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
- json_object *volumeJ=NULL;
-
- if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_volume", &volumeJ))
+ json_object *volumeJ = NULL;
+ if(!json_object_object_get_ex(pEndpointJ, "arg_volume", &volumeJ))
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
volumeStr = (char*)json_object_get_string(volumeJ);
- // TODO: Parse volume string to support increment/absolute/percent notation (or delegate to action / policy layer to interpret)
+ // TODO: Parse volume string to support increment/absolute/percent notation
int vol = atoi(volumeStr);
- //Set the volume
- err= PolicySetVolume(EndpointInfo.endpointID,
- EndpointInfo.type,
- EndpointInfo.gsHALAPIName,
- EndpointInfo.pRoleName,
- EndpointInfo.deviceURIType,
- vol,
- false);
+ // Set the volume
+ err = PolicySetVolume(Endpoint.endpointID,
+ Endpoint.type,
+ Endpoint.gsHALAPIName,
+ Endpoint.pRoleName,
+ Endpoint.deviceURIType,
+ vol,
+ false); // Volume ramp and send events
if (err)
{
- AFB_ERROR("Set Volume return with errorcode%i", err);
+ AFB_ERROR("Set Volume return with errorcode %i", err);
return AHL_POLICY_REJECT;
}
return AHL_POLICY_ACCEPT;
}
-int Policy_SetProperty(json_object *pPolicyEndpointJ)
+int Policy_SetProperty(json_object *pEndpointJ)
{
-
char *propertyName = NULL;
- EndpointInfoT EndpointInfo;
+ EndPointInterfaceInfoT Endpoint;
- int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo);
+ int err = JSONToEndpoint(pEndpointJ, &Endpoint);
if(err == AHL_POLICY_UTIL_FAIL)
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
- json_object *propertyNameJ=NULL;
-
- if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_property_name", &propertyNameJ))
+ json_object *propertyNameJ = NULL;
+ if(!json_object_object_get_ex(pEndpointJ, "arg_property_name", &propertyNameJ))
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
propertyName = (char*)json_object_get_string(propertyNameJ);
- json_object *propValueJ;
- if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_property_value", &propValueJ))
+ json_object *propValueJ = NULL;
+ if(!json_object_object_get_ex(pEndpointJ, "arg_property_value", &propValueJ))
{
- return AHL_POLICY_ACCEPT;
+ return AHL_POLICY_REJECT;
}
+ json_type currentTypeJ = json_object_get_type(propValueJ);
- gpointer *key_value=NULL;
-
- key_value = g_hash_table_lookup(EndpointInfo.pPropTable,propertyName);
- if(key_value == NULL)
+ json_object *propArray = NULL;
+ if(!json_object_object_get_ex(pEndpointJ, "properties", &propArray))
{
- AFB_ERROR("Can't find property %s, request will be rejected", propertyName);
- return AHL_POLICY_REJECT;
+ return AHL_POLICY_REJECT;
}
- //Get JsonObjectype
- json_type currentjType = json_object_get_type((json_object*)key_value);
- json_type newjType = json_object_get_type(propValueJ);
-
- //Apply policy on set property if needed here
- //Here we only validate that the type is the same
- if(currentjType != newjType)
+ int iPropArrayLen = json_object_array_length(propArray);
+ int foundProperty = 0;
+
+ for (int i = 0; i < iPropArrayLen; i++)
{
- AFB_ERROR("Property Value Type is wrong");
- return AHL_POLICY_REJECT;
+ // get the i-th object in medi_array
+ json_object *propElementJ = json_object_array_get_idx(propArray, i);
+ if(propElementJ)
+ {
+ json_object *propElementNameJ=NULL;
+ if(json_object_object_get_ex(propElementJ, "property_name", &propElementNameJ))
+ {
+ char *propElementName = (char*)json_object_get_string(propElementNameJ);
+ if(strcasecmp(propElementName,propertyName)==0)
+ {
+ json_object *propElementValueJ=NULL;
+ if(!json_object_object_get_ex(propElementJ, "property_value", &propElementValueJ))
+ {
+ json_type elementTypeJ = json_object_get_type(propElementValueJ);
+
+ // Apply policy on set property if needed here
+ // Here we only validate that the type is the same
+ if(currentTypeJ != elementTypeJ)
+ {
+ AFB_ERROR("Property Value Type is wrong");
+ return AHL_POLICY_REJECT;
+ }
+ foundProperty = 1;
+ break;
+ }
+ }
+ }
+ }
}
+ if(foundProperty== 0)
+ {
+ AFB_ERROR("Can't find property %s, request will be rejected", propertyName);
+ return AHL_POLICY_REJECT;
+ }
- //Create a new Json Object
+ // Create a new Json Object
json_object *pEventDataJ = NULL;
err = wrap_json_pack(&pEventDataJ,"{s:s,s:i,s:i,s:s,s:o,s:s}",
"event_name", AHL_ENDPOINT_PROPERTY_EVENT,
- "endpoint_id", EndpointInfo.endpointID,
- "endpoint_type", EndpointInfo.type,
+ "endpoint_id", Endpoint.endpointID,
+ "endpoint_type", Endpoint.type,
"property_name", propertyName,
"value",propValueJ,
- "audio_role", EndpointInfo.pRoleName);
+ "audio_role", Endpoint.pRoleName);
if(err)
{
AFB_ERROR("Unable to pack property event");
return AHL_POLICY_REJECT;
}
- //Raise Event to update HLB
+
+ // Raise Event to update HLB
audiohlapi_raise_event(pEventDataJ);
return AHL_POLICY_ACCEPT;
@@ -978,94 +981,137 @@ int Policy_PostAction(json_object *pPolicyActionJ)
AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
return AHL_POLICY_REJECT;
}
+
audiohlapi_raise_event(pEventDataJ);
return AHL_POLICY_ACCEPT;
}
-int Policy_Endpoint_Init(json_object *pPolicyEndpointJ)
+int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolicyEndpointJ)
{
- EndpointInfoT EndpointInfo;
-
- int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo);
- if(err == AHL_POLICY_UTIL_FAIL)
- {
- return AHL_POLICY_REJECT;
+ endpointID_t endpointID = AHL_UNDEFINED;
+ EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
+ DeviceURITypeT deviceURIType = DEVICEURITYPE_MAXVALUE;
+ int iAllocString = 0;
+ char * pRoleName = NULL;
+ int iAlsaCardNumber = AHL_UNDEFINED;
+ char * pDeviceName = NULL;
+ int err = wrap_json_unpack(pInPolicyEndpointJ,"{s:i,s:i,s:i,s:s,s:i,s:s}",
+ "endpoint_id",&endpointID,
+ "endpoint_type",&endpointType,
+ "device_uri_type",&deviceURIType,
+ "audio_role",&pRoleName,
+ "alsa_cardNum", &iAlsaCardNumber,
+ "device_name", &pDeviceName );
+ if (err) {
+ AFB_ERROR("Unable to unpack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ goto OnError;
}
- if (EndpointInfo.deviceURIType != DEVICEURITYPE_NOT_ALSA) {
+ StreamConfigT StreamConfig;
+ getStreamConfig(pRoleName, &StreamConfig);
+
+ char * pDisplayName = NULL;
+ char * pHALName = NULL;
+ if (deviceURIType != DEVICEURITYPE_NOT_ALSA) {
// Update Hal Name
- err = RetrieveAssociatedHALAPIName(&EndpointInfo);
+ err = RetrieveAssociatedHALAPIName(iAlsaCardNumber,&pDisplayName,&pHALName);
if (err) {
- AFB_ERROR("HAL not found for Device %s", EndpointInfo.gsDeviceName);
- return AHL_POLICY_REJECT;
+ AFB_WARNING("HAL not found for device %s", pDeviceName);
+ pDisplayName = g_strdup(AHL_POLICY_UNDEFINED_DISPLAYNAME);
+ pHALName = g_strdup(AHL_POLICY_UNDEFINED_HALNAME);
+ iAllocString = 1;
}
-
- //Set Init Volume
- StreamConfigT StreamConfig;
- getStreamConfig(EndpointInfo.pRoleName, &StreamConfig);
- err = PolicySetVolume(EndpointInfo.endpointID,
- EndpointInfo.type,
- EndpointInfo.gsHALAPIName,
- EndpointInfo.pRoleName,
- EndpointInfo.deviceURIType,
- StreamConfig.iVolumeInit,
- false);
- if(err) {
- return AHL_POLICY_REJECT;
+ else
+ {
+ // Set initial Volume
+ err = PolicySetVolume(endpointID,
+ endpointType,
+ pHALName,
+ pRoleName,
+ deviceURIType,
+ StreamConfig.iVolumeInit,
+ true); // Do not raise event and no volume ramp
+ if(err) {
+ goto OnError;
+ }
}
}
-
- // Test example
- Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_LOW,3);
- Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_MID,0);
- Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_HIGH,6);
- Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_BALANCE,0);
- Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_FADE,30);
- Add_Endpoint_Property_String(&EndpointInfo,"preset_name","flat");
-
-
- gpointer *key_value = g_hash_table_lookup(EndpointInfo.pPropTable,AHL_PROPERTY_BALANCE);
- if(key_value == NULL)
- {
- AFB_ERROR("Can't find property %s, request will be rejected", AHL_PROPERTY_BALANCE);
- return AHL_POLICY_REJECT;
+ else {
+ // Set display / HAL for non ALSA devices (default)
+ pDisplayName = g_strdup(AHL_POLICY_UNDEFINED_DISPLAYNAME);
+ pHALName = g_strdup(AHL_POLICY_UNDEFINED_HALNAME);
+ iAllocString = 1;
}
- //Create a new Json Object
- json_object *pNewPolicyEndpointJ = NULL;
- err = PolicyEndpointStructToJSON(&EndpointInfo, &pNewPolicyEndpointJ);
- if (err == AHL_POLICY_UTIL_FAIL)
- {
- return AHL_POLICY_REJECT;
- }
- json_object *paramJ= json_object_new_string(AHL_ENDPOINT_INIT_EVENT);
- json_object_object_add(pNewPolicyEndpointJ, "event_name", paramJ);
+ // Populate special device property (TODO: Should be obtained from HAL)
+ // if (strcasecmp(gsHALAPIName,"Device")==0)
+ // {
+ // Create json object for PropTable
+ json_object *pPropTableJ = json_object_new_array();
+ Add_Endpoint_Property_Int(pPropTableJ,AHL_PROPERTY_EQ_LOW,3);
+ Add_Endpoint_Property_Int(pPropTableJ,AHL_PROPERTY_EQ_MID,0);
+ Add_Endpoint_Property_Int(pPropTableJ,AHL_PROPERTY_EQ_HIGH,6);
+ Add_Endpoint_Property_Int(pPropTableJ,AHL_PROPERTY_BALANCE,0);
+ Add_Endpoint_Property_Int(pPropTableJ,AHL_PROPERTY_FADE,30);
+ Add_Endpoint_Property_String(pPropTableJ,"preset_name","flat");
+ // }
+
+ err = wrap_json_pack(pOutPolicyEndpointJ,"{s:i,s:s,s:s,s:o}",
+ "init_volume",StreamConfig.iVolumeInit,
+ "display_name",pDisplayName,
+ "hal_name",pHALName,
+ "property_table",pPropTableJ
+ );
+ if (err) {
+ AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ goto OnError;
+ }
+
+ // TODO: Future policy binding to return request response with pOutPolicyEndpointJ (instead of output argument)
+ return AHL_POLICY_ACCEPT; // No errors
- //Raise Event to update HLB
- audiohlapi_raise_event(pNewPolicyEndpointJ);
+OnError:
+ if (iAllocString) {
+ g_free(pDisplayName);
+ g_free(pHALName);
+ }
+ return AHL_POLICY_REJECT;
- return AHL_POLICY_ACCEPT; // No errors
}
int Policy_Init()
{
+ // Start fresh
+ memset(&g_PolicyCtx,0,sizeof(g_PolicyCtx));
+
// Initialize Ressources
- g_PolicyCtx.pSourceEndpoints =g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT));
+ g_PolicyCtx.pSourceEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT));
g_PolicyCtx.pSinkEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT));
g_PolicyCtx.pHALList = g_ptr_array_new_with_free_func(g_free);
- //Get HalList
+ //Require AlsaCore Dependency
+ int err = afb_daemon_require_api_v2(AHL_POLICY_ALSA_API,1) ;
+ if( err != 0 )
+ {
+ AFB_ERROR("Audio Policy could not set dependency on alsacore API");
+ return AHL_POLICY_REJECT;
+ }
+
+ // Get HalList
GetHALList();
- //Set System Normal for now, this should be set by an event
- //TODO: Receive event from low level
+ // TODO: Register events from low level / HAL for dynamic changes
+
+ // Set System Normal for now, this should be set by an event
g_PolicyCtx.systemState = SYSTEM_NORMAL;
- //register audio backend events
- //This is to simulate can bus, only used for demo
- json_object *queryurl, *responseJ, *eventsJ;
-
+
+
+#ifdef AK_POLICY_DEMO
+ // Register audio backend events (TODO: should instead do this with signal composer with appropriate dependency)
+ // This is to simulate can bus, only used for demo
+ json_object *queryurl = NULL, *responseJ = NULL, *eventsJ = NULL;
eventsJ = json_object_new_array();
json_object_array_add(eventsJ, json_object_new_string("audiod_system_event"));
queryurl = json_object_new_object();
@@ -1075,12 +1121,15 @@ int Policy_Init()
AFB_ERROR("Fail subscribing to Audio Backend System events");
return AHL_POLICY_REJECT;
}
+#endif
+
+
return AHL_POLICY_ACCEPT;
}
void Policy_Term()
{
- //Free Ressources
+ // Free Ressources
if (g_PolicyCtx.pHALList) {
g_ptr_array_free(g_PolicyCtx.pHALList,TRUE);
g_PolicyCtx.pHALList = NULL;
@@ -1106,6 +1155,7 @@ void Policy_Term()
g_PolicyCtx.pSinkEndpoints = NULL;
}
+// For demo purpose only, should be listening to signal composer / CAN events instead
void Policy_OnEvent(const char *evtname, json_object *eventJ)
{
AFB_DEBUG("Policy received event %s", evtname);
@@ -1129,7 +1179,7 @@ void Policy_OnEvent(const char *evtname, json_object *eventJ)
AFB_WARNING("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(event_parameter));
return;
}
- //When speed change Modify volume on Endpoint where entertainment change
+ // When speed change Modify volume on Endpoint where entertainment change
PolicySpeedModify(speed);
}
}
diff --git a/ahl-policy/ahl-policy.h b/ahl-policy/ahl-policy.h
index 942055a..0200973 100644
--- a/ahl-policy/ahl-policy.h
+++ b/ahl-policy/ahl-policy.h
@@ -16,6 +16,7 @@
#ifndef AHL_POLICY_INCLUDE
#define AHL_POLICY_INCLUDE
+
#include "ahl-policy-utils.h"
#ifndef AHL_DISCONNECT_POLICY
@@ -27,19 +28,22 @@
#define AHL_POLICY_UNDEFINED_HALNAME "UNDEFINED"
#define AHL_POLICY_UNDEFINED_DISPLAYNAME "DeviceNotFound"
+#define AHL_POLICY_ALSA_API "alsacore"
-int Policy_Endpoint_Init(json_object *pPolicyEndpointJ);
-int Policy_OpenStream(json_object *pPolicyStreamJ);
-int Policy_CloseStream(json_object *pPolicyStreamJ);
-int Policy_SetStreamState(json_object *pPolicyStreamJ);
-int Policy_SetStreamMute(json_object *pPolicyStreamJ);
-int Policy_PostAction(json_object *pPolicyActionJ);
-int Policy_SetVolume(json_object *pPolicyEndpointJ);
-int Policy_SetProperty(json_object *pPolicyEndpointJ);
+int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolicyEndpointJ);
+int Policy_OpenStream(json_object *pStreamJ);
+int Policy_CloseStream(json_object *pStreamJ);
+int Policy_SetStreamState(json_object *pStreamJ);
+int Policy_SetStreamMute(json_object *pStreamJ);
+int Policy_PostAction(json_object *pActionJ);
+int Policy_SetVolume(json_object *pEndpointJ);
+int Policy_SetProperty(json_object *pEndpointJ);
int Policy_Init();
void Policy_Term();
void Policy_OnEvent(const char *evtname, json_object *eventJ);
+// TODO: To be replaced by AGL events once policy is isolated in its own binding
extern void audiohlapi_raise_event(json_object * pEventDataJ);
+
#endif // AHL_DISCONNECT_POLICY
#endif // AHL_POLICY_INCLUDE \ No newline at end of file
diff --git a/ahl-utilities/ahl-policy-utils.c b/ahl-utilities/ahl-policy-utils.c
index 60ddd36..195c591 100644..100755
--- a/ahl-utilities/ahl-policy-utils.c
+++ b/ahl-utilities/ahl-policy-utils.c
@@ -14,223 +14,168 @@
* limitations under the License.
*/
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
#include "ahl-policy-utils.h"
#include "wrap-json.h"
#include <json-c/json.h>
-#include <glib.h>
-void Add_Endpoint_Property_Double( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, double in_dPropertyValue)
+void Add_Endpoint_Property_Double( json_object * io_pPropertyArray, char * in_pPropertyName, double in_dPropertyValue)
{
- json_object * propValueJ = json_object_new_double(in_dPropertyValue);
- g_hash_table_insert(io_pEndpointInfo->pPropTable, in_pPropertyName, propValueJ);
+ json_object * pPropertyJ = NULL;
+ wrap_json_pack(&pPropertyJ, "{s:s,s:o}",
+ "property_name", in_pPropertyName,
+ "property_value", json_object_new_double(in_dPropertyValue)
+ );
+ json_object_array_add(io_pPropertyArray, pPropertyJ);
}
-
-void Add_Endpoint_Property_Int( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, int in_iPropertyValue)
+void Add_Endpoint_Property_Int( json_object * io_pPropertyArray, char * in_pPropertyName, int in_iPropertyValue)
{
- json_object * propValueJ = json_object_new_int(in_iPropertyValue);
- g_hash_table_insert(io_pEndpointInfo->pPropTable, in_pPropertyName, propValueJ);
+ json_object * pPropertyJ = NULL;
+ wrap_json_pack(&pPropertyJ, "{s:s,s:o}",
+ "property_name", in_pPropertyName,
+ "property_value", json_object_new_int(in_iPropertyValue)
+ );
+ json_object_array_add(io_pPropertyArray, pPropertyJ);
}
-void Add_Endpoint_Property_String( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, const char * in_pPropertyValue)
+void Add_Endpoint_Property_String( json_object * io_pPropertyArray, char * in_pPropertyName, const char * in_pPropertyValue)
{
- json_object * propValueJ = json_object_new_string(in_pPropertyValue);
- g_hash_table_insert(io_pEndpointInfo->pPropTable, in_pPropertyName, propValueJ);
+ json_object * pPropertyJ = NULL;
+ wrap_json_pack(&pPropertyJ, "{s:s,s:o}",
+ "property_name", in_pPropertyName,
+ "property_value", json_object_new_string(in_pPropertyValue)
+ );
+ json_object_array_add(io_pPropertyArray, pPropertyJ);
}
-int PolicyEndpointStructToJSON(EndpointInfoT * pEndpointInfo, json_object **ppPolicyEndpointJ)
+int EndpointToJSON(EndPointInterfaceInfoT * pEndpoint, json_object **ppEndpointJ)
{
- if(pEndpointInfo == NULL || pEndpointInfo->pPropTable == NULL)
+ if(ppEndpointJ == NULL || pEndpoint == NULL)
{
- AFB_ERROR("Invalid PolicyEndpointStructToJSON arguments");
+ AFB_ERROR("Invalid EndpointToJSON arguments");
return AHL_POLICY_UTIL_FAIL;
}
-
- //Create json object for PropTable
- json_object *pPropTableJ = json_object_new_array();
- if(pEndpointInfo->pPropTable) {
- GHashTableIter iter;
- gpointer key, value;
- g_hash_table_iter_init (&iter, pEndpointInfo->pPropTable);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- json_object *pPropertyJ = NULL;
- int error=wrap_json_pack(&pPropertyJ, "{s:s,s:o}",
- "property_name", (char*)key,
- "property_value", value
- );
- if(error)
- {
- AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(error));
- return AHL_POLICY_UTIL_FAIL;
- }
- json_object_array_add(pPropTableJ, pPropertyJ);
- }
- AFB_DEBUG("json object query=%s", json_object_get_string(pPropTableJ));
- }
-
- //Create json object for Endpoint
- int err= wrap_json_pack(ppPolicyEndpointJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:o}",
- "endpoint_id", pEndpointInfo->endpointID,
- "endpoint_type", pEndpointInfo->type,
- "device_name", pEndpointInfo->gsDeviceName,
- "display_name", pEndpointInfo->gsDisplayName,
- "device_uri", pEndpointInfo->gsDeviceURI,
- "device_domain", pEndpointInfo->gsDeviceDomain,
- "audio_role",pEndpointInfo->pRoleName,
- "device_uri_type", pEndpointInfo->deviceURIType,
- "hal_api_name", pEndpointInfo->gsHALAPIName,
- "alsa_cardNum", pEndpointInfo->alsaInfo.cardNum,
- "alsa_deviceNum", pEndpointInfo->alsaInfo.deviceNum,
- "alsa_subDeviceNum", pEndpointInfo->alsaInfo.subDeviceNum,
- "format_samplerate", pEndpointInfo->format.sampleRate,
- "format_numchannels", pEndpointInfo->format.numChannels,
- "format_sampletype",pEndpointInfo->format.sampleType,
- "volume", pEndpointInfo->iVolume,
- "property_table", pPropTableJ
+
+ // Create json object for Endpoint
+ int err = wrap_json_pack(ppEndpointJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s?o}",
+ "endpoint_id", pEndpoint->endpointID,
+ "endpoint_type", pEndpoint->type,
+ "device_name", pEndpoint->gsDeviceName,
+ "display_name", pEndpoint->gsDisplayName,
+ "device_uri", pEndpoint->gsDeviceURI,
+ "device_domain", pEndpoint->gsDeviceDomain,
+ "audio_role",pEndpoint->pRoleName,
+ "device_uri_type", pEndpoint->deviceURIType,
+ "hal_api_name", pEndpoint->gsHALAPIName,
+ "alsa_cardNum", pEndpoint->alsaInfo.cardNum,
+ "alsa_deviceNum", pEndpoint->alsaInfo.deviceNum,
+ "alsa_subDeviceNum", pEndpoint->alsaInfo.subDeviceNum,
+ "format_samplerate", pEndpoint->format.sampleRate,
+ "format_numchannels", pEndpoint->format.numChannels,
+ "format_sampletype",pEndpoint->format.sampleType,
+ "volume", pEndpoint->iVolume,
+ "property_table", pEndpoint->pPropTableJ
);
if (err) {
AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
return AHL_POLICY_UTIL_FAIL;
}
- AFB_DEBUG("JSON endpoint information=%s", json_object_get_string(*ppPolicyEndpointJ));
+ AFB_DEBUG("JSON endpoint information=%s", json_object_get_string(*ppEndpointJ));
return AHL_POLICY_UTIL_SUCCESS;
}
-int PolicyStreamStructToJSON(StreamInfoT * pPolicyStream, json_object **ppPolicyStreamJ)
+int StreamToJSON(StreamInterfaceInfoT * pStream, json_object **ppStreamJ)
{
- if(pPolicyStream == NULL)
+ if(pStream == NULL)
{
- AFB_ERROR("Invalid arguments to PolicyStreamStructToJSON");
+ AFB_ERROR("Invalid arguments to StreamToJSON, stream structure is NULL");
return AHL_POLICY_UTIL_FAIL;
}
- json_object * pEndpointJ = NULL;
- int iRet = PolicyEndpointStructToJSON(pPolicyStream->pEndpointInfo, &pEndpointJ);
- if (iRet) {
- return iRet;
+ json_object *EndpointJ = NULL;
+ int err = EndpointToJSON(&pStream->endpoint, &EndpointJ);
+ if (err) {
+ AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ return AHL_POLICY_UTIL_FAIL;
}
- //Create json object for stream
- int err = wrap_json_pack(ppPolicyStreamJ, "{s:i,s:i,s:i,s:I,s:i,s:s,s:i,s:i,s:o}",
- "stream_id", pPolicyStream->streamID,
- "stream_state", pPolicyStream->streamState,
- "stream_mute", pPolicyStream->streamMute,
- "stream_state_event", &pPolicyStream->streamStateEvent,
- "endpoint_sel_mod", pPolicyStream->endpointSelMode,
- "role_name", pPolicyStream->pRoleName,
- "priority", pPolicyStream->iPriority,
- "interrupt_behavior", pPolicyStream->eInterruptBehavior,
- "endpoint_info", pEndpointJ
+ // Create json object for stream
+ err = wrap_json_pack(ppStreamJ, "{s:i,s:i,s:i,s:s,s:i,s:i,s:o}",
+ "stream_id", pStream->streamID,
+ "stream_state", pStream->streamState,
+ "stream_mute", pStream->streamMute,
+ "role_name", pStream->pRoleName,
+ "priority", pStream->iPriority,
+ "interrupt_behavior", pStream->eInterruptBehavior,
+ "endpoint_info", EndpointJ
);
if (err) {
- AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err));
+ AFB_ERROR("Unable to pack JSON Stream, =%s", wrap_json_get_error_string(err));
return AHL_POLICY_UTIL_FAIL;
}
- AFB_DEBUG("JSON stream information=%s", json_object_get_string(*ppPolicyStreamJ));
+ AFB_DEBUG("JSON stream information=%s", json_object_get_string(*ppStreamJ));
return AHL_POLICY_UTIL_SUCCESS;
}
-int PolicyCtxJSONToEndpoint(json_object *pEndpointJ, EndpointInfoT * pEndpointInfo)
+//pEndpointInterfaceInfo must be pre-allocated by the caller
+int JSONToEndpoint(json_object *pEndpointJ, EndPointInterfaceInfoT *pEndpoint)
{
- if(pEndpointJ == NULL || pEndpointInfo == NULL /*|| pEndpointInfo->pPropTable == NULL */ )
+ if(pEndpointJ == NULL || pEndpoint == NULL)
{
- AFB_ERROR("Invalid arguments for PolicyCtxJSONToEndpoint");
+ AFB_ERROR("Invalid arguments for JSONToEndpoint");
return AHL_POLICY_UTIL_FAIL;
}
//Unpack Endpoint
- json_object *pPropTableJ = NULL;
- int err = wrap_json_unpack(pEndpointJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:o}",
- "endpoint_id", &pEndpointInfo->endpointID,
- "endpoint_type", &pEndpointInfo->type,
- "device_name", &pEndpointInfo->gsDeviceName,
- "display_name", &pEndpointInfo->gsDisplayName,
- "device_uri", &pEndpointInfo->gsDeviceURI,
- "device_domain", &pEndpointInfo->gsDeviceDomain,
- "audio_role", &pEndpointInfo->pRoleName,
- "device_uri_type", &pEndpointInfo->deviceURIType,
- "hal_api_name", &pEndpointInfo->gsHALAPIName,
- "alsa_cardNum", &pEndpointInfo->alsaInfo.cardNum,
- "alsa_deviceNum", &pEndpointInfo->alsaInfo.deviceNum,
- "alsa_subDeviceNum", &pEndpointInfo->alsaInfo.subDeviceNum,
- "format_samplerate", &pEndpointInfo->format.sampleRate,
- "format_numchannels", &pEndpointInfo->format.numChannels,
- "format_sampletype",&pEndpointInfo->format.sampleType,
- "volume", &pEndpointInfo->iVolume,
- "property_table", &pPropTableJ
+ int err = wrap_json_unpack(pEndpointJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s?o}",
+ "endpoint_id", &pEndpoint->endpointID,
+ "endpoint_type", &pEndpoint->type,
+ "device_name", &pEndpoint->gsDeviceName,
+ "display_name", &pEndpoint->gsDisplayName,
+ "device_uri", &pEndpoint->gsDeviceURI,
+ "device_domain", &pEndpoint->gsDeviceDomain,
+ "audio_role", &pEndpoint->pRoleName,
+ "device_uri_type", &pEndpoint->deviceURIType,
+ "hal_api_name", &pEndpoint->gsHALAPIName,
+ "alsa_cardNum", &pEndpoint->alsaInfo.cardNum,
+ "alsa_deviceNum", &pEndpoint->alsaInfo.deviceNum,
+ "alsa_subDeviceNum", &pEndpoint->alsaInfo.subDeviceNum,
+ "format_samplerate", &pEndpoint->format.sampleRate,
+ "format_numchannels", &pEndpoint->format.numChannels,
+ "format_sampletype",&pEndpoint->format.sampleType,
+ "volume", &pEndpoint->iVolume,
+ "property_table", &pEndpoint->pPropTableJ
);
if (err) {
AFB_ERROR("Unable to unpack JSON endpoint, =%s", wrap_json_get_error_string(err));
return AHL_POLICY_UTIL_FAIL;
}
-
- // Unpack prop table
- if(pPropTableJ)
- {
- pEndpointInfo->pPropTable = g_hash_table_new(g_str_hash, g_str_equal);
-
- int nbProperties = json_object_array_length(pPropTableJ);
- for(int i=0; i<nbProperties; i++)
- {
- json_object * propJ = json_object_array_get_idx(pPropTableJ,i);
- if (propJ) {
- char * pPropertyName = NULL;
- json_object * pPropertyValueJ = NULL;
-
- int err=wrap_json_unpack(propJ, "{s:s,s:o}",
- "property_name", &pPropertyName,
- "property_value", &pPropertyValueJ);
- if (err) {
- AFB_ERROR("Unable to unpack JSON endpoint, = %s", wrap_json_get_error_string(err));
- return AHL_POLICY_UTIL_FAIL;
- }
-
- // Object type detection for property value (string = state, numeric = property)
- json_type jType = json_object_get_type(pPropertyValueJ);
- switch (jType) {
- case json_type_double:
- Add_Endpoint_Property_Double(pEndpointInfo,pPropertyName,json_object_get_double(pPropertyValueJ));
- break;
- case json_type_int:
- Add_Endpoint_Property_Int(pEndpointInfo,pPropertyName,json_object_get_int(pPropertyValueJ));
- break;
- case json_type_string:
- Add_Endpoint_Property_String(pEndpointInfo,pPropertyName,json_object_get_string(pPropertyValueJ));
- break;
- default:
- AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(pPropertyValueJ));
- return AHL_POLICY_UTIL_FAIL;
- }
- }
- }
- }
-
return AHL_POLICY_UTIL_SUCCESS;
}
-int PolicyCtxJSONToStream(json_object *pStreamJ, StreamInfoT * pPolicyStream)
+int JSONToStream(json_object *pStreamJ, StreamInterfaceInfoT * pStream)
{
- if(pStreamJ == NULL || pPolicyStream == NULL)
+ if(pStreamJ == NULL || pStream == NULL)
{
- AFB_ERROR("Invalid arguments for PolicyCtxJSONToStream");
+ AFB_ERROR("Invalid arguments for InterfaceCtxJSONToStream");
return AHL_POLICY_UTIL_FAIL;
}
//Unpack StreamInfo
json_object *pEndpointJ = NULL;
AFB_WARNING("json object query=%s", json_object_get_string(pStreamJ));
- int err=wrap_json_unpack(pStreamJ, "{s:i,s:i,s:i,s:I,s:i,s:s,s:i,s:i,s:o}",
- "stream_id", &pPolicyStream->streamID,
- "stream_state", &pPolicyStream->streamState,
- "stream_mute", &pPolicyStream->streamMute,
- "stream_state_event", &pPolicyStream->streamStateEvent,
- "endpoint_sel_mod", &pPolicyStream->endpointSelMode,
- "role_name", &pPolicyStream->pRoleName,
- "priority", &pPolicyStream->iPriority,
- "interrupt_behavior", &pPolicyStream->eInterruptBehavior,
+ int err = wrap_json_unpack(pStreamJ, "{s:i,s:i,s:i,s:s,s:i,s:i,s:o}",
+ "stream_id", &pStream->streamID,
+ "stream_state", &pStream->streamState,
+ "stream_mute", &pStream->streamMute,
+ "role_name", &pStream->pRoleName,
+ "priority", &pStream->iPriority,
+ "interrupt_behavior", &pStream->eInterruptBehavior,
"endpoint_info", &pEndpointJ
);
@@ -239,9 +184,9 @@ int PolicyCtxJSONToStream(json_object *pStreamJ, StreamInfoT * pPolicyStream)
return AHL_POLICY_UTIL_FAIL;
}
- int iRet = PolicyCtxJSONToEndpoint(pEndpointJ,pPolicyStream->pEndpointInfo);
- if (iRet) {
- return iRet;
+ err = JSONToEndpoint(pEndpointJ,&pStream->endpoint);
+ if (err) {
+ return AHL_POLICY_UTIL_FAIL;
}
return AHL_POLICY_UTIL_SUCCESS;
}
diff --git a/ahl-utilities/ahl-policy-utils.h b/ahl-utilities/ahl-policy-utils.h
index 6adfa4e..3c20020 100644..100755
--- a/ahl-utilities/ahl-policy-utils.h
+++ b/ahl-utilities/ahl-policy-utils.h
@@ -17,16 +17,15 @@
#ifndef AHL_POLICY_UTILS_INCLUDE
#define AHL_POLICY_UTILS_INCLUDE
-#define AFB_BINDING_VERSION 2
#include <json-c/json.h>
-#include <afb/afb-binding.h>
-#include <glib.h>
#define AHL_POLICY_ACCEPT 1
#define AHL_POLICY_REJECT 0
#define AHL_POLICY_UTIL_SUCCESS 0
#define AHL_POLICY_UTIL_FAIL 1
+#define AHL_UNDEFINED -1
+
typedef int endpointID_t;
typedef int streamID_t;
@@ -118,60 +117,38 @@ typedef enum EndpointSelectionMode {
ENDPOINTSELMODEMAXVALUE, // Enum count, keep at the end
} EndpointSelectionModeT;
-typedef struct EndpointInfo
-{
+typedef struct EndPointInterfaceInfo {
endpointID_t endpointID; // Unique endpoint ID (per type)
EndpointTypeT type; // Source or sink device
char * gsDeviceName; // Unique device card name
char * gsDisplayName; // Application display name
char * gsDeviceURI; // Associated URI
char * gsDeviceDomain; // Device URI domain (e.g. alsa or pulse)
- char * pRoleName; // Role assigned to this endpoint
DeviceURITypeT deviceURIType; // Device URI type (includes audio domain information)
char * gsHALAPIName; // HAL associated with the device (for volume control)
+ char * pRoleName; // Role string identifier (from role config but could be programatically overriden later)
AlsaDeviceInfoT alsaInfo; // ALSA specific device information
AudioFormatT format; // Preferred audio format supported (later could be array of supported formats)
- int iVolume; // Storage for current endpoint volume (policy effected).
- GHashTable * pPropTable; // Storage for array of properties (policy effected)
-} EndpointInfoT;
+ int iVolume; // Storage for current endpoint volume (policy effected).
+ json_object *pPropTableJ; //Property Table
+} EndPointInterfaceInfoT;
-typedef struct StreamInfo {
+typedef struct StreamInterfaceInfo {
streamID_t streamID; // Stream unique ID
- EndpointInfoT * pEndpointInfo; // Associated endpoint information (reference)
StreamStateT streamState; // Stream activity state
StreamMuteT streamMute; // Stream mute state
- struct afb_event streamStateEvent; // Stream specific event for stream state changes
- EndpointSelectionModeT endpointSelMode; // Automatic (priority based) or manual endpoint selection
char * pRoleName; // Role string identifier (from role config but could be programatically overriden later)
int iPriority; // Role normalized priority (0-100) (from role config but could be programatically overriden later)
- InterruptBehaviorT eInterruptBehavior; // Role behavior when interrupting lower priority streams (from role config but could be programatically overriden later)
-} StreamInfoT;
-
-
-typedef struct StreamPolicyInfo {
- streamID_t streamID;
- int RolePriority;
- char * pAudioRole;
- InterruptBehaviorT interruptBehavior;
- int iDuckVolume; //duck Volume
-} StreamPolicyInfoT;
-
-typedef struct EndPointPolicyInfo {
- endpointID_t endpointID;
- EndpointTypeT type;
- DeviceURITypeT deviceType;
- char * pDeviceName;
- char * pHalApiName;
- int iVolume; //Current Volume
- GArray * streamInfo; //List of playing or duck stream at a given endpoint
-} EndPointPolicyInfoT;
-
-void Add_Endpoint_Property_Double( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, double in_dPropertyValue);
-void Add_Endpoint_Property_Int( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, int in_iPropertyValue);
-void Add_Endpoint_Property_String( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, const char * in_pPropertyValue);
-int PolicyEndpointStructToJSON(EndpointInfoT * pPolicyEndpoint, json_object **ppPolicyEndpointJ);
-int PolicyCtxJSONToEndpoint(json_object *pEndpointJ, EndpointInfoT * pPolicyStream);
-int PolicyStreamStructToJSON(StreamInfoT * pPolicyStream, json_object **ppPolicyStreamJ);
-int PolicyCtxJSONToStream(json_object *pStreamJ, StreamInfoT * pPolicyStream);
+ InterruptBehaviorT eInterruptBehavior; // Role behavior when interrupting lower priority streams (from role config but could be programatically overriden later)
+ EndPointInterfaceInfoT endpoint;
+} StreamInterfaceInfoT;
+
+void Add_Endpoint_Property_Double( json_object * io_pPropertyArray, char * in_pPropertyName, double in_dPropertyValue);
+void Add_Endpoint_Property_Int( json_object * io_pPropertyArray, char * in_pPropertyName, int in_iPropertyValue);
+void Add_Endpoint_Property_String( json_object * io_pPropertyArray, char * in_pPropertyName, const char * in_pPropertyValue);
+int F(EndPointInterfaceInfoT * pEndpoint, json_object **ppEndpointJ);
+int JSONToEndpoint(json_object *pEndpointJ, EndPointInterfaceInfoT * pStream);
+int StreamToJSON(StreamInterfaceInfoT * pPolicyStream, json_object **ppStreamJ);
+int JSONToStream(json_object *pStreamJ, StreamInterfaceInfoT * pPolicyStream);
#endif // AHL_POLICY_UTILS_INCLUDE
diff --git a/conf.d/project/ahl-audiok4a-config.json b/conf.d/project/ahl-audiok4a-config.json
index f49c0be..74ab251 100644
--- a/conf.d/project/ahl-audiok4a-config.json
+++ b/conf.d/project/ahl-audiok4a-config.json
@@ -7,7 +7,6 @@
"audio_roles": [
{
"name": "Warning",
- "id": 0,
"description": "Safety-relevant or critical alerts/alarms",
"priority": 100,
"output": [
@@ -23,7 +22,6 @@
},
{
"name": "Guidance",
- "id": 1,
"description": "Important user information where user action is expected (e.g. navigation instruction)",
"priority": 25,
"output": [
@@ -39,7 +37,6 @@
},
{
"name": "Notification",
- "id": 2,
"description": "HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...)",
"priority": 0,
"output": [
@@ -57,7 +54,6 @@
},
{
"name": "Communication",
- "id": 3,
"description": "Voice communications (e.g. handsfree, speech recognition)",
"priority": 50,
"output": [
@@ -76,7 +72,6 @@
},
{
"name": "Entertainment",
- "id": 4,
"description": "Multimedia content (e.g. tuner, media player, etc.)",
"priority": 0,
"output": [
@@ -87,7 +82,6 @@
},
{
"name": "System",
- "id": 5,
"description": "System level content or development",
"priority": 100,
"output": [
@@ -100,7 +94,6 @@
},
{
"name": "Startup",
- "id": 6,
"description": "Early (startup) sound",
"priority": 100,
"output": [
@@ -113,7 +106,6 @@
},
{
"name": "Shutdown",
- "id": 7,
"description": "Late (shutdown) sound",
"priority": 100,
"output": [
diff --git a/htdocs/audiohl.html b/htdocs/audiohl.html
index a2cd247..0e153f5 100644
--- a/htdocs/audiohl.html
+++ b/htdocs/audiohl.html
@@ -59,23 +59,26 @@
<br>
<ol>
- <li><button onclick="callbinder('ahl-4a','get_sources', {audio_role:ar})">get_sources(audio_role)</button></li>
- <li><button onclick="callbinder('ahl-4a','get_sinks', {audio_role:ar})">get_sinks(audio_role)</button></li>
+ <li><button onclick="callbinder('ahl-4a','get_endpoints', {audio_role:ar,endpoint_type:ep_type})">get_endpoints(audio_role,endpoint_type)</button></li>
<li><button onclick="callbinder('ahl-4a','stream_open', {audio_role:ar,endpoint_type:ep_type})">stream_open(audio_role,endpoint_type)</button></li>
<li><button onclick="callbinder('ahl-4a','stream_open', {audio_role:ar,endpoint_type:ep_type,endpoint_id:ep_id})">stream_open(audio_role,enpoint_type,endpoint_id)</button></li>
<li><button onclick="callbinder('ahl-4a','stream_close', {stream_id:s_id})">stream_close(stream_id)</button></li>
+ <li><button onclick="callbinder('ahl-4a','stream_close', {})">stream_close()</button></li>
<li><button onclick="callbinder('ahl-4a','get_stream_info', {stream_id:s_id})">get_stream_info(stream_id)</button></li>
+ <li><button onclick="callbinder('ahl-4a','set_stream_state', {stream_id:s_id})">set_stream_state(stream_id)</button></li>
<li><button onclick="callbinder('ahl-4a','set_stream_state', {stream_id:s_id,state:st_state})">set_stream_state(stream_id,stream_state)</button></li>
- <li><button onclick="callbinder('ahl-4a','set_stream_mute', {stream_id:s_id,mute:st_mute})">set_stream_mute(stream_id,mute)</button></li>
- <li><button onclick="callbinder('ahl-4a','set_volume', {endpoint_type:ep_type,endpoint_id:ep_id,volume:vol_val})">set_volume(endpoint_type,endpoint_id,value)</button></li>
- <li><button onclick="callbinder('ahl-4a','get_volume', {endpoint_type:ep_type,endpoint_id:ep_id})">get_volume(endpoint_type,endpoint_id)</button></li>
- <li><button onclick="callbinder('ahl-4a','set_property', {endpoint_type:ep_type,endpoint_id:ep_id,property_name:p_name,value:prop_val})">set_property(endpoint_type,endpoint_id,property,value)</button></li>
- <li><button onclick="callbinder('ahl-4a','get_property', {endpoint_type:ep_type,endpoint_id:ep_id,property_name:p_name})">get_property(endpoint_type,endpoint_id,property)</button></li>
+ <li><button onclick="callbinder('ahl-4a','set_stream_state', {stream_id:s_id,mute:st_mute})">set_stream_state(stream_id,mute)</button></li>
+ <li><button onclick="callbinder('ahl-4a','set_stream_state', {stream_id:s_id,state:st_state,mute:st_mute})">set_stream_state(stream_id,stream_state,mute)</button></li>
+ <li><button onclick="callbinder('ahl-4a','set_stream_state', {state:st_state,mute:st_mute})">set_stream_state(stream_state,mute)</button></li>
+ <li><button onclick="callbinder('ahl-4a','volume', {endpoint_type:ep_type,endpoint_id:ep_id,volume:vol_val})">volume(endpoint_type,endpoint_id,value)</button></li>
+ <li><button onclick="callbinder('ahl-4a','volume', {endpoint_type:ep_type,endpoint_id:ep_id})">volume(endpoint_type,endpoint_id)</button></li>
+ <li><button onclick="callbinder('ahl-4a','property', {endpoint_type:ep_type,endpoint_id:ep_id,property_name:p_name,value:prop_val})">property(endpoint_type,endpoint_id,property,value)</button></li>
+ <li><button onclick="callbinder('ahl-4a','property', {endpoint_type:ep_type,endpoint_id:ep_id,property_name:p_name})">property(endpoint_type,endpoint_id,property)</button></li>
<li><button onclick="callbinder('ahl-4a','get_endpoint_info', {endpoint_type:ep_type,endpoint_id:ep_id})">get_endpoint_info(endpoint_type,endpoint_id)</button></li>
<li><button onclick="callbinder('ahl-4a','get_list_actions', {audio_role:ar})">get_list_actions(audio_role)</button></li>
<li><button onclick="callbinder('ahl-4a','post_action', {action_name:'emergency_brake',audio_role:ar,media_name:'Warning.wav'})">post_action(emergency_brake,audio_role,'Warning.wav')</button></li>
- <li><button onclick="callbinder('ahl-4a','subscribe', {events:['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action']})">subscribe(['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'])</button>
- <li><button onclick="callbinder('ahl-4a','unsubscribe', {events:['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action']})">unsubscribe(['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'])</button></li>
+ <li><button onclick="callbinder('ahl-4a','event_subscription', {events:['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'],subscribe:1})">subscribe(['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'])</button>
+ <li><button onclick="callbinder('ahl-4a','event_subscription', {events:['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'],subscribe:0})">unsubscribe(['ahl_endpoint_property_event','ahl_endpoint_volume_event','ahl_post_action'])</button></li>
</ol>
<div id="main" style="visibility:hidden">