diff options
author | Tai Vuong <tvuong@audiokinetic.com> | 2017-11-02 16:31:15 -0400 |
---|---|---|
committer | Tai Vuong <tvuong@audiokinetic.com> | 2017-11-02 16:31:15 -0400 |
commit | 5d2ee4455d95771d12cc6058bc19c0d6f7fe43d1 (patch) | |
tree | b4cbc2be7475641edf71ae42c6ce117dba27b91d /src | |
parent | e92aade201ec131c3eb7430305f60a0a4c9c44c1 (diff) | |
parent | ab6e470190f2cc410b1f6fa8f146317a3c3b08b5 (diff) |
merge dev branch with master
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 67 | ||||
-rw-r--r-- | src/ahl-apidef.h | 237 | ||||
-rw-r--r-- | src/ahl-apidef.json | 447 | ||||
-rw-r--r-- | src/ahl-binding.c | 1276 | ||||
-rw-r--r-- | src/ahl-binding.h | 118 | ||||
-rw-r--r-- | src/ahl-config.c | 175 | ||||
-rw-r--r-- | src/ahl-deviceenum.c | 332 | ||||
-rw-r--r-- | src/ahl-interface.h | 96 | ||||
-rw-r--r-- | src/ahl-json.c | 296 | ||||
-rw-r--r-- | src/ahl-json.h | 26 | ||||
-rwxr-xr-x | src/ahl-policy-utils.c | 193 | ||||
-rwxr-xr-x | src/ahl-policy-utils.h | 154 | ||||
-rw-r--r-- | src/ahl-policy.c | 1188 | ||||
-rw-r--r-- | src/ahl-policy.h | 49 | ||||
-rw-r--r-- | src/ahl-policyJSON.c | 307 | ||||
-rw-r--r-- | src/ahl-policyJSON.h | 30 |
16 files changed, 0 insertions, 4991 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 0bb3986..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,67 +0,0 @@ -########################################################################### -# Copyright 2017 Audiokinetic.com -# -# author: Francois Thibault <fthibault@audiokinetic.com> -# -# 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. -########################################################################### -# Generate API-v2 hat from OpenAPI json definition -macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) - add_custom_command(OUTPUT ${API_DEF_NAME}.h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${API_DEF_NAME}.json - COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h - ) - add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) - add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) - -endmacro(SET_TARGET_GENSKEL) - -FIND_PACKAGE(PkgConfig REQUIRED) -PKG_CHECK_MODULES(GLIB_PKG REQUIRED glib-2.0) - -# get_cmake_property(_variableNames VARIABLES) -# foreach (_variableName ${_variableNames}) -# message(STATUS "${_variableName}=${${_variableName}}") -# endforeach() - -# Add target to project dependency list -PROJECT_TARGET_ADD(audiohighlevel) - - # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE ahl-binding.c ahl-deviceenum.c ahl-config.c ahl-policy-utils.c ahl-policy.c ahl-json.c) - - # Generate API-v2 hat from OpenAPI json definition - SET_TARGET_GENSKEL(${TARGET_NAME} ahl-apidef) - - # Binder exposes a unique public entry point - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "afb-" - LABELS "BINDING" - LINK_FLAGS ${BINDINGS_LINK_FLAG} - OUTPUT_NAME ${TARGET_NAME} - ) - - # Define target includes - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} - PUBLIC ${GLIB_PKG_INCLUDE_DIRS} - ) - - # Library dependencies (include updates automatically) - # Find package for GLIB does not seem to export - TARGET_LINK_LIBRARIES(${TARGET_NAME} - afb-utilities - ${GLIB_PKG_LIBRARIES} - ${link_libraries} - ) - diff --git a/src/ahl-apidef.h b/src/ahl-apidef.h deleted file mode 100644 index 97f8de7..0000000 --- a/src/ahl-apidef.h +++ /dev/null @@ -1,237 +0,0 @@ - -static const char _afb_description_v2_audiohl[] = - "{\"openapi\":\"3.0.0\",\"info\":{\"description\":\"Audio high level API " - "for AGL applications\",\"title\":\"audiohighlevel\",\"version\":\"1.0\"," - "\"x-binding-c-generator\":{\"api\":\"audiohl\",\"version\":2,\"prefix\":" - "\"audiohlapi_\",\"postfix\":\"\",\"start\":null,\"onevent\":\"AhlOnEvent" - "\",\"init\":\"AhlBindingInit\",\"scope\":\"\",\"private\":false}},\"serv" - "ers\":[{\"url\":\"ws://{host}:{port}/api/audiohl\",\"description\":\"Aud" - "io high level API for AGL applications.\",\"variables\":{\"host\":{\"def" - "ault\":\"localhost\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\":" - "[{\"$ref\":\"#/components/schemas/afb-event\"}]}],\"components\":{\"sche" - "mas\":{\"afb-reply\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"" - "afb-event\":{\"$ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply" - "-v2\":{\"title\":\"Generic response.\",\"type\":\"object\",\"required\":" - "[\"jtype\",\"request\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"" - "const\":\"afb-reply\"},\"request\":{\"type\":\"object\",\"required\":[\"" - "status\"],\"properties\":{\"status\":{\"type\":\"string\"},\"info\":{\"t" - "ype\":\"string\"},\"token\":{\"type\":\"string\"},\"uuid\":{\"type\":\"s" - "tring\"},\"reqid\":{\"type\":\"string\"}}},\"response\":{\"type\":\"obje" - "ct\"}}},\"afb-event-v2\":{\"type\":\"object\",\"required\":[\"jtype\",\"" - "event\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-" - "event\"},\"event\":{\"type\":\"string\"},\"data\":{\"type\":\"object\"}}" - "},\"endpoint_info\":{\"type\":\"object\",\"required\":[\"endpoint_id\",\"" - "type\",\"device_name\",\"device_uri\"],\"properties\":{\"endpoint_id\":{" - "\"type\":\"int\"},\"type\":{\"type\":\"enum\"},\"device_name\":{\"type\"" - ":\"string\"},\"device_uri_type\":{\"type\":\"string\"}}},\"stream_info\"" - ":{\"type\":\"object\",\"required\":[\"stream_id\",\"state\",\"mute\",\"e" - "ndpoint_info\"],\"properties\":{\"stream_id\":{\"type\":\"int\"},\"state" - "\":{\"type\":\"int\"},\"mute\":{\"type\":\"int\"},\"device_uri\":{\"type" - "\":\"string\"},\"$ref\":\"#/components/schemas/endpoint_info\"}}},\"x-pe" - "rmissions\":{\"streamcontrol\":{\"permission\":\"urn:AGL:permission:audi" - "o:public:streamcontrol\"},\"endpointcontrol\":{\"permission\":\"urn:AGL:" - "permission:audio:public:endpointcontrol\"},\"audiostream\":{\"permission" - "\":\"urn:AGL:permission:audio:public:audiostream\"},\"soundevent\":{\"pe" - "rmission\":\"urn:AGL:permission:audio:public:soundevent\"}},\"responses\"" - ":{\"200\":{\"description\":\"A complex object array response\",\"content" - "\":{\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/af" - "b-reply\"}}}},\"400\":{\"description\":\"Invalid arguments\"}}},\"paths\"" - ":{\"/get_endpoints\":{\"description\":\"Retrieve array of available audi" - "o endpoints\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"audi" - "o_role\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"q" - "uery\",\"name\":\"endpoint_type\",\"required\":true,\"schema\":{\"type\"" - ":\"enum\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/2" - "00\",\"response\":{\"description\":\"Array of endpoint info structures\"" - ",\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/endpoint_" - "info\"}}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/stream" - "_open\":{\"description\":\"Request opening a stream\",\"get\":{\"x-permi" - "ssions\":{\"$ref\":\"#/components/x-permissions/audiostream\"},\"paramet" - "ers\":[{\"in\":\"query\",\"name\":\"audio_role\",\"required\":true,\"sch" - "ema\":{\"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\":false,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":" - "{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/componen" - "ts/responses/400\"}}}},\"/set_stream_state\":{\"description\":\"Change s" - "tream active and/or mute state\",\"get\":{\"x-permissions\":{\"$ref\":\"" - "#/components/x-permissions/streamcontrol\"},\"parameters\":[{\"in\":\"qu" - "ery\",\"name\":\"stream_id\",\"required\":false,\"schema\":{\"type\":\"i" - "nt\"}},{\"in\":\"query\",\"name\":\"state\",\"required\":false,\"schema\"" - ":{\"type\":\"int\"}},{\"in\":\"query\",\"name\":\"mute\",\"required\":fa" - "lse,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"200\":{\"$ref\":\"#" - "/components/responses/200\"},\"400\":{\"$ref\":\"#/components/responses/" - "400\"}}}},\"/get_stream_info\":{\"description\":\"Retrieve stream inform" - "ation\",\"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_" - "info\"}},\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/volume\"" - ":{\"description\":\"Set or get volume on endpoint\",\"get\":{\"x-permiss" - "ions\":{\"$ref\":\"#/components/x-permissions/endpointcontrol\"},\"param" - "eters\":[{\"in\":\"query\",\"name\":\"endpoint_type\",\"required\":true," - "\"schema\":{\"type\":\"enum\"}},{\"in\":\"query\",\"name\":\"endpoint_id" - "\",\"required\":true,\"schema\":{\"type\":\"int\"}},{\"in\":\"query\",\"" - "name\":\"volume\",\"required\":false,\"schema\":{\"type\":\"string\"}}]," - "\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"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\":true,\"schema\":{\"type\":\"int\"}}],\"r" - "esponses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"" - "$ref\":\"#/components/responses/400\"}}}},\"/property\":{\"description\"" - ":\"Set/get endpoint property value\",\"get\":{\"x-permissions\":{\"$ref\"" - ":\"#/components/x-permissions/endpointcontrol\"},\"parameters\":[{\"in\"" - ":\"query\",\"name\":\"endpoint_type\",\"required\":true,\"schema\":{\"ty" - "pe\":\"enum\"}},{\"in\":\"query\",\"name\":\"endpoint_id\",\"required\":" - "true,\"schema\":{\"type\":\"int\"}},{\"in\":\"query\",\"name\":\"propert" - "y_name\",\"required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"q" - "uery\",\"name\":\"value\",\"required\":false,\"schema\":{\"type\":\"stri" - "ng\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}" - ",\"400\":{\"$ref\":\"#/components/responses/400\"}}}},\"/get_list_action" - "s\":{\"description\":\"Retrieve a list of supported actions for a partic" - "ular audio role\",\"get\":{\"parameters\":[{\"in\":\"query\",\"name\":\"" - "audio_role\",\"required\":true,\"schema\":{\"type\":\"string\"}}],\"resp" - "onses\":{\"200\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$r" - "ef\":\"#/components/responses/400\"}}}},\"/post_action\":{\"description\"" - ":\"Post sound or audio device related action event (extendable mechanism" - ")\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/so" - "undevent\"},\"parameters\":[{\"in\":\"query\",\"name\":\"action_name\",\"" - "required\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query\",\"na" - "me\":\"audio_role\",\"required\":true,\"schema\":{\"type\":\"string\"}}," - "{\"in\":\"query\",\"name\":\"media_name\",\"required\":false,\"schema\":" - "{\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"action_context\",\"r" - "equired\":false,\"schema\":{\"type\":\"object\"}}],\"responses\":{\"200\"" - ":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/compone" - "nts/responses/400\"}}}},\"/event_subscription\":{\"description\":\"Subsc" - "ribe to audio high level events\",\"get\":{\"parameters\":[{\"in\":\"que" - "ry\",\"name\":\"events\",\"required\":true,\"schema\":{\"type\":\"array\"" - ",\"items\":{\"type\":\"string\"}}},{\"in\":\"query\",\"name\":\"subscrib" - "e\",\"required\":true,\"schema\":{\"type\":\"int\"}}],\"responses\":{\"2" - "00\":{\"$ref\":\"#/components/responses/200\"},\"400\":{\"$ref\":\"#/com" - "ponents/responses/400\"}}}}}}" -; - -static const struct afb_auth _afb_auths_v2_audiohl[] = { - { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:audiostream" }, - { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:streamcontrol" }, - { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:endpointcontrol" }, - { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:soundevent" } -}; - - 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_get_stream_info(struct afb_req req); - void audiohlapi_volume(struct afb_req req); - void audiohlapi_get_endpoint_info(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_event_subscription(struct afb_req req); - -static const struct afb_verb_v2 _afb_verbs_v2_audiohl[] = { - { - .verb = "get_endpoints", - .callback = audiohlapi_get_endpoints, - .auth = NULL, - .info = "Retrieve array of available audio endpoints", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "stream_open", - .callback = audiohlapi_stream_open, - .auth = &_afb_auths_v2_audiohl[0], - .info = "Request opening a stream", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "stream_close", - .callback = audiohlapi_stream_close, - .auth = &_afb_auths_v2_audiohl[0], - .info = "Request closing a stream", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "set_stream_state", - .callback = audiohlapi_set_stream_state, - .auth = &_afb_auths_v2_audiohl[1], - .info = "Change stream active and/or mute state", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "get_stream_info", - .callback = audiohlapi_get_stream_info, - .auth = NULL, - .info = "Retrieve stream information", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "volume", - .callback = audiohlapi_volume, - .auth = &_afb_auths_v2_audiohl[2], - .info = "Set or get volume on endpoint", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "get_endpoint_info", - .callback = audiohlapi_get_endpoint_info, - .auth = NULL, - .info = "Retrieve endpoint information including its properties", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "property", - .callback = audiohlapi_property, - .auth = &_afb_auths_v2_audiohl[2], - .info = "Set/get endpoint property value", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "get_list_actions", - .callback = audiohlapi_get_list_actions, - .auth = NULL, - .info = "Retrieve a list of supported actions for a particular audio role", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "post_action", - .callback = audiohlapi_post_action, - .auth = &_afb_auths_v2_audiohl[3], - .info = "Post sound or audio device related action event (extendable mechanism)", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "event_subscription", - .callback = audiohlapi_event_subscription, - .auth = NULL, - .info = "Subscribe to audio high level events", - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = NULL, - .callback = NULL, - .auth = NULL, - .info = NULL, - .session = 0 - } -}; - -const struct afb_binding_v2 afbBindingV2 = { - .api = "audiohl", - .specification = _afb_description_v2_audiohl, - .info = "Audio high level API for AGL applications", - .verbs = _afb_verbs_v2_audiohl, - .preinit = NULL, - .init = AhlBindingInit, - .onevent = AhlOnEvent, - .noconcurrency = 0 -}; - diff --git a/src/ahl-apidef.json b/src/ahl-apidef.json deleted file mode 100644 index 15ee186..0000000 --- a/src/ahl-apidef.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "openapi": "3.0.0", - "info": { - "description": "Audio high level API for AGL applications", - "title": "audiohighlevel", - "version": "1.0", - "x-binding-c-generator": { - "api": "audiohl", - "version": 2, - "prefix": "audiohlapi_", - "postfix": "", - "start": null, - "onevent": "AhlOnEvent", - "init": "AhlBindingInit", - "scope": "", - "private": false - } - }, - "servers": [ - { - "url": "ws://{host}:{port}/api/audiohl", - "description": "Audio high level API for AGL applications.", - "variables": { - "host": { - "default": "localhost" - }, - "port": { - "default": "1234" - } - }, - "x-afb-events": [ - { - "$ref": "#/components/schemas/afb-event" - } - ] - } - ], - "components": { - "schemas": { - "afb-reply": { - "$ref": "#/components/schemas/afb-reply-v2" - }, - "afb-event": { - "$ref": "#/components/schemas/afb-event-v2" - }, - "afb-reply-v2": { - "title": "Generic response.", - "type": "object", - "required": ["jtype", "request"], - "properties": { - "jtype": { - "type": "string", - "const": "afb-reply" - }, - "request": { - "type": "object", - "required": ["status"], - "properties": { - "status": { - "type": "string" - }, - "info": { - "type": "string" - }, - "token": { - "type": "string" - }, - "uuid": { - "type": "string" - }, - "reqid": { - "type": "string" - } - } - }, - "response": { - "type": "object" - } - } - }, - "afb-event-v2": { - "type": "object", - "required": ["jtype", "event"], - "properties": { - "jtype": { - "type": "string", - "const": "afb-event" - }, - "event": { - "type": "string" - }, - "data": { - "type": "object" - } - } - }, - "endpoint_info": { - "type": "object", - "required": [ "endpoint_id", "type", "device_name", "device_uri" ], - "properties": { - "endpoint_id": { "type": "int" }, - "type": { "type": "enum" }, - "device_name": { "type": "string" }, - "device_uri_type": { "type": "string" } - } - }, - "stream_info": { - "type": "object", - "required": [ "stream_id", "state", "mute", "endpoint_info" ], - "properties": { - "stream_id": { "type": "int" }, - "state": { "type": "int" }, - "mute": { "type": "int" }, - "device_uri": { "type": "string" }, - "$ref": "#/components/schemas/endpoint_info" - } - } - }, - "x-permissions": { - "streamcontrol": { "permission": "urn:AGL:permission:audio:public:streamcontrol"}, - "endpointcontrol": { "permission": "urn:AGL:permission:audio:public:endpointcontrol"}, - "audiostream": { "permission": "urn:AGL:permission:audio:public:audiostream"}, - "soundevent": {"permission": "urn:AGL:permission:audio:public:soundevent"} - }, - "responses": { - "200": { - "description": "A complex object array response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/afb-reply" - } - } - } - }, - "400": { "description": "Invalid arguments" } - } - }, - "paths": { - "/get_endpoints": { - "description": "Retrieve array of available audio endpoints", - "get": { - "parameters": [ - { - "in": "query", - "name": "audio_role", - "required": true, - "schema": { "type": "string" } - }, - { - "in": "query", - "name": "endpoint_type", - "required": true, - "schema": { "type": "enum" } - } - ], - "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" } - } - } - }, - "/stream_open": { - "description": "Request opening a stream", - "get": { - "x-permissions": { "$ref": "#/components/x-permissions/audiostream" }, - "parameters": [ - { - "in": "query", - "name": "audio_role", - "required": true, - "schema": { "type": "string" } - }, - { - "in": "query", - "name": "endpoint_type", - "required": true, - "schema": { "type": "enum" } - }, - { - "in": "query", - "name": "endpoint_id", - "required": false, - "schema": { "type": "int" } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200", - "response": { - "description": "Stream information structure", - "$ref": "#/components/schemas/stream_info" - } - }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/stream_close": { - "description": "Request closing a stream", - "get": { - "x-permissions": { "$ref": "#/components/x-permissions/audiostream" }, - "parameters": [ - { - "in": "query", - "name": "stream_id", - "required": false, - "schema": { "type": "int" } - } - ], - "responses": { - "200": { "$ref": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/set_stream_state": { - "description": "Change stream active and/or mute state", - "get": { - "x-permissions": { - "$ref": "#/components/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": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/get_stream_info": { - "description": "Retrieve stream information", - "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_info" - } - }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/volume": { - "description": "Set or get volume on endpoint", - "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": "volume", - "required": false, - "schema": { "type": "string" } - } - ], - "responses": { - "200": { "$ref": "#/components/responses/200" }, - "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": true, - "schema": { "type": "int" } - } - ], - "responses": { - "200": { "$ref": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/property": { - "description": "Set/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_name", - "required": true, - "schema": { "type": "string" } - }, - { - "in": "query", - "name": "value", - "required": false, - "schema": { "type": "string" } - } - ], - "responses": { - "200": { "$ref": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/get_list_actions": { - "description": "Retrieve a list of supported actions for a particular audio role", - "get": { - "parameters": [ - { - "in": "query", - "name": "audio_role", - "required": true, - "schema": { "type": "string" } - } - ], - "responses": { - "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/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": false, - "schema": { "type": "string"} - }, - { - "in": "query", - "name": "action_context", - "required": false, - "schema": { "type": "object" } - } - ], - "responses": { - "200": { "$ref": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - }, - "/event_subscription": { - "description": "Subscribe 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": { - "200": { "$ref": "#/components/responses/200" }, - "400": { "$ref": "#/components/responses/400" } - } - } - } - } -} diff --git a/src/ahl-binding.c b/src/ahl-binding.c deleted file mode 100644 index c205c8e..0000000 --- a/src/ahl-binding.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <string.h> - -#include "ahl-binding.h" -#include "ahl-apidef.h" // Generated from JSON OpenAPI -#include "wrap-json.h" -#include "ahl-policy.h" -#include "ahl-json.h" - -// Global high-level binding context -AHLCtxT g_AHLCtx; - -static EndpointTypeT EndpointTypeToEnum(char * in_pEndpointTypeStr) -{ - if (in_pEndpointTypeStr == NULL) { - return ENDPOINTTYPE_MAXVALUE; - } - else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SOURCE)==0) { - return ENDPOINTTYPE_SOURCE; - } - else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SINK)==0) { - return ENDPOINTTYPE_SINK; - } - else - return ENDPOINTTYPE_MAXVALUE; -} - -static StreamStateT StreamStateToEnum(char * in_pStreamStateStr) -{ - if (in_pStreamStateStr == NULL) { - return STREAM_STATE_MAXVALUE; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_IDLE)==0) { - return STREAM_STATE_IDLE; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_RUNNING)==0) { - return STREAM_STATE_RUNNING; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_PAUSED)==0) { - return STREAM_STATE_PAUSED; - } - else - return STREAM_STATE_MAXVALUE; -} - -static StreamMuteT StreamMuteToEnum(char * in_pStreamMuteStr) -{ - if (in_pStreamMuteStr == NULL) { - return STREAM_MUTE_MAXVALUE; - } - else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_UNMUTED)==0) { - return STREAM_UNMUTED; - } - else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_MUTED)==0) { - return STREAM_MUTED; - } - else - return STREAM_MUTE_MAXVALUE; -} - -static streamID_t CreateNewStreamID() -{ - streamID_t newID = g_AHLCtx.nextStreamID; - g_AHLCtx.nextStreamID++; - return newID; -} - -static EndpointInfoT * GetEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole) -{ - EndpointInfoT * pEndpointInfo = NULL; - 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) { - pEndpointInfo = pCurEndpointInfo; - break; - } - } - - return pEndpointInfo; -} - -static EndpointInfoT * GetEndpointInfo(endpointID_t in_endpointID, EndpointTypeT in_endpointType) -{ - EndpointInfoT * pEndpointInfo = NULL; - - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo); - while (pEndpointInfo == NULL && g_hash_table_iter_next (&iter, &key, &value)) - { - RoleInfoT * pRoleInfo = (RoleInfoT*)value; - pEndpointInfo = GetEndpointInfoWithRole(in_endpointID,in_endpointType,pRoleInfo); - } - - return pEndpointInfo; -} - -static StreamInfoT * GetStream(streamID_t in_streamID) -{ - if (g_AHLCtx.policyCtx.pStreams == NULL) - return NULL; - - return g_hash_table_lookup(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&in_streamID)); -} - -static RoleInfoT * GetRole(char * in_pAudioRoleName) -{ - if (g_AHLCtx.policyCtx.pRoleInfo == NULL) - return NULL; - - 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)); - pClientCtx->pStreamAccessList = g_array_new(FALSE, TRUE, sizeof(streamID_t)); - return pClientCtx; -} - -static void TerminateClientContext(void * ptr) -{ - AHLClientCtxT * pClientCtx = (AHLClientCtxT *) ptr; - if (pClientCtx != NULL) { - CloseAllClientStreams(pClientCtx,NULL); - - if (pClientCtx->pStreamAccessList) { - g_array_free( pClientCtx->pStreamAccessList, TRUE); - pClientCtx->pStreamAccessList = NULL; - } - - free(pClientCtx); - } -} - -static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t streamID) -{ - int iAccessControl = AHL_ACCESS_CONTROL_DENIED; - if (pClientCtx && 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) { - iAccessControl = AHL_ACCESS_CONTROL_GRANTED; - } - } - } - return iAccessControl; -} - -static int CreateEvents() -{ - g_AHLCtx.policyCtx.propertyEvent = afb_daemon_make_event(AHL_ENDPOINT_PROPERTY_EVENT); - int err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); - if (err) { - AFB_ERROR("Could not create endpoint property change event"); - 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 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 AHL_FAIL; - } - - return AHL_SUCCESS; -} - -static void AhlBindingTerm() -{ -#ifndef AHL_DISCONNECT_POLICY - // Policy termination - Policy_Term(); -#endif - - // Roles - if (g_AHLCtx.policyCtx.pRoleInfo != NULL) { - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init(&iter, g_AHLCtx.policyCtx.pRoleInfo); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - RoleInfoT * pRole = (RoleInfoT *)value; - if (pRole) - { - if(pRole->pRoleName) { - g_free(pRole->pRoleName); - pRole->pRoleName = NULL; - } - // Actions - if (pRole->pActionList) { - for (int i = 0; i < pRole->pActionList->len; i++) - { - g_ptr_array_remove_index( pRole->pActionList, i ); // Free char * is called by GLib - } - } - // Source endpoints - if (pRole->pSourceEndpoints) { - for (int i = 0; i < pRole->pSourceEndpoints->len; i++) - { - EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSourceEndpoints, i ); // Free endpoint * is called by GLib - if (pEndpoint) { - TermEndpointInfo(pEndpoint); - } - } - } - // Sink endpoints - if (pRole->pSinkEndpoints) { - for (int i = 0; i < pRole->pSinkEndpoints->len; i++) - { - EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSinkEndpoints, i ); // Free endpoint * is called by GLib - if (pEndpoint) { - TermEndpointInfo(pEndpoint); - } - } - } - free(pRole); - } - } - g_hash_table_remove_all(g_AHLCtx.policyCtx.pRoleInfo); - g_hash_table_destroy(g_AHLCtx.policyCtx.pRoleInfo); - g_AHLCtx.policyCtx.pRoleInfo = NULL; - } - - if (g_AHLCtx.policyCtx.pStreams) { - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pStreams); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (value) - free(value); - } - g_hash_table_remove_all(g_AHLCtx.policyCtx.pStreams); - g_hash_table_destroy(g_AHLCtx.policyCtx.pStreams); - g_AHLCtx.policyCtx.pStreams = NULL; - } - - if (g_AHLCtx.policyCtx.pHALList) { - g_ptr_array_free(g_AHLCtx.policyCtx.pHALList,TRUE); - g_AHLCtx.policyCtx.pHALList = NULL; - } - - AFB_INFO("Audio high-level binding termination success"); -} - -// Binding initialization -PUBLIC int AhlBindingInit() -{ - memset(&g_AHLCtx,0,sizeof(g_AHLCtx)); - - // Register exit function - atexit(AhlBindingTerm); - - // 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 AHL_FAIL; - } - -#ifndef AHL_DISCONNECT_POLICY - // Policy initialization - err = Policy_Init(); - if(err == AHL_POLICY_REJECT) { - //Error messages already reported inside PolicyInit - return AHL_FAIL; - } - - // 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)) - { - RoleInfoT * pRoleInfo = (RoleInfoT*)value; - if (pRoleInfo->pSourceEndpoints){ - // for all source endpoints - for (int j = 0; j < pRoleInfo->pSourceEndpoints->len; j++) { - EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSourceEndpoints,j); - g_assert_nonnull(pCurEndpointInfo); - 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 AHL_FAIL; - } - else - { - 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 - } - 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 *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 AHL_FAIL; - } - else - { - 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 - } - 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 // 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 AHL_FAIL; - } - - AFB_DEBUG("Audio high-level Binding success"); - return AHL_SUCCESS; -} - -PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ) -{ - AFB_DEBUG("AHL received event %s", evtname); - - // TODO: Handle event from the policy to update internal information (currently not possible since within the same binding) - -#ifndef AHL_DISCONNECT_POLICY - // Temp: currently forward to policy to handle events (they will be received directly when disconnected into separate binding) - Policy_OnEvent(evtname, eventJ); -#endif -} - -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,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; - } - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - 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 = 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) { - JSONPublicPackageEndpoint(pEndpointInfo,&deviceJ); - json_object_array_add(devicesJ, deviceJ); - } - } - } - } - - afb_req_success(req, devicesJ, "List of endpoints"); -} - -PUBLIC void audiohlapi_stream_open(struct afb_req req) -{ - json_object *streamInfoJ = NULL; - StreamInfoT * pStreamInfo = NULL; - json_object *queryJ = NULL; - char * audioRole = NULL; - char * endpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointInfoT * pEndpointInfo = NULL; - EndpointSelectionModeT endpointSelMode = ENDPOINTSELMODEMAXVALUE; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?i}", "audio_role", &audioRole, "endpoint_type", &endpointTypeStr, "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; - } - endpointType = EndpointTypeToEnum(endpointTypeStr); - - // 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) - { - pClientCtx = AllocateClientContext(); - afb_req_context_set(req, pClientCtx, TerminateClientContext); - } - - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - GPtrArray * pDeviceArray = NULL; - if (endpointType == ENDPOINTTYPE_SOURCE){ - pDeviceArray = pRole->pSourceEndpoints; - } - else{ - pDeviceArray = pRole->pSinkEndpoints; - } - if (pDeviceArray == NULL || pDeviceArray->len == 0) { - afb_req_fail_f(req, "No available devices", "No available devices for role:%s and device type:%s",audioRole,endpointTypeStr); - return; - } - - if (endpointID == AHL_UNDEFINED) - { - // 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; - // Find specified endpoint ID in list of devices - int iNumberDevices = pDeviceArray->len; - for ( int j = 0 ; j < iNumberDevices; j++) - { - pEndpointInfo = g_ptr_array_index(pDeviceArray,j); - if (pEndpointInfo && pEndpointInfo->endpointID == endpointID) { - break; - } - pEndpointInfo = NULL; - } - } - - if (pEndpointInfo == NULL) { - afb_req_fail_f(req, "Endpoint not available", "Specified endpoint not available for role:%s and device type:%d endpoint id %d",audioRole,endpointType,endpointID); - return; - } - - pStreamInfo = (StreamInfoT*) malloc(sizeof(StreamInfoT)); - memset(pStreamInfo,0,sizeof(StreamInfoT)); - - // Create stream - pStreamInfo->streamID = CreateNewStreamID(); // create new ID - pStreamInfo->streamState = STREAM_STATE_IDLE; - pStreamInfo->streamMute = STREAM_UNMUTED; - pStreamInfo->pEndpointInfo = pEndpointInfo; - pStreamInfo->endpointSelMode = endpointSelMode; - // Directly from role config for now, but could be programmatically overriden in the future - pStreamInfo->pRoleName = pRole->pRoleName; - pStreamInfo->iPriority = pRole->iPriority; - pStreamInfo->eInterruptBehavior = pRole->eInterruptBehavior; - -#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 = StreamInfoToJSON(pStreamInfo,&pPolicyStreamJ); - if (err) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_OpenStream"); - return; - } - - int policyAllowed = Policy_OpenStream(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(req, "Audio policy violation", "Open stream not allowed in current context"); - return; - } -#endif - - char streamEventName[128]; - snprintf(streamEventName,128,"ahl_streamstate_%d",pStreamInfo->streamID); - - pStreamInfo->streamStateEvent = afb_daemon_make_event(streamEventName); - err = !afb_event_is_valid(pStreamInfo->streamStateEvent); - if (err) { - afb_req_fail(req, "Stream event creation failure", "Could not create stream specific state change event"); - return; - } - - err = afb_req_subscribe(req,pStreamInfo->streamStateEvent); - if (err) { - afb_req_fail(req, "Stream event subscription failure", "Could not subscribe to stream specific state change event"); - return; - } - - // Add to client context stream ID access rights - g_array_append_val(pClientCtx->pStreamAccessList, pStreamInfo->streamID); - - // Push stream on active stream list - if (g_AHLCtx.policyCtx.pStreams) - g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo ); - - // Package and return stream information to client - JSONPublicPackageStream(pStreamInfo,&streamInfoJ); - - afb_req_success(req, streamInfoJ, "Stream info structure"); -} - -PUBLIC void audiohlapi_stream_close(struct afb_req req) -{ - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - - queryJ = afb_req_json(req); - 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; - } - - // 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; - } - - if (streamID == AHL_UNDEFINED) { - err = CloseAllClientStreams(pClientCtx,&req); - if (err) { - afb_req_fail(req, "Error closing streams", "Streams cannot close"); - return; - } - } - 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"); -} - -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(*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( in_pClientCtx, streamID ); - if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED) - { - afb_req_fail(*pReq, "Access control denied", "Set stream state not allowed in current client context"); - return AHL_FAIL; - } - - if (pStreamStateStr != NULL) { - StreamStateT streamState = StreamStateToEnum(pStreamStateStr); -#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_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 - } - - 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; - } - - 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->streamMute = muteState; -#endif - } - - return AHL_SUCCESS; -} - - 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,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; - } - - // 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; - } - - 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; - } - } - } - } - else { - err = SetStreamState(pClientCtx,&req,streamID,streamStateStr,pMuteStr); - if (err) { - return; - } - } - - afb_req_success(req, NULL, "Set stream state"); - } - - PUBLIC void audiohlapi_get_stream_info(struct afb_req req) - { - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - json_object * streamInfoJ = NULL; - - queryJ = afb_req_json(req); - 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; - } - - 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; - } - - JSONPublicPackageStream(pStreamInfo,&streamInfoJ); - - afb_req_success(req, streamInfoJ, "Get stream info completed"); - } - -PUBLIC void audiohlapi_volume(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - 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); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - 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; - } - - if (volumeStr != 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; - } - - 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; - } -#else - // Simulate that policy returns target state (accepted) - pEndpointInfo->iVolume = atoi(volumeStr); -#endif - } - - json_object * volumeJ = json_object_new_int(pEndpointInfo->iVolume); - - afb_req_success(req, volumeJ, "Set/get volume completed"); -} - -PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - - 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; - } - 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; - } - - json_object *endpointInfoJ = NULL; - EndpointInfoToJSON(pEndpointInfo,&endpointInfoJ); - - afb_req_success(req, endpointInfoJ, "Retrieved endpoint information and properties"); -} - -PUBLIC void audiohlapi_property(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - char * propertyName = NULL; - 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); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - 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; - } - - 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; - } - - 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 - } - - // Retrieve cached property value - json_object * propertyValJ = (json_object *)g_hash_table_lookup(pEndpointInfo->pPropTable,propertyName); - if (propertyValJ == NULL) { - afb_req_fail_f(req, "Property not found", "Property information not found: %s",propertyName); - return; - } - - json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object - - afb_req_success(req, propertyValJ, "Set/get property completed"); -} - -PUBLIC void audiohlapi_get_list_actions(struct afb_req req) -{ - json_object *queryJ = NULL; - char * audioRole = NULL; - json_object * roleActionsJ = 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; - } - - // Build and return list of actions for specific audio role - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - roleActionsJ = json_object_new_array(); - if (pRole->pActionList) { - int iNumberActions = pRole->pActionList->len; - for ( int i = 0 ; i < iNumberActions; i++) - { - char * pActionName = g_ptr_array_index(pRole->pActionList,i); - json_object * actionJ = json_object_new_string(pActionName); - json_object_array_add(roleActionsJ, actionJ); - } - } - - afb_req_success(req, roleActionsJ, "Retrieved action list for audio role"); -} - -PUBLIC void audiohlapi_post_action(struct afb_req req) -{ - json_object *queryJ = NULL; - char * actionName = NULL; - char * audioRole = NULL; - char * mediaName = NULL; - json_object *actionContext = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{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", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - // Verify if known action for audio role - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - // Check to find specific action - int iActionFound = 0; - if (pRole->pActionList) { - int iNumberActions = pRole->pActionList->len; - char * pTargetActionName = NULL; - for ( int i = 0 ; i < iNumberActions; i++) - { - pTargetActionName = g_ptr_array_index(pRole->pActionList,i); - if ( strcasecmp(pTargetActionName,actionName)==0) { - iActionFound = 1; - break; - } - } - } - - if (!iActionFound) { - afb_req_fail_f(req, "Event not found for audio role", "Event -> %s not found for role:%s",actionName,audioRole); - return; - } - -#ifndef AHL_DISCONNECT_POLICY - // Call policy to allow custom policy actions in current context (e.g. cancel playback) - 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"); - return; - } -#endif - - afb_req_success(req, NULL, "Posted sound action"); - } - -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,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; - } - - 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)) { - 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)) { - 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)) { - 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"); - return; - } - } - - 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 -// This is a first step toward isolation, when policy is migrated in its own binding it can simply raise AGL events -// This binding will register for these policy events and will execute the code below upon event reception -PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) -{ - char * pEventName = NULL; - - int err = wrap_json_unpack(pEventDataJ,"{s:s}","event_name", &pEventName); - if(err) - { - AFB_ERROR("Unable to retrieve event name"); - return; - } - - if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) { - char * pAudioRole = NULL; - char * pPropertyName = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - json_object * propValueJ = NULL; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s,s:o,s:s}", - "endpoint_id", &endpointID, - "endpoint_type", &endpointType, - "property_name", &pPropertyName, - "value",&propValueJ, - "audio_role", &pAudioRole); - if(err) - { - AFB_ERROR("Unable to unpack property 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 = GetEndpointInfoWithRole(endpointID,endpointType,pRole); - // update property value - if ((pEndpointInfo!=NULL) && (pEndpointInfo->pPropTable!=NULL)) - { - json_type jType = json_object_get_type(propValueJ); - switch (jType) { - case json_type_double: - g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_double(json_object_get_double(propValueJ))); - break; - case json_type_int: - g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_int(json_object_get_int(propValueJ))); - break; - case json_type_string: - 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)); - return ; - } - } - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ); - } - else if(strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)==0) { - char * pAudioRole = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - int iVolume = 0; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:i,s:s}", - "endpoint_id", &endpointID, - "endpoint_type", &endpointType, - "value",&iVolume, - "audio_role", &pAudioRole); - if(err) - { - AFB_ERROR("Unable to unpack volume event data"); - return; - } - RoleInfoT * pRole = GetRole(pAudioRole); - if ( pRole == NULL ){ - AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); - return; - } - EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); - // update volume value - 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); - } - 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) { - streamID_t streamID = AHL_UNDEFINED; - StreamEventT streamEvent = STREAM_EVENT_MAXVALUE; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i}", - "stream_id", &streamID, - "state_event", &streamEvent); - if(err) - { - AFB_ERROR("Unable to unpack stream event data"); - return; - } - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); - return; - } - - // update streamstate value - switch (streamEvent) { - case STREAM_EVENT_START: - pStreamInfo->streamState = STREAM_STATE_RUNNING; - break; - case STREAM_EVENT_STOP: - pStreamInfo->streamState = STREAM_STATE_IDLE; - break; - case STREAM_EVENT_PAUSE: - pStreamInfo->streamState = STREAM_STATE_PAUSED; - break; - case STREAM_EVENT_RESUME: - pStreamInfo->streamState = STREAM_STATE_RUNNING; - break; - case STREAM_EVENT_MUTED: - pStreamInfo->streamMute = STREAM_MUTED; - break; - case STREAM_EVENT_UNMUTED: - pStreamInfo->streamMute = STREAM_UNMUTED; - break; - default: - AFB_ERROR("Unknown stream event"); - } - - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - afb_event_push(pStreamInfo->streamStateEvent,pEventDataJ); - } - else { - AFB_ERROR("Unknown event name"); - } -}
\ No newline at end of file diff --git a/src/ahl-binding.h b/src/ahl-binding.h deleted file mode 100644 index 405144d..0000000 --- a/src/ahl-binding.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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_BINDING_INCLUDE -#define AHL_BINDING_INCLUDE - -//#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 - -#define AHL_SUCCESS 0 -#define AHL_FAIL 1 - -#define AHL_ACCESS_CONTROL_GRANTED 1 -#define AHL_ACCESS_CONTROL_DENIED 0 - -#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 - int iPriority; // Role normalized priority (0-100) - InterruptBehaviorT eInterruptBehavior; // Role behavior when interrupting lower priority streams - GPtrArray * pActionList; // List of supported actions for the role (gchar*) - GPtrArray * pSourceEndpoints; // Source endpoints info (EndpointInfoT*) - GPtrArray * pSinkEndpoints; // Sink endpoints info (EndpointInfoT*) -} RoleInfoT; - -// Parts of the context that are visible to the policy (for state based decisions) -typedef struct AHLPolicyCtx { - GHashTable * pRoleInfo; // Hash table of role information structure (RoleInfoT*) accessed by role name - GHashTable * pStreams; // List of active streams (StreamInfoT*) accessed by streamID - GPtrArray * pHALList; // List of HAL dependencies - // TODO: Events need to be sent directly by HLB when separation with policy complete - struct afb_event propertyEvent; // AGL event used when property changes - struct afb_event volumeEvent; // AGL event used when volume changes - struct afb_event postActionEvent; // AGL event used on post action call -} AHLPolicyCtxT; - -// Global binding context -typedef struct AHLCtx { - AHLPolicyCtxT policyCtx; - endpointID_t nextSourceEndpointID; // Counter to assign new ID - endpointID_t nextSinkEndpointID; // Counter to assign new ID - endpointID_t nextStreamID; // Counter to assign new ID -} AHLCtxT; - -// Client specific binding context -typedef struct AHLClientCtx { - GArray * pStreamAccessList; // List of streams that client has control over -} AHLClientCtxT; - -// ahl-binding.c -PUBLIC int AhlBindingInit(); -PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ); - -// ahl-deviceenum.c -int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, EndpointTypeT in_deviceType, GPtrArray * out_pEndpointArray); -EndpointInfoT * InitEndpointInfo(); -void TermEndpointInfo( EndpointInfoT * out_pEndpointInfo ); -// ahl-config.c -int ParseHLBConfig(); -// ahl-policy.c -#ifndef AHL_DISCONNECT_POLICY -PUBLIC void audiohlapi_raise_event(json_object *EventDataJ); -#endif - -#endif // AHL_BINDING_INCLUDE diff --git a/src/ahl-config.c b/src/ahl-config.c deleted file mode 100644 index f076d14..0000000 --- a/src/ahl-config.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <string.h> -#include <json-c/json.h> -#include "wrap-json.h" -#include "ahl-binding.h" - -extern AHLCtxT g_AHLCtx; - -static InterruptBehaviorT InterruptBehaviorToEnum(char * in_pInterruptBehaviorStr) -{ - g_assert_nonnull(in_pInterruptBehaviorStr); - if (strcasecmp(in_pInterruptBehaviorStr,AHL_INTERRUPTBEHAVIOR_CONTINUE)==0) { - return INTERRUPTBEHAVIOR_CONTINUE; - } - else if (strcasecmp(in_pInterruptBehaviorStr,AHL_INTERRUPTBEHAVIOR_CANCEL)==0) { - return INTERRUPTBEHAVIOR_CANCEL; - } - else if (strcasecmp(in_pInterruptBehaviorStr,AHL_INTERRUPTBEHAVIOR_PAUSE)==0) { - return INTERRUPTBEHAVIOR_PAUSE; - } - else - return INTERRUPTBEHAVIOR_MAXVALUE; -} - -int ParseHLBConfig() { - char * versionStr = NULL; - json_object * jAudioRoles = NULL; - json_object * jHALList = NULL; - char * policyModule = NULL; - - // TODO: This should be retrieved from binding startup arguments - char configfile_path[256]; - if(getenv("AHL_CONFIG_FILE") == NULL) - { - AFB_ERROR("Please Set Environnement Variable AHL_CONFIG_FILE"); - return AHL_FAIL; - } - - sprintf(configfile_path, "%s", getenv("AHL_CONFIG_FILE")); - AFB_INFO("High-level config file -> %s\n", configfile_path); - - // Open configuration file - json_object *config_JFile=json_object_from_file(configfile_path); - if(config_JFile == NULL) - { - AFB_ERROR("Error: Can't open configuration file -> %s",configfile_path); - 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 AHL_FAIL; - } - AFB_INFO("High-level audio API version: %s", "1.0.0"); - AFB_INFO("Config version: %s", versionStr); - AFB_INFO("Policy module: %s", policyModule); - - int iHALListLength = json_object_array_length(jHALList); - g_AHLCtx.policyCtx.pHALList = g_ptr_array_new_with_free_func(g_free); - int iNumberOfRoles = json_object_array_length(jAudioRoles); - g_AHLCtx.policyCtx.pRoleInfo = g_hash_table_new(g_str_hash, g_str_equal); - - for (int i = 0; i < iHALListLength; i++) - { - char * pHAL = NULL; - json_object * jHAL = json_object_array_get_idx(jHALList,i); - if (jHAL) { - pHAL = (char *)json_object_get_string(jHAL); - char * pHALName = g_strdup( pHAL ); - g_ptr_array_add( g_AHLCtx.policyCtx.pHALList, pHALName ); - - // Set dependency on HAL specified - err = afb_daemon_require_api_v2(pHAL,1) ; - if( err != 0 ) - { - AFB_ERROR("Audio high level API could not set dependency on API: %s",pHAL); - return AHL_FAIL; - } - } - } - - for (int i = 0; i < iNumberOfRoles; i++) - { - int priority = 0; - json_object * jAudioRole = json_object_array_get_idx(jAudioRoles,i); - json_object * jOutputDevices = NULL; - json_object * jInputDevices = NULL; - json_object * jActions = NULL; - char * pRoleName = NULL; - char * pInteruptBehavior = NULL; - - int iNumOutDevices = 0; - int iNumInDevices = 0; - int iNumActions = 0; - - err = wrap_json_unpack(jAudioRole, "{s:s,s:i,s:s,s?o,s?o,s?o}", - "name", &pRoleName, - "priority",&priority, - "interupt_behavior",&pInteruptBehavior, - "output",&jOutputDevices, - "input",&jInputDevices, - "actions",&jActions - ); - if (err) { - AFB_ERROR("Invalid audio role configuration : %s", json_object_to_json_string(jAudioRole)); - return AHL_FAIL; - } - - if (jOutputDevices) - iNumOutDevices = json_object_array_length(jOutputDevices); - if (jInputDevices) - iNumInDevices = json_object_array_length(jInputDevices); - if (jActions) - iNumActions = json_object_array_length(jActions); - - RoleInfoT * pRoleInfo = (RoleInfoT*) malloc(sizeof(RoleInfoT)); - memset(pRoleInfo,0,sizeof(RoleInfoT)); - pRoleInfo->pRoleName = g_strdup( pRoleName ); - pRoleInfo->iPriority = priority; - pRoleInfo->eInterruptBehavior = InterruptBehaviorToEnum(pInteruptBehavior); - - // Actions - pRoleInfo->pActionList = g_ptr_array_new_with_free_func(g_free); - // Parse and validate list of available actions - for (int i = 0; i < iNumActions; i++) - { - json_object * jAction = json_object_array_get_idx(jActions,i); - char * pActionName = (char *)json_object_get_string(jAction); - if (pActionName) - g_ptr_array_add(pRoleInfo->pActionList, g_strdup(pActionName)); - } - - // Sources - pRoleInfo->pSourceEndpoints = g_ptr_array_new_with_free_func(g_free); - if (iNumInDevices) { - err = EnumerateDevices(jInputDevices,pRoleName,ENDPOINTTYPE_SOURCE,pRoleInfo->pSourceEndpoints); - if (err) { - AFB_ERROR("Invalid input devices : %s", json_object_to_json_string(jInputDevices)); - return AHL_FAIL; - } - } - // Sinks - pRoleInfo->pSinkEndpoints = g_ptr_array_new_with_free_func(g_free); - if (iNumOutDevices) { - err = EnumerateDevices(jOutputDevices,pRoleName,ENDPOINTTYPE_SINK,pRoleInfo->pSinkEndpoints); - if (err) { - AFB_ERROR("Invalid output devices : %s", json_object_to_json_string(jOutputDevices)); - 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 AHL_SUCCESS; -} diff --git a/src/ahl-deviceenum.c b/src/ahl-deviceenum.c deleted file mode 100644 index 763b2ca..0000000 --- a/src/ahl-deviceenum.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * 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. - */ - -#include <alsa/asoundlib.h> -#include <alsa/pcm.h> -#include "ahl-binding.h" - -extern AHLCtxT g_AHLCtx; - -// TODO: Hash from endpoint ID information instead -static endpointID_t CreateNewSourceID() -{ - endpointID_t newID = g_AHLCtx.nextSourceEndpointID; - g_AHLCtx.nextSourceEndpointID++; - return newID; -} - -// TODO: Hash from endpoint ID information instead -static endpointID_t CreateNewSinkID() -{ - endpointID_t newID = g_AHLCtx.nextSinkEndpointID; - g_AHLCtx.nextSinkEndpointID++; - return newID; -} - -// Watchout: This function uses strtok and is destructive on the input string (use a copy) -static int SeparateDomainFromDeviceURI( char * in_pDeviceURI, char ** out_pDomain, char ** out_pDevice) -{ - *out_pDomain = strtok(in_pDeviceURI, "."); - if (*out_pDomain == NULL) - { - AFB_ERROR("Error tokenizing device URI -> %s",in_pDeviceURI); - return 1; - } - // TODO: Validate domain is known string (e.g. ALSA,Pulse,GStreamer) - *out_pDevice = strtok(NULL, "."); - if (*out_pDevice == NULL) - { - AFB_ERROR("Error tokenizing device URI -> %s",in_pDeviceURI); - return 1; - } - return AHL_SUCCESS; -} - -static int IsAlsaDomain(const char * in_pDomainStr) -{ - return (int) (strcasecmp(in_pDomainStr,AHL_DOMAIN_ALSA) == 0); -} - -static int IsPulseDomain(const char * in_pDomainStr) -{ - return (int) (strcasecmp(in_pDomainStr,AHL_DOMAIN_PULSE) == 0); -} - -static int IsGStreamerDomain(const char * in_pDomainStr) -{ - return (int) (strcasecmp(in_pDomainStr,AHL_DOMAIN_GSTREAMER) == 0); -} - -static int IsExternalDomain(const char * in_pDomainStr) -{ - return (int) (strcasecmp(in_pDomainStr,AHL_DOMAIN_EXTERNAL) == 0); -} - -static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndpointInfo ) -{ - g_assert_nonnull(in_pPcmHandle); - g_assert_nonnull(out_pEndpointInfo); - snd_pcm_type_t pcmType = 0; - snd_pcm_info_t * pPcmInfo = NULL; - int iAlsaRet = 0; - const char * pCardName = NULL; - snd_ctl_t * ctlHandle = NULL; - snd_ctl_card_info_t * ctlInfo = NULL; - - snd_pcm_info_alloca(&pPcmInfo); - snd_ctl_card_info_alloca(&ctlInfo); - - // retrieve PCM type - pcmType = snd_pcm_type(in_pPcmHandle); - switch (pcmType) { - case SND_PCM_TYPE_HW: - out_pEndpointInfo->deviceURIType = DEVICEURITYPE_ALSA_HW; - break; - case SND_PCM_TYPE_DMIX: - out_pEndpointInfo->deviceURIType = DEVICEURITYPE_ALSA_DMIX; - break; - case SND_PCM_TYPE_SOFTVOL: - out_pEndpointInfo->deviceURIType = DEVICEURITYPE_ALSA_SOFTVOL; - break; - case SND_PCM_TYPE_PLUG: - out_pEndpointInfo->deviceURIType = DEVICEURITYPE_ALSA_PLUG; - break; - default: - out_pEndpointInfo->deviceURIType = DEVICEURITYPE_ALSA_OTHER; - break; - } - - iAlsaRet = snd_pcm_info(in_pPcmHandle,pPcmInfo); - if (iAlsaRet < 0) - { - AFB_WARNING("Error retrieving PCM device info"); - return AHL_FAIL; - } - - // get card number - out_pEndpointInfo->alsaInfo.cardNum = snd_pcm_info_get_card(pPcmInfo); - if ( out_pEndpointInfo->alsaInfo.cardNum < 0 ) - { - AFB_WARNING("No Alsa card number available"); - return AHL_FAIL; - } - - // get device number - out_pEndpointInfo->alsaInfo.deviceNum = snd_pcm_info_get_device(pPcmInfo); - if ( out_pEndpointInfo->alsaInfo.deviceNum < 0 ) - { - AFB_WARNING("No Alsa device number available"); - return AHL_FAIL; - } - - // get sub-device number - out_pEndpointInfo->alsaInfo.subDeviceNum = snd_pcm_info_get_subdevice(pPcmInfo); - if ( out_pEndpointInfo->alsaInfo.subDeviceNum < 0 ) - { - AFB_WARNING("No Alsa subdevice number available"); - return AHL_FAIL; - } - - char cardName[32]; - sprintf(cardName, "hw:%d", out_pEndpointInfo->alsaInfo.cardNum); - iAlsaRet = snd_ctl_open(&ctlHandle, cardName, 0); - if ( iAlsaRet < 0 ) - { - AFB_WARNING("Could not open ALSA card control"); - return AHL_FAIL; - } - - iAlsaRet = snd_ctl_card_info(ctlHandle, ctlInfo); - if ( iAlsaRet < 0 ) - { - AFB_WARNING("Could not retrieve ALSA card info"); - snd_ctl_close(ctlHandle); - return AHL_FAIL; - } - - // Populate unique target card name - pCardName = snd_ctl_card_info_get_id(ctlInfo); - if (pCardName == NULL) - { - AFB_WARNING("No Alsa card name available"); - snd_ctl_close(ctlHandle); - return AHL_FAIL; - } - g_strlcpy(out_pEndpointInfo->gsDeviceName,pCardName,AHL_STR_MAX_LENGTH); - - snd_ctl_close(ctlHandle); - - return AHL_SUCCESS; -} - -EndpointInfoT * InitEndpointInfo() -{ - EndpointInfoT * pEndpointInfo = (EndpointInfoT*) malloc(sizeof(EndpointInfoT)); - memset(pEndpointInfo,0,sizeof(EndpointInfoT)); - pEndpointInfo->endpointID = AHL_UNDEFINED; - pEndpointInfo->type = ENDPOINTTYPE_MAXVALUE; - pEndpointInfo->deviceURIType = DEVICEURITYPE_MAXVALUE; - pEndpointInfo->alsaInfo.cardNum = AHL_UNDEFINED; - pEndpointInfo->alsaInfo.deviceNum = AHL_UNDEFINED; - pEndpointInfo->alsaInfo.subDeviceNum = AHL_UNDEFINED; - 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; -} - -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->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 - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, out_pEndpointInfo->pPropTable); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (value) - json_object_put(value); - } - g_hash_table_remove_all(out_pEndpointInfo->pPropTable); - g_hash_table_destroy(out_pEndpointInfo->pPropTable); - out_pEndpointInfo->pPropTable = NULL; - } - // GLib automatically frees item when removed from the array -} - -// For a given audio role -int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, EndpointTypeT in_deviceType, GPtrArray * out_pEndpointArray) { - - g_assert_nonnull(in_jDeviceArray); - int iNumberDevices = json_object_array_length(in_jDeviceArray); - - // Parse and validate list of available devices - for (int i = 0; i < iNumberDevices; i++) - { - char * pDeviceURIDomain = NULL; - char * pFullDeviceURI = NULL; - char * pDeviceURIPCM = NULL; - int err = AHL_SUCCESS; - - json_object * jDevice = json_object_array_get_idx(in_jDeviceArray,i); - if (jDevice == NULL) { - AFB_WARNING("Invalid device array -> %s",json_object_to_json_string(in_jDeviceArray)); - continue; - } - // strip domain name from URI - pFullDeviceURI = (char *)json_object_get_string(jDevice); - char * pFullDeviceURICopy = g_strdup(pFullDeviceURI); // strtok is destructive - err = SeparateDomainFromDeviceURI(pFullDeviceURICopy,&pDeviceURIDomain,&pDeviceURIPCM); - if (err) - { - AFB_WARNING("Invalid device URI string -> %s",pFullDeviceURICopy); - continue; - } - - EndpointInfoT * pEndpointInfo = InitEndpointInfo(); - g_assert_nonnull(pEndpointInfo); - - // 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 - 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; - pDeviceURIDomain = NULL; //Derived from above mem - pDeviceURIPCM = NULL; //Derived from above mem - - if (IsAlsaDomain(pEndpointInfo->gsDeviceDomain)) - { - // TODO: Missing support for loose name matching - // This will require using ALSA hints to get PCM names - // And would iterate over all available devices matching string (possibly all if no filtering is desired for a certain role) - - // Get PCM handle - snd_pcm_t * pPcmHandle = NULL; - snd_pcm_stream_t streamType = in_deviceType == ENDPOINTTYPE_SOURCE ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; - err = snd_pcm_open(&pPcmHandle, pEndpointInfo->gsDeviceURI, streamType, 0); - if (err < 0) - { - AFB_NOTICE("Alsa PCM device was not found -> %s", pEndpointInfo->gsDeviceURI); - continue; - } - - err = FillALSAPCMInfo(pPcmHandle,pEndpointInfo); - if (err) { - AFB_WARNING("Unable to retrieve PCM information for PCM -> %s",pEndpointInfo->gsDeviceURI); - snd_pcm_close(pPcmHandle); - continue; - } - - snd_pcm_close(pPcmHandle); - } - else if (IsPulseDomain(pEndpointInfo->gsDeviceDomain)) { - // Pulse domain - // For now display name is device URI directly, could extrapolated using more heuristics or even usins Pulse API later on - pEndpointInfo->deviceURIType = DEVICEURITYPE_NOT_ALSA; - } - else if (IsGStreamerDomain(pEndpointInfo->gsDeviceDomain)){ - // GStreamer domain - // For now display name is device URI directly, could extrapolated using more heuristics or even usins GStreamer API later on - pEndpointInfo->deviceURIType = DEVICEURITYPE_NOT_ALSA; - } - else if (IsExternalDomain(pEndpointInfo->gsDeviceDomain)){ - // External domain - pEndpointInfo->deviceURIType = DEVICEURITYPE_NOT_ALSA; - } - else { - // Unknown domain - AFB_WARNING("Unknown domain in device URI string -> %s",pFullDeviceURI); - continue; - } - - pEndpointInfo->endpointID = in_deviceType == ENDPOINTTYPE_SOURCE ? CreateNewSourceID() : CreateNewSinkID(); - pEndpointInfo->type = in_deviceType; - - // add to structure to list of available devices - g_ptr_array_add(out_pEndpointArray, pEndpointInfo); - - } // for all devices - - AFB_DEBUG ("Audio high-level - Enumerate devices done"); - return AHL_SUCCESS; -}
\ No newline at end of file diff --git a/src/ahl-interface.h b/src/ahl-interface.h deleted file mode 100644 index fc0ac68..0000000 --- a/src/ahl-interface.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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_INTERFACE_INCLUDE -#define AHL_INTERFACE_INCLUDE - -///// API ///// - -// Endpoint types -#define AHL_ENDPOINTTYPE_SOURCE "source" // source devices -#define AHL_ENDPOINTTYPE_SINK "sink" // sink devices - -// Stream state -#define AHL_STREAM_STATE_IDLE "idle" // Stream is inactive -#define AHL_STREAM_STATE_RUNNING "running" // Stream is active and running -#define AHL_STREAM_STATE_PAUSED "paused" // Stream is active but paused - -// Stream mute state -#define AHL_STREAM_UNMUTED "off" // Stream is not muted -#define AHL_STREAM_MUTED "on" // Stream is muted - -// Property/Volume/Action events -#define AHL_ENDPOINT_PROPERTY_EVENT "ahl_endpoint_property_event" -#define AHL_ENDPOINT_VOLUME_EVENT "ahl_endpoint_volume_event" -#define AHL_POST_ACTION_EVENT "ahl_post_action" -#define AHL_STREAM_STATE_EVENT "ahl_stream_state_event" - -// Stream state event types -#define AHL_STREAM_EVENT_START "start" // Stream is inactive -#define AHL_STREAM_EVENT_STOP "stop" // Stream is running -#define AHL_STREAM_EVENT_PAUSE "pause" // Audio stream paused -#define AHL_STREAM_EVENT_RESUME "resume" // Audio stream resumed -#define AHL_STREAM_EVENT_MUTE "mute" // Audio stream muted -#define AHL_STREAM_EVENT_UNMUTE "unmute" // Audio stream unmuted - -///// Interpret returned or configuration information ///// - -// Known audio domain string definitions (for configuration file format and device URI interpretation) -#define AHL_DOMAIN_ALSA "alsa" -#define AHL_DOMAIN_PULSE "pulse" -#define AHL_DOMAIN_GSTREAMER "gstreamer" -#define AHL_DOMAIN_EXTERNAL "external" - -// ALSA Device URI type -#define AHL_DEVICEURITYPE_ALSA_HW "hw" // Alsa hardware device URI -#define AHL_DEVICEURITYPE_ALSA_DMIX "dmix" // Alsa Dmix device URI (only for playback devices) -#define AHL_DEVICEURITYPE_ALSA_DSNOOP "dsnoop" // Alsa DSnoop device URI (only for capture devices) -#define AHL_DEVICEURITYPE_ALSA_SOFTVOL "softvol" // Alsa softvol device URI -#define AHL_DEVICEURITYPE_ALSA_PLUG "plug" // Alsa plug device URI -#define AHL_DEVICEURITYPE_ALSA_OTHER "other" // Alsa domain URI device of unspecified type -#define AHL_DEVICEURITYPE_NOT_ALSA "nonalsa" - -// Define default behavior of audio role when interrupting lower priority sources (in configuration) -#define AHL_INTERRUPTBEHAVIOR_CONTINUE "continue" // Continue to play when interrupted (e.g. media may be ducked) -#define AHL_INTERRUPTBEHAVIOR_CANCEL "cancel" // Abort playback when interrupted (e.g. non-important HMI feedback that does not make sense later) -#define AHL_INTERRUPTBEHAVIOR_PAUSE "pause" // Pause source when interrupted, to be resumed afterwards (e.g. non-temporal guidance) - -///// Naming convention ///// - -// Standardized name for common audio roles (not enforced in any way, just helps compatibility) -#define AHL_ROLE_WARNING "warning" // Safety-relevant or critical alerts/alarms -#define AHL_ROLE_GUIDANCE "guidance" // Important user information where user action is expected (e.g. navigation instruction) -#define AHL_ROLE_NOTIFICATION "notification" // HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...) -#define AHL_ROLE_COMMUNICATION "communication" // Voice communications (e.g. handsfree, speech recognition) -#define AHL_ROLE_ENTERTAINMENT "entertainment" // Multimedia content (e.g. tuner, media player, etc.) -#define AHL_ROLE_SYSTEM "system" // System level content or development -#define AHL_ROLE_STARTUP "startup" // Early (startup) sound -#define AHL_ROLE_SHUTDOWN "shutdown" // Late (shutdown) sound -#define AHL_ROLE_NONE "none" // Non-assigned / legacy applications - -// Standardized list of properties (not enforced in any way, just helps compatibility) -#define AHL_PROPERTY_BALANCE "balance" -#define AHL_PROPERTY_FADE "fade" -#define AHL_PROPERTY_EQ_LOW "eq_bass" -#define AHL_PROPERTY_EQ_MID "eq_mid" -#define AHL_PROPERTY_EQ_HIGH "eq_treble" - -// Standardized list of events (not enforced in any way, just helps compatibility) -#define AHL_EVENTS_PLAYSOUND "play_sound" -#define AHL_EVENTS_ECHOCANCEL_ENABLE "echocancel_enable" -#define AHL_EVENTS_ECHOCANCEL_DISABLE "echocancel_disable" - -#endif // AHL_INTERFACE_INCLUDE diff --git a/src/ahl-json.c b/src/ahl-json.c deleted file mode 100644 index 5e8bf97..0000000 --- a/src/ahl-json.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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/src/ahl-json.h b/src/ahl-json.h deleted file mode 100644 index ffd683a..0000000 --- a/src/ahl-json.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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/src/ahl-policy-utils.c b/src/ahl-policy-utils.c deleted file mode 100755 index 195c591..0000000 --- a/src/ahl-policy-utils.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 "ahl-policy-utils.h" -#include "wrap-json.h" -#include <json-c/json.h> - -void Add_Endpoint_Property_Double( json_object * io_pPropertyArray, char * in_pPropertyName, double in_dPropertyValue) -{ - 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( json_object * io_pPropertyArray, char * in_pPropertyName, int in_iPropertyValue) -{ - 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( json_object * io_pPropertyArray, char * in_pPropertyName, const char * in_pPropertyValue) -{ - 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 EndpointToJSON(EndPointInterfaceInfoT * pEndpoint, json_object **ppEndpointJ) -{ - if(ppEndpointJ == NULL || pEndpoint == NULL) - { - AFB_ERROR("Invalid EndpointToJSON arguments"); - return AHL_POLICY_UTIL_FAIL; - } - - // 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(*ppEndpointJ)); - return AHL_POLICY_UTIL_SUCCESS; -} - -int StreamToJSON(StreamInterfaceInfoT * pStream, json_object **ppStreamJ) -{ - if(pStream == NULL) - { - AFB_ERROR("Invalid arguments to StreamToJSON, stream structure is NULL"); - return AHL_POLICY_UTIL_FAIL; - } - - 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 - 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 Stream, =%s", wrap_json_get_error_string(err)); - return AHL_POLICY_UTIL_FAIL; - } - - AFB_DEBUG("JSON stream information=%s", json_object_get_string(*ppStreamJ)); - - return AHL_POLICY_UTIL_SUCCESS; -} - -//pEndpointInterfaceInfo must be pre-allocated by the caller -int JSONToEndpoint(json_object *pEndpointJ, EndPointInterfaceInfoT *pEndpoint) -{ - if(pEndpointJ == NULL || pEndpoint == NULL) - { - AFB_ERROR("Invalid arguments for JSONToEndpoint"); - return AHL_POLICY_UTIL_FAIL; - } - - //Unpack Endpoint - 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; - } - return AHL_POLICY_UTIL_SUCCESS; -} - -int JSONToStream(json_object *pStreamJ, StreamInterfaceInfoT * pStream) -{ - if(pStreamJ == NULL || pStream == NULL) - { - 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: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 - ); - - if (err) { - AFB_ERROR("Unable to parse JSON stream information=%s", json_object_get_string(pStreamJ)); - return AHL_POLICY_UTIL_FAIL; - } - - err = JSONToEndpoint(pEndpointJ,&pStream->endpoint); - if (err) { - return AHL_POLICY_UTIL_FAIL; - } - return AHL_POLICY_UTIL_SUCCESS; -} -
\ No newline at end of file diff --git a/src/ahl-policy-utils.h b/src/ahl-policy-utils.h deleted file mode 100755 index 3c20020..0000000 --- a/src/ahl-policy-utils.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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_UTILS_INCLUDE -#define AHL_POLICY_UTILS_INCLUDE - -#include <json-c/json.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; - -typedef enum StreamEvent { - STREAM_EVENT_START = 0, // Stream is inactive - STREAM_EVENT_STOP, // Stream is running - STREAM_EVENT_PAUSE, // Audio stream paused - STREAM_EVENT_RESUME, // Audio stream resumed - STREAM_EVENT_MUTED, // Audio stream muted - STREAM_EVENT_UNMUTED, // Audio stream unmuted - STREAM_EVENT_MAXVALUE // Enum count, keep at the end -} StreamEventT; - -typedef enum StreamMute { - STREAM_UNMUTED = 0, // Stream is not muted - STREAM_MUTED, // Stream is muted - STREAM_MUTE_MAXVALUE, // Enum count, keep at the end -} StreamMuteT; - -typedef enum EndpointType { - ENDPOINTTYPE_SOURCE = 0, // source devices - ENDPOINTTYPE_SINK, // sink devices - ENDPOINTTYPE_MAXVALUE // Enum count, keep at the end -} EndpointTypeT; - -typedef enum StreamState { - STREAM_STATE_IDLE = 0, // Stream is inactive - STREAM_STATE_RUNNING, // Stream is active and running - STREAM_STATE_PAUSED, // Stream is active but paused - STREAM_STATE_MAXVALUE // Enum count, keep at the end -} StreamStateT; - -// Define default behavior of audio role when interrupting lower priority sources -typedef enum InterruptBehavior { - INTERRUPTBEHAVIOR_CONTINUE = 0, // Continue to play lower priority source when interrupted (e.g. media may be ducked) - INTERRUPTBEHAVIOR_CANCEL, // Abort playback of lower priority source when interrupted (e.g. non-important HMI feedback that does not make sense later) - INTERRUPTBEHAVIOR_PAUSE, // Pause lower priority source when interrupted, to be resumed afterwards (e.g. non-temporal guidance) - INTERRUPTBEHAVIOR_MAXVALUE, // Enum count, keep at the end -} InterruptBehaviorT; - -typedef enum DeviceURIType { - DEVICEURITYPE_ALSA_HW = 0, // Alsa hardware device URI - DEVICEURITYPE_ALSA_DMIX, // Alsa Dmix device URI (only for playback devices) - DEVICEURITYPE_ALSA_DSNOOP, // Alsa DSnoop device URI (only for capture devices) - DEVICEURITYPE_ALSA_SOFTVOL, // Alsa softvol device URI - DEVICEURITYPE_ALSA_PLUG, // Alsa plug device URI - DEVICEURITYPE_ALSA_OTHER, // Alsa domain URI device of unspecified type - DEVICEURITYPE_NOT_ALSA, // Unknown (not ALSA domain) - DEVICEURITYPE_MAXVALUE // Enum count, keep at the end -} DeviceURITypeT; - -// CPU endianness assumed in all formats -typedef enum SampleType { - AHL_FORMAT_UNKNOWN = -1, // Unknown - AHL_FORMAT_U8 = 0, // Unsigned 8 bit - AHL_FORMAT_S16, // Signed 16 bit Little Endian - AHL_FORMAT_S24, // Signed 24 bit Little Endian using low three bytes in 32-bit word - AHL_FORMAT_S32, // Signed 32 bit Little Endian - AHL_FORMAT_FLOAT, // Float 32 bit Little Endian, Range -1.0 to 1.0 - AHL_FORMAT_FLOAT64, // Float 64 bit Little Endian, Range -1.0 to 1.0 - AHL_FORMAT_IEC958, // IEC-958 Little Endian (SPDIF) - AHL_FORMAT_MU_LAW, // Mu-Law - AHL_FORMAT_A_LAW, // A-Law - AHL_FORMAT_IMA_ADPCM, // Ima-ADPCM - AHL_FORMAT_MPEG, // MPEG - AHL_FORMAT_GSM, // GSM - AHL_FORMAT_G723, // G723 - AHL_FORMAT_DSD, // Direct stream digital - AHL_FORMAT_MAXVALUE, // Enum count, keep at the end -} SampleTypeT; - -typedef struct AudioFormat { - int sampleRate; // Sample rate - int numChannels; // Number of channels - SampleTypeT sampleType; // Sample type - // TODO: Interleaving? - // TODO: Sample sub format? -} AudioFormatT; - -typedef struct AlsaDeviceInfo { - int cardNum; // HW card number - int deviceNum; // HW device number - int subDeviceNum; // HW sub device number -} AlsaDeviceInfoT; - -typedef enum EndpointSelectionMode { - ENDPOINTSELMODE_AUTO = 0, // Automatic endpoint selection based on config priority - ENDPOINTSELMODE_MANUAL, // Explicit endpoint selection - ENDPOINTSELMODEMAXVALUE, // Enum count, keep at the end -} EndpointSelectionModeT; - -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) - 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). - json_object *pPropTableJ; //Property Table -} EndPointInterfaceInfoT; - -typedef struct StreamInterfaceInfo { - streamID_t streamID; // Stream unique ID - StreamStateT streamState; // Stream activity state - StreamMuteT streamMute; // Stream mute state - 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) - 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/src/ahl-policy.c b/src/ahl-policy.c deleted file mode 100644 index 4a34ed8..0000000 --- a/src/ahl-policy.c +++ /dev/null @@ -1,1188 +0,0 @@ -/* - * 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. - */ - -#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 - SYSTEM_SHUTDOWN, // ShutDown - SYSTEM_NORMAL, // Normal - SYSTEM_LOW_POWER, // Low Power, save mode - SYSTEM_MAXVALUE // Enum count, keep at the end -} SystemStateT; - -typedef struct HalInfo { - char *pDevID; - char *pAPIName; - char *pDisplayName; -} HalInfoT; - -typedef struct StreamConfig { - int iNbMaxStream; - int iVolumeInit; - int iVolumeDuckValue; -} StreamConfigT; - -// Global Policy Local context -typedef struct PolicyLocalCtx { - GArray * pSourceEndpoints; // List of Source Endpoint with playing stream or interrupted stream - GArray * pSinkEndpoints; // List of Sink Endpoint with playing stream or interrupted stream - GPtrArray * pHALList; - SystemStateT systemState; -} PolicyLocalCtxT; - -// Policy context -PolicyLocalCtxT g_PolicyCtx; - -// Helper Functions -static int getStreamConfig(char *pAudioRole, StreamConfigT *pStreamConfig) -{ - if(pAudioRole == NULL || pStreamConfig==NULL) - { - return POLICY_FAIL; - } - - if ( strcasecmp(pAudioRole,AHL_ROLE_WARNING) == 0 ) - { - pStreamConfig->iNbMaxStream = 4; - pStreamConfig->iVolumeInit = 80; - pStreamConfig->iVolumeDuckValue = 0; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_GUIDANCE) == 0 ) - { - pStreamConfig->iNbMaxStream = 10; - pStreamConfig->iVolumeInit = 70; - pStreamConfig->iVolumeDuckValue = 30; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_NOTIFICATION) == 0 ) - { - pStreamConfig->iNbMaxStream = 4; - pStreamConfig->iVolumeInit = 80; - pStreamConfig->iVolumeDuckValue = 10; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_COMMUNICATION) == 0 ) - { - pStreamConfig->iNbMaxStream = 10; - pStreamConfig->iVolumeInit = 70; - pStreamConfig->iVolumeDuckValue = 10; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_ENTERTAINMENT) == 0 ) - { - pStreamConfig->iNbMaxStream = MAX_ACTIVE_STREAM_POLICY; - pStreamConfig->iVolumeInit = 60; - pStreamConfig->iVolumeDuckValue = 40; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_SYSTEM) == 0 ) - { - pStreamConfig->iNbMaxStream = 2; - pStreamConfig->iVolumeInit = 100; - pStreamConfig->iVolumeDuckValue = 0; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_STARTUP) == 0 ) - { - pStreamConfig->iNbMaxStream = 1; - pStreamConfig->iVolumeInit = 90; - pStreamConfig->iVolumeDuckValue = 0; - } - else if ( strcasecmp(pAudioRole,AHL_ROLE_SHUTDOWN) == 0 ) - { - pStreamConfig->iNbMaxStream = 1; - pStreamConfig->iVolumeInit = 90; - pStreamConfig->iVolumeDuckValue = 0; - } - return POLICY_SUCCESS; -} - -static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName, char *AudioRole, DeviceURITypeT deviceType, int iVolume, bool bMute) -{ - if(pHalApiName == NULL || (strcasecmp(pHalApiName, AHL_POLICY_UNDEFINED_HALNAME) == 0)) - { - AFB_WARNING("SetVolume cannot be accomplished without proper HAL association"); - return POLICY_FAIL; - } - - if(AudioRole == NULL) - { - AFB_ERROR("Invalid AudioRole : %s",AudioRole); - return POLICY_FAIL; - } - - // Using audio role available from endpoint to target the right HAL control (build string based on convention) - GString * gsHALControlName = NULL; - switch(deviceType) - { - case DEVICEURITYPE_ALSA_HW: - gsHALControlName = g_string_new("Master_Playback_Volume"); - break; - case DEVICEURITYPE_ALSA_DMIX: - case DEVICEURITYPE_ALSA_DSNOOP: - case DEVICEURITYPE_ALSA_PLUG: - case DEVICEURITYPE_ALSA_SOFTVOL: - gsHALControlName = g_string_new(AudioRole); - if(bMute == false) - { - AFB_DEBUG("Using ramp"); - g_string_append(gsHALControlName,"_Ramp"); - } - else - { - AFB_DEBUG("Not using ramp"); - g_string_append(gsHALControlName,"_Vol"); // no ramping - } - break; - default: - // 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 = NULL, *j_query = NULL; - - // Package query - int err = wrap_json_pack(&j_query,"{s:s,s:i}","label",gsHALControlName->str, "val",iVolume); - if (err) - { - AFB_ERROR("Invalid query for HAL ctlset: %s with errorcode: %i",json_object_to_json_string(j_query), err); - return POLICY_FAIL; - } - - // TODO: implement Volume limitation based on policy - - // Set the volume using the HAL - err = afb_service_call_sync(pHalApiName, "ctlset", j_query, &j_response); - if (err) - { - AFB_ERROR("Could not ctlset on HAL: %s with errorcode: %i",pHalApiName, err); - return POLICY_FAIL; - } - AFB_DEBUG("HAL ctlset response=%s", json_object_to_json_string(j_response)); - - if (bMute == false) { - // Package event data - json_object * eventDataJ = NULL; - err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i,s:i,s:s}","event_name", AHL_ENDPOINT_VOLUME_EVENT,"endpoint_id", iEndpointID, "endpoint_type", iEndpointType,"value",iVolume, "audio_role", AudioRole); - if (err) - { - AFB_ERROR("Invalid event data for volume event %s with errorcode: %i",json_object_to_json_string(eventDataJ), err); - return POLICY_FAIL; - } - - audiohlapi_raise_event(eventDataJ); - } - - return POLICY_SUCCESS; -} - -static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName, char *AudioRole, DeviceURITypeT deviceType, int *pVolume) -{ - GString * gsHALControlName = NULL; - - // Using audio role available from endpoint to target the right HAL control (build string based on convention) - switch(deviceType) - { - case DEVICEURITYPE_ALSA_HW: - gsHALControlName = g_string_new("Master_Playback_Volume"); - break; - case DEVICEURITYPE_ALSA_DMIX: - case DEVICEURITYPE_ALSA_DSNOOP: - case DEVICEURITYPE_ALSA_PLUG: - case DEVICEURITYPE_ALSA_SOFTVOL: - gsHALControlName = g_string_new(AudioRole); - g_string_append(gsHALControlName,"_Vol"); // Return target value - break; - default: - // Set volume to zero for display purpose only. - // Not supported yet - *pVolume = 0; - AFB_WARNING("Can't get volume on HAL: %s for device type: %d",pHalApiName,deviceType); - return POLICY_FAIL; - } - - // Set endpoint volume using HAL services (leveraging ramps etc.) - json_object *j_response = NULL, *j_query = NULL; - - // Package query - int err = wrap_json_pack(&j_query,"{s:s}","label",gsHALControlName->str); - if (err) - { - AFB_WARNING("Invalid query for HAL ctlset: %s, errorcode: %i",json_object_to_json_string(j_query),err); - return POLICY_FAIL; - } - - // Get the volume using the HAL - err = afb_service_call_sync(pHalApiName, "ctlget", j_query, &j_response); - if (err) - { - AFB_WARNING("Could not ctlset on HAL: %s, errorcode: %i",pHalApiName, err); - return POLICY_FAIL; - } - AFB_DEBUG("HAL ctlget response=%s", json_object_to_json_string(j_response)); - - // Parse response - json_object * jRespObj = NULL; - json_object_object_get_ex(j_response, "response", &jRespObj); - json_object * jVal = NULL; - int val1 = 0, val2 = 0; // Why 2 values? - - json_object_object_get_ex(jRespObj, "val", &jVal); - int nbElement = json_object_array_length(jVal); - if(nbElement == 2) - { - err = wrap_json_unpack(jVal, "[ii]", &val1, &val2); - if (err) { - AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); - return POLICY_FAIL; - } - } - else - { - err = wrap_json_unpack(jVal, "[i]", &val1); - if (err) { - AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); - return POLICY_FAIL; - } - } - - *pVolume = val1; - - // Package event data - json_object * eventDataJ = NULL; - err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i,s:i,s:s}","event_name", AHL_ENDPOINT_VOLUME_EVENT,"endpoint_id", iEndpointID, "endpoint_type", iEndpointType,"value",*pVolume, "audio_role", AudioRole); - if (err) - { - AFB_ERROR("Invalid event data for volume event %s with errorcode: %i",json_object_to_json_string(eventDataJ), err); - return POLICY_FAIL; - } - - audiohlapi_raise_event(eventDataJ); - - return POLICY_SUCCESS; -} - -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) - { - AFB_ERROR("Invalid event data for stream state event: %s",json_object_to_json_string(eventDataJ)); - } - else - { - audiohlapi_raise_event(eventDataJ); - } -} - -static EndPointPolicyInfoT *PolicySearchEndPoint(EndpointTypeT type, char *pDeviceName) -{ - GArray *pcurEndpointArray = NULL; - - if(type==ENDPOINTTYPE_SINK) - { - pcurEndpointArray = g_PolicyCtx.pSinkEndpoints; - } - else - { - pcurEndpointArray = g_PolicyCtx.pSourceEndpoints; - } - - for(int i=0; i<pcurEndpointArray->len; i++) - { - EndPointPolicyInfoT * pCurEndpoint = &g_array_index(pcurEndpointArray,EndPointPolicyInfoT,i); - - if(strcasecmp(pCurEndpoint->pDeviceName,pDeviceName)==0) - { - return pCurEndpoint; - } - } - - return NULL; -} - -static int PolicyAddEndPoint(StreamInterfaceInfoT *pStreamInfo) -{ - EndPointPolicyInfoT *pPolicyEndPoint = PolicySearchEndPoint(pStreamInfo->endpoint.type, pStreamInfo->endpoint.gsDeviceName); - if(pPolicyEndPoint == NULL) - { - //create EndPoint and add playing stream - EndPointPolicyInfoT newEndPointPolicyInfo; - 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); - } - else - { - g_array_append_val(g_PolicyCtx.pSourceEndpoints, newEndPointPolicyInfo); - } - - } - return POLICY_SUCCESS; -} - -static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInterfaceInfoT *pStreamInfo) -{ - StreamPolicyInfoT newStreamPolicyInfo; - - newStreamPolicyInfo.streamID = pStreamInfo->streamID; - newStreamPolicyInfo.RolePriority = pStreamInfo->iPriority; - newStreamPolicyInfo.pAudioRole = pStreamInfo->pRoleName; - newStreamPolicyInfo.interruptBehavior = pStreamInfo->eInterruptBehavior; - newStreamPolicyInfo.iDuckVolume = 0; - g_array_append_val(pCurrEndPointPolicy->streamInfo, newStreamPolicyInfo); - return POLICY_SUCCESS; -} - -static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,StreamInterfaceInfoT * pStreamInfo) -{ - int err=0; - if(pCurrEndPointPolicy == NULL || pCurrEndPointPolicy->streamInfo->len == 0) - { - AFB_ERROR("StreamID not found in active endpoint when running to idle transition is requested"); - return POLICY_FAIL; - } - // Search for the matching stream - for(int i=0; i<pCurrEndPointPolicy->streamInfo->len; i++) - { - StreamPolicyInfoT currentPolicyStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,i); - if(currentPolicyStreamInfo.streamID == pStreamInfo->streamID) - { - //remove the current stream - g_array_remove_index(pCurrEndPointPolicy->streamInfo, i); - if(pCurrEndPointPolicy->streamInfo->len > 0) //need to unduck - { - //check the last element(Akways highest priority) - StreamPolicyInfoT HighPriorityStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,pCurrEndPointPolicy->streamInfo->len-1); - switch(currentPolicyStreamInfo.interruptBehavior) - { - case INTERRUPTBEHAVIOR_CONTINUE: - //unduck and set Volume back to original value - err = PolicySetVolume(pCurrEndPointPolicy->endpointID, - pCurrEndPointPolicy->type, - pCurrEndPointPolicy->pHalApiName, - HighPriorityStreamInfo.pAudioRole, - pCurrEndPointPolicy->deviceType, - HighPriorityStreamInfo.iDuckVolume, - false); - if(err) - { - return POLICY_FAIL; - } - - return POLICY_SUCCESS; - case INTERRUPTBEHAVIOR_PAUSE: - PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_RESUME); - return POLICY_SUCCESS; - case INTERRUPTBEHAVIOR_CANCEL: - PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_START); - return POLICY_SUCCESS; - default: - AFB_ERROR("Unsupported Intterupt Behavior"); - return POLICY_FAIL; - } - } - } - } - return POLICY_SUCCESS; -} - -static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInterfaceInfoT * pStreamInfo) -{ - int err=0; - if(pCurrEndPointPolicy->streamInfo == NULL) - { - AFB_ERROR("pCurrEndPointPolicy->streamInfo is null on an active endpoint"); - return POLICY_FAIL; - } - - if(pCurrEndPointPolicy->streamInfo->len == 0) //No stream is playing on this endpoint - { - PolicyAddStream(pCurrEndPointPolicy, pStreamInfo); - } - else //Interrupt case - { - //check the last element - StreamPolicyInfoT *pCurrentActiveStreamInfo = &g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,pCurrEndPointPolicy->streamInfo->len-1); - g_assert_nonnull(pCurrentActiveStreamInfo); - if(pStreamInfo->iPriority >= pCurrentActiveStreamInfo->RolePriority) - { - switch(pStreamInfo->eInterruptBehavior) - { - case INTERRUPTBEHAVIOR_CONTINUE: - //Save the current Volume and set the docking volume - pCurrentActiveStreamInfo->iDuckVolume = pStreamInfo->endpoint.iVolume; - StreamConfigT StreamConfig; - err = getStreamConfig(pStreamInfo->pRoleName, &StreamConfig); - if(err == POLICY_FAIL) - { - AFB_ERROR("Error getting stream configuration for audiorole: %s", pStreamInfo->pRoleName); - return POLICY_FAIL; - } - err = PolicySetVolume(pCurrEndPointPolicy->endpointID, - pCurrEndPointPolicy->type, - pCurrEndPointPolicy->pHalApiName, - pCurrentActiveStreamInfo->pAudioRole, - pCurrEndPointPolicy->deviceType, - StreamConfig.iVolumeDuckValue, - false); - if(err) - { - AFB_ERROR("Set Volume return with errorcode%i for streamID: %i and Hal:%s", err, pCurrentActiveStreamInfo->streamID, pCurrEndPointPolicy->pHalApiName); - return POLICY_FAIL; - } - break; - 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); - break; - default: - AFB_ERROR("Unsupported Intterupt Behavior"); - return AHL_POLICY_REJECT; - } - - //Add the playing stream at last - PolicyAddStream(pCurrEndPointPolicy, pStreamInfo); - } - else - { - //Higher Priority Stream is playing - AFB_ERROR("Higher Priority Stream is playing"); - return POLICY_FAIL; - } - } - - return POLICY_SUCCESS; -} - -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); - if(pCurEndpoint == NULL) - { - AFB_WARNING("Sink Endpoint not found"); - return; - } - - //check if active - if(pCurEndpoint->streamInfo->len > 0 ) - { - StreamPolicyInfoT * pCurStream = &g_array_index(pCurEndpoint->streamInfo,StreamPolicyInfoT,pCurEndpoint->streamInfo->len-1); - if(strcasecmp(pCurStream->pAudioRole,AHL_ROLE_ENTERTAINMENT)==0) - { - if(speed > 30 && speed < 100) - { - int volume =speed; - PolicySetVolume(pCurEndpoint->endpointID, - pCurEndpoint->type, - pCurEndpoint->pHalApiName, - pCurStream->pAudioRole, - pCurEndpoint->deviceType, - volume, - false); - } - } - } - } -} - -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++) - { - 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 == iAlsaCardNumber) { - *out_pDisplayName = pHalInfo->pDisplayName; - *out_pHALName = pHalInfo->pAPIName; - return POLICY_SUCCESS; - } - } - } - - return POLICY_FAIL; -} - -static int GetHALList(void) -{ - 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; - } - AFB_DEBUG("ALSAcore hallist response=%s", json_object_to_json_string(j_response)); - - // Look through returned list for matching card - json_object * jRespObj = NULL; - json_object_object_get_ex(j_response, "response", &jRespObj); - int iNumHAL = json_object_array_length(jRespObj); - for ( int i = 0 ; i < iNumHAL; i++) - { - json_object * jHAL = json_object_array_get_idx(jRespObj,i); - char * pDevIDStr = NULL; - char * pAPIName = NULL; - char * pShortName = NULL; - - int err = wrap_json_unpack(jHAL, "{s:s,s:s,s:s}", "devid", &pDevIDStr,"api", &pAPIName,"shortname",&pShortName); - if (err) { - AFB_ERROR("Could not retrieve devid string=%s", json_object_get_string(jHAL)); - return POLICY_FAIL; - } - - HalInfoT *pHalInfo = (HalInfoT*)malloc(sizeof(HalInfoT)); - if(pHalInfo == NULL) - { - AFB_ERROR("Unable to allocate memory for HalInfo"); - return POLICY_FAIL; - } - - pHalInfo->pDevID = strdup(pDevIDStr); - pHalInfo->pAPIName = strdup(pAPIName); - pHalInfo->pDisplayName = strdup(pShortName); - - g_ptr_array_add( g_PolicyCtx.pHALList, pHalInfo); - } - - return POLICY_SUCCESS; -} - -// -// Policy API Functions -// -int Policy_OpenStream(json_object *pStreamJ) -{ - StreamInterfaceInfoT Stream; - - int err = JSONToStream(pStreamJ, &Stream); - if(err == AHL_POLICY_UTIL_FAIL) - { - 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) - // Should receive event from lower level layer - if(g_PolicyCtx.systemState != SYSTEM_NORMAL) - { - return AHL_POLICY_REJECT; - } - - StreamConfigT StreamConfig; - err = getStreamConfig(Stream.pRoleName, &StreamConfig); - if(err == POLICY_FAIL) - { - return AHL_POLICY_REJECT; - } - - // 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(&Stream); - if(err == POLICY_FAIL) - { - return AHL_POLICY_REJECT; - } - return AHL_POLICY_ACCEPT; -} - -int Policy_CloseStream(json_object *pStreamJ) -{ - StreamInterfaceInfoT Stream; - int err = JSONToStream(pStreamJ, &Stream); - if(err == AHL_POLICY_UTIL_FAIL) - { - return AHL_POLICY_REJECT; - } - - return AHL_POLICY_ACCEPT; -} - -int Policy_SetStreamState(json_object *pStreamJ) -{ - // Optional TODO: Could mute endpoint before activation, unmute afterwards (after a delay?) to avoid noises - - StreamStateT streamState = 0; - StreamInterfaceInfoT Stream; - - int err = JSONToStream(pStreamJ, &Stream); - if(err == AHL_POLICY_UTIL_FAIL) - { - return AHL_POLICY_REJECT; - } - - json_object *streamStateJ = NULL; - - if(!json_object_object_get_ex(pStreamJ, "arg_stream_state", &streamStateJ)) - { - return AHL_POLICY_REJECT; - } - streamState = (StreamStateT)json_object_get_int(streamStateJ); - - // Change of state - if(Stream.streamState != streamState) - { - //seach corresponding endpoint and gather information on it - EndPointPolicyInfoT *pCurrEndPointPolicy = PolicySearchEndPoint(Stream.endpoint.type , Stream.endpoint.gsDeviceName); - - switch(Stream.streamState) - { - case STREAM_STATE_IDLE: - switch(streamState) - { - case STREAM_STATE_RUNNING: - err = PolicyIdleRunningTransition(pCurrEndPointPolicy, &Stream); - if(err) - { - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_START); - break; - case STREAM_STATE_PAUSED: - err = PolicyIdleRunningTransition(pCurrEndPointPolicy, &Stream); - if(err) - { - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_PAUSE); - break; - default: - return AHL_POLICY_REJECT; - } - break; - case STREAM_STATE_RUNNING: - switch(streamState) - { - case STREAM_STATE_IDLE: - err = PolicyRunningIdleTransition(pCurrEndPointPolicy, &Stream); - if(err) - { - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_STOP); - break; - case STREAM_STATE_PAUSED: - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_PAUSE); - break; - default: - return AHL_POLICY_REJECT; - } - break; - case STREAM_STATE_PAUSED: - switch(streamState) - { - case STREAM_STATE_IDLE: - err = PolicyRunningIdleTransition(pCurrEndPointPolicy, &Stream); - if(err) - { - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_STOP); - break; - case STREAM_STATE_RUNNING: - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_RESUME); - break; - default: - return AHL_POLICY_REJECT; - } - break; - default: - return AHL_POLICY_REJECT; - } - } - return AHL_POLICY_ACCEPT; -} - -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; - StreamInterfaceInfoT Stream; - - int err = JSONToStream(pStreamJ, &Stream); - if(err == AHL_POLICY_UTIL_FAIL) - { - return AHL_POLICY_REJECT; - } - - json_object *streamMuteJ=NULL; - - if(!json_object_object_get_ex(pStreamJ, "mute_state", &streamMuteJ)) - { - return AHL_POLICY_REJECT; - } - streamMute = (StreamMuteT)json_object_get_int(streamMuteJ); - - if(streamMute != Stream.streamMute) - { - if(streamMute == STREAM_MUTED) - { - 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",Stream.streamID, err); - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_MUTED); - } - else - { - 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",Stream.streamID, err); - return AHL_POLICY_REJECT; - } - PolicyPostStateEvent(Stream.streamID,STREAM_EVENT_UNMUTED); - } - } - - return AHL_POLICY_ACCEPT; -} - -int Policy_SetVolume(json_object *pEndpointJ) -{ - char *volumeStr = NULL; - EndPointInterfaceInfoT Endpoint; - - int err = JSONToEndpoint(pEndpointJ, &Endpoint); - if(err == AHL_POLICY_UTIL_FAIL) - { - return AHL_POLICY_REJECT; - } - - json_object *volumeJ = NULL; - if(!json_object_object_get_ex(pEndpointJ, "arg_volume", &volumeJ)) - { - return AHL_POLICY_REJECT; - } - volumeStr = (char*)json_object_get_string(volumeJ); - - // TODO: Parse volume string to support increment/absolute/percent notation - int vol = atoi(volumeStr); - - // 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); - return AHL_POLICY_REJECT; - } - - return AHL_POLICY_ACCEPT; -} - -int Policy_SetProperty(json_object *pEndpointJ) -{ - char *propertyName = NULL; - EndPointInterfaceInfoT Endpoint; - - int err = JSONToEndpoint(pEndpointJ, &Endpoint); - if(err == AHL_POLICY_UTIL_FAIL) - { - return AHL_POLICY_REJECT; - } - - json_object *propertyNameJ = NULL; - if(!json_object_object_get_ex(pEndpointJ, "arg_property_name", &propertyNameJ)) - { - return AHL_POLICY_REJECT; - } - propertyName = (char*)json_object_get_string(propertyNameJ); - - json_object *propValueJ = NULL; - if(!json_object_object_get_ex(pEndpointJ, "arg_property_value", &propValueJ)) - { - return AHL_POLICY_REJECT; - } - json_type currentTypeJ = json_object_get_type(propValueJ); - - json_object *propArray = NULL; - if(!json_object_object_get_ex(pEndpointJ, "properties", &propArray)) - { - return AHL_POLICY_REJECT; - } - - int iPropArrayLen = json_object_array_length(propArray); - int foundProperty = 0; - - for (int i = 0; i < iPropArrayLen; i++) - { - // 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 - 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", Endpoint.endpointID, - "endpoint_type", Endpoint.type, - "property_name", propertyName, - "value",propValueJ, - "audio_role", Endpoint.pRoleName); - if(err) - { - AFB_ERROR("Unable to pack property event"); - return AHL_POLICY_REJECT; - } - - // Raise Event to update HLB - audiohlapi_raise_event(pEventDataJ); - - return AHL_POLICY_ACCEPT; -} - -int Policy_PostAction(json_object *pPolicyActionJ) -{ - char * actionName = NULL; - char * audioRole = NULL; - char * mediaName = NULL; - json_object *actionContext = NULL; - - int err = wrap_json_unpack(pPolicyActionJ, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); - if (err) { - AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); - return AHL_POLICY_REJECT; - } - - // TODO: Any event with media specified should trigger action on provided rendering services (e.g. Wwise binding, gstreamer file player wrapper, MPDC? simple ALSA player (aplay)?) - // Example (when the policy is hooked to CAN events). Post audio playback events other than safety during reverse gear engaged declined - // Example post HMI audio role playback events declined when higher priority streams are active - - //In this use case just return the action back to highlevel binding. - - json_object *pEventDataJ = NULL; - err = wrap_json_pack(&pEventDataJ, "{s:s,s:s,s:s,s?s,s?o}", "event_name", AHL_POST_ACTION_EVENT, "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); - if (err) { - 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 *pInPolicyEndpointJ,json_object **pOutPolicyEndpointJ) -{ - 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; - } - - StreamConfigT StreamConfig; - getStreamConfig(pRoleName, &StreamConfig); - - char * pDisplayName = NULL; - char * pHALName = NULL; - if (deviceURIType != DEVICEURITYPE_NOT_ALSA) { - // Update Hal Name - err = RetrieveAssociatedHALAPIName(iAlsaCardNumber,&pDisplayName,&pHALName); - if (err) { - 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; - } - 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; - } - } - } - 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; - } - - // 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 - -OnError: - if (iAllocString) { - g_free(pDisplayName); - g_free(pHALName); - } - return AHL_POLICY_REJECT; - -} - -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.pSinkEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); - g_PolicyCtx.pHALList = g_ptr_array_new_with_free_func(g_free); - - //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(); - - // 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; - - - -#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(); - json_object_object_add(queryurl, "events", eventsJ); - int returnResult = afb_service_call_sync("audiod", "subscribe", queryurl, &responseJ); - if (returnResult) { - AFB_ERROR("Fail subscribing to Audio Backend System events"); - return AHL_POLICY_REJECT; - } -#endif - - - return AHL_POLICY_ACCEPT; -} - -void Policy_Term() -{ - // Free Ressources - if (g_PolicyCtx.pHALList) { - g_ptr_array_free(g_PolicyCtx.pHALList,TRUE); - g_PolicyCtx.pHALList = NULL; - } - - for(int i=0; i<g_PolicyCtx.pSourceEndpoints->len; i++) - { - EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSourceEndpoints,EndPointPolicyInfoT,i); - g_array_free(pCurEndpoint->streamInfo,TRUE); - pCurEndpoint->streamInfo= NULL; - } - - for(int i=0; i<g_PolicyCtx.pSinkEndpoints->len; i++) - { - EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSinkEndpoints,EndPointPolicyInfoT,i); - g_array_free(pCurEndpoint->streamInfo,TRUE); - pCurEndpoint->streamInfo = NULL; - } - - g_array_free(g_PolicyCtx.pSourceEndpoints,TRUE); - g_PolicyCtx.pSourceEndpoints = NULL; - g_array_free(g_PolicyCtx.pSinkEndpoints,TRUE); - 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); - char *eventName = NULL; - json_object *event_parameter = NULL; - int speed = 0; - - if(strcasecmp(evtname, "audiod/system_events")==0) - { - int err = wrap_json_unpack(eventJ, "{s:s,s:o}", "event_name", &eventName, "event_parameter", &event_parameter); - if (err) { - AFB_WARNING("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(eventJ)); - return; - } - - if(strcasecmp(eventName, "speed")==0) - { - AFB_NOTICE("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(event_parameter)); - err = wrap_json_unpack(event_parameter, "{s:i}", "speed_value", &speed); - if (err) { - 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 - PolicySpeedModify(speed); - } - } -} - -#endif // AHL_DISCONNECT_POLICY
\ No newline at end of file diff --git a/src/ahl-policy.h b/src/ahl-policy.h deleted file mode 100644 index 0200973..0000000 --- a/src/ahl-policy.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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_INCLUDE -#define AHL_POLICY_INCLUDE - -#include "ahl-policy-utils.h" - -#ifndef AHL_DISCONNECT_POLICY - -#define MAX_ACTIVE_STREAM_POLICY 30 -#define POLICY_FAIL 1 -#define POLICY_SUCCESS 0 - -#define AHL_POLICY_UNDEFINED_HALNAME "UNDEFINED" -#define AHL_POLICY_UNDEFINED_DISPLAYNAME "DeviceNotFound" - -#define AHL_POLICY_ALSA_API "alsacore" - -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/src/ahl-policyJSON.c b/src/ahl-policyJSON.c deleted file mode 100644 index 1fdf2d9..0000000 --- a/src/ahl-policyJSON.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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. - */ - -#include "wrap-json.h" -#include <json-c/json.h> -#include <glib.h> -#include "ahl-policy-utils.h" -#include "ahl-interface.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; - int err = 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)); - if(err) - { - AFB_NOTICE("Content object=%s", json_object_get_string(*endpointInfoJ)); - } - - 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); - int err = 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 - - if(err) - { - AFB_NOTICE("Content object=%s", json_object_get_string(*streamInfoJ)); - } - - json_object_object_add(*streamInfoJ,"endpoint_info",endpointInfoJ); -}
\ No newline at end of file diff --git a/src/ahl-policyJSON.h b/src/ahl-policyJSON.h deleted file mode 100644 index c651f79..0000000 --- a/src/ahl-policyJSON.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - -#include <json-c/json.h> -#include <afb/afb-binding.h> -#include "ahl-policy-utils.h" // TODO: Should remigrate AHL structures to binding.h - -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 |