diff options
-rw-r--r-- | conf.d/project/agl-ahl-config.json | 8 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/ahl-binding.c | 71 | ||||
-rw-r--r-- | src/ahl-binding.h | 4 | ||||
-rw-r--r-- | src/ahl-config.c | 21 | ||||
-rw-r--r-- | src/ahl-deviceenum.c | 30 | ||||
-rw-r--r-- | src/ahl-json.c | 296 | ||||
-rw-r--r-- | src/ahl-json.h | 26 | ||||
-rwxr-xr-x | src/ahl-policy-utils.c | 23 | ||||
-rwxr-xr-x | src/ahl-policy-utils.h | 7 | ||||
-rw-r--r-- | src/ahl-policy.c | 234 | ||||
-rw-r--r-- | src/ahl-policy.h | 5 |
12 files changed, 508 insertions, 219 deletions
diff --git a/conf.d/project/agl-ahl-config.json b/conf.d/project/agl-ahl-config.json index f49c0be..74ab251 100644 --- a/conf.d/project/agl-ahl-config.json +++ b/conf.d/project/agl-ahl-config.json @@ -7,7 +7,6 @@ "audio_roles": [ { "name": "Warning", - "id": 0, "description": "Safety-relevant or critical alerts/alarms", "priority": 100, "output": [ @@ -23,7 +22,6 @@ }, { "name": "Guidance", - "id": 1, "description": "Important user information where user action is expected (e.g. navigation instruction)", "priority": 25, "output": [ @@ -39,7 +37,6 @@ }, { "name": "Notification", - "id": 2, "description": "HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...)", "priority": 0, "output": [ @@ -57,7 +54,6 @@ }, { "name": "Communication", - "id": 3, "description": "Voice communications (e.g. handsfree, speech recognition)", "priority": 50, "output": [ @@ -76,7 +72,6 @@ }, { "name": "Entertainment", - "id": 4, "description": "Multimedia content (e.g. tuner, media player, etc.)", "priority": 0, "output": [ @@ -87,7 +82,6 @@ }, { "name": "System", - "id": 5, "description": "System level content or development", "priority": 100, "output": [ @@ -100,7 +94,6 @@ }, { "name": "Startup", - "id": 6, "description": "Early (startup) sound", "priority": 100, "output": [ @@ -113,7 +106,6 @@ }, { "name": "Shutdown", - "id": 7, "description": "Late (shutdown) sound", "priority": 100, "output": [ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 75a16cc..0bb3986 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,7 +39,7 @@ PKG_CHECK_MODULES(GLIB_PKG REQUIRED glib-2.0) 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-policyJSON.c) + 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) diff --git a/src/ahl-binding.c b/src/ahl-binding.c index 01138c3..c205c8e 100644 --- a/src/ahl-binding.c +++ b/src/ahl-binding.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> @@ -22,8 +21,7 @@ #include "ahl-apidef.h" // Generated from JSON OpenAPI #include "wrap-json.h" #include "ahl-policy.h" -#include "ahl-policyJSON.h" -#include "ahl-policy-utils.h" +#include "ahl-json.h" // Global high-level binding context AHLCtxT g_AHLCtx; @@ -140,7 +138,6 @@ static RoleInfoT * GetRole(char * in_pAudioRoleName) } static int CloseStream(AHLClientCtxT * in_pClientCtx, streamID_t streamID,struct afb_req * pReq) { - // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions StreamInfoT * pStreamInfo = GetStream(streamID); if (pStreamInfo == NULL) { AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); @@ -251,30 +248,28 @@ static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t strea static int CreateEvents() { - int err = 0; - g_AHLCtx.policyCtx.propertyEvent = afb_daemon_make_event(AHL_ENDPOINT_PROPERTY_EVENT); - err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); + int err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); if (err) { AFB_ERROR("Could not create endpoint property change event"); - return err; + return AHL_FAIL; } g_AHLCtx.policyCtx.volumeEvent = afb_daemon_make_event(AHL_ENDPOINT_VOLUME_EVENT); err = !afb_event_is_valid(g_AHLCtx.policyCtx.volumeEvent); if (err) { AFB_ERROR("Could not create endpoint volume change event"); - return err; + return AHL_FAIL; } g_AHLCtx.policyCtx.postActionEvent = afb_daemon_make_event(AHL_POST_ACTION_EVENT); err = !afb_event_is_valid(g_AHLCtx.policyCtx.postActionEvent); if (err) { AFB_ERROR("Could not create post action event call event"); - return err; + return AHL_FAIL; } - return err; + return AHL_SUCCESS; } static void AhlBindingTerm() @@ -358,42 +353,36 @@ static void AhlBindingTerm() // Binding initialization PUBLIC int AhlBindingInit() { - int err = 0; - memset(&g_AHLCtx,0,sizeof(g_AHLCtx)); // Register exit function atexit(AhlBindingTerm); // Create AGL Events - err = CreateEvents(); - if(err) - { - //Error messages already reported inside CreateEvents - return err; + int err = CreateEvents(); + if(err) { + // Error messages already reported inside CreateEvents + return AHL_FAIL; } // Parse high-level binding JSON configuration file (will build device lists) err = ParseHLBConfig(); - if(err) - { - //Error messages already reported inside ParseHLBConfig - return err; + if(err) { + // Error messages already reported inside ParseHLBConfig + return AHL_FAIL; } #ifndef AHL_DISCONNECT_POLICY // Policy initialization err = Policy_Init(); - if(err == AHL_POLICY_REJECT) - { + if(err == AHL_POLICY_REJECT) { //Error messages already reported inside PolicyInit - return err; + return AHL_FAIL; } - // for all audio Roles + // Call policy for initalization of all source + sink endpoints for all audio Roles GHashTableIter iter; gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo); while (g_hash_table_iter_next (&iter, &key, &value)) { @@ -415,15 +404,15 @@ PUBLIC int AhlBindingInit() 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); - + 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); + // json_object_put(pOutPolicyEndpointJ); } } } @@ -445,7 +434,7 @@ PUBLIC int AhlBindingInit() 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); - //return AHL_FAIL; + // continue } json_object_put(pInPolicyEndpointJ); err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ); @@ -465,11 +454,11 @@ PUBLIC int AhlBindingInit() if(g_AHLCtx.policyCtx.pStreams == NULL) { AFB_ERROR("Unable to create Active Stream List"); - return err; + return AHL_FAIL; } AFB_DEBUG("Audio high-level Binding success"); - return err; + return AHL_SUCCESS; } PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ) @@ -583,7 +572,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) // Assign a device based on configuration priority (first in the list for requested role and endpoint type) pEndpointInfo = g_ptr_array_index(pDeviceArray,0); endpointSelMode = ENDPOINTSELMODE_AUTO; - } else{ endpointSelMode = ENDPOINTSELMODE_MANUAL; @@ -659,6 +647,7 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) if (g_AHLCtx.policyCtx.pStreams) g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo ); + // Package and return stream information to client JSONPublicPackageStream(pStreamInfo,&streamInfoJ); afb_req_success(req, streamInfoJ, "Stream info structure"); @@ -1075,7 +1064,6 @@ PUBLIC void audiohlapi_post_action(struct afb_req req) } json_object_get(pActionInfo); int policyAllowed = Policy_PostAction(pActionInfo); - //int policyAllowed = Policy_PostAction(queryJ); if (!policyAllowed) { afb_req_fail(req, "Audio policy violation", "Post sound action not allowed in current context"); @@ -1174,7 +1162,7 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) } EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); // update property value - if (pEndpointInfo->pPropTable) + if ((pEndpointInfo!=NULL) && (pEndpointInfo->pPropTable!=NULL)) { json_type jType = json_object_get_type(propValueJ); switch (jType) { @@ -1216,9 +1204,16 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); return; } - EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); + EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); // update volume value - pEndpointInfo->iVolume = iVolume; + if(pEndpointInfo) + { + pEndpointInfo->iVolume = iVolume; + } + else + { + AFB_ERROR("Unable to find endpoint"); + } // Remove event name from object json_object_object_del(pEventDataJ,"event_name"); afb_event_push(g_AHLCtx.policyCtx.volumeEvent,pEventDataJ); diff --git a/src/ahl-binding.h b/src/ahl-binding.h index c6f0846..405144d 100644 --- a/src/ahl-binding.h +++ b/src/ahl-binding.h @@ -17,13 +17,11 @@ #ifndef AHL_BINDING_INCLUDE #define AHL_BINDING_INCLUDE -#define AFB_BINDING_VERSION 2 - //#define AHL_DISCONNECT_POLICY // define for debugging HLB in standalone only #include <json-c/json.h> #include <glib.h> - +#define AFB_BINDING_VERSION 2 #include <afb/afb-binding.h> #include "ahl-interface.h" #include "ahl-policy-utils.h" diff --git a/src/ahl-config.c b/src/ahl-config.c index 5e3de08..f076d14 100644 --- a/src/ahl-config.c +++ b/src/ahl-config.c @@ -14,12 +14,10 @@ * limitations under the License. */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <json-c/json.h> #include "wrap-json.h" - #include "ahl-binding.h" extern AHLCtxT g_AHLCtx; @@ -46,12 +44,12 @@ int ParseHLBConfig() { json_object * jHALList = NULL; char * policyModule = NULL; - // TODO: This should be retrieve from binding startup arguments + // 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 1; + return AHL_FAIL; } sprintf(configfile_path, "%s", getenv("AHL_CONFIG_FILE")); @@ -62,13 +60,13 @@ int ParseHLBConfig() { if(config_JFile == NULL) { AFB_ERROR("Error: Can't open configuration file -> %s",configfile_path); - return 1; + return AHL_FAIL; } int err = wrap_json_unpack(config_JFile, "{s:s,s:s,s:o,s:o}", "version", &versionStr,"policy_module", &policyModule,"audio_roles",&jAudioRoles,"hal_list",&jHALList); if (err) { AFB_ERROR("Invalid configuration file -> %s", configfile_path); - return 1; + return AHL_FAIL; } AFB_INFO("High-level audio API version: %s", "1.0.0"); AFB_INFO("Config version: %s", versionStr); @@ -93,7 +91,7 @@ int ParseHLBConfig() { if( err != 0 ) { AFB_ERROR("Audio high level API could not set dependency on API: %s",pHAL); - return 1; + return AHL_FAIL; } } } @@ -122,7 +120,7 @@ int ParseHLBConfig() { ); if (err) { AFB_ERROR("Invalid audio role configuration : %s", json_object_to_json_string(jAudioRole)); - return 1; + return AHL_FAIL; } if (jOutputDevices) @@ -155,7 +153,7 @@ int ParseHLBConfig() { err = EnumerateDevices(jInputDevices,pRoleName,ENDPOINTTYPE_SOURCE,pRoleInfo->pSourceEndpoints); if (err) { AFB_ERROR("Invalid input devices : %s", json_object_to_json_string(jInputDevices)); - return 1; + return AHL_FAIL; } } // Sinks @@ -164,15 +162,14 @@ int ParseHLBConfig() { err = EnumerateDevices(jOutputDevices,pRoleName,ENDPOINTTYPE_SINK,pRoleInfo->pSinkEndpoints); if (err) { AFB_ERROR("Invalid output devices : %s", json_object_to_json_string(jOutputDevices)); - return 1; + return AHL_FAIL; } } g_hash_table_insert(g_AHLCtx.policyCtx.pRoleInfo, pRoleInfo->pRoleName, pRoleInfo); - } // Build lists of all device URI referenced in config file (input/output) AFB_DEBUG ("Audio high-level - Parse high-level audio configuration done"); - return 0; + return AHL_SUCCESS; } diff --git a/src/ahl-deviceenum.c b/src/ahl-deviceenum.c index ebadb1f..763b2ca 100644 --- a/src/ahl-deviceenum.c +++ b/src/ahl-deviceenum.c @@ -14,16 +14,9 @@ * limitations under the License. */ -#define _GNU_SOURCE -#include <stdio.h> -#include <string.h> #include <alsa/asoundlib.h> #include <alsa/pcm.h> -#include <json-c/json.h> -#include "wrap-json.h" - #include "ahl-binding.h" -#include "ahl-policy.h" extern AHLCtxT g_AHLCtx; @@ -59,7 +52,7 @@ static int SeparateDomainFromDeviceURI( char * in_pDeviceURI, char ** out_pDomai AFB_ERROR("Error tokenizing device URI -> %s",in_pDeviceURI); return 1; } - return 0; + return AHL_SUCCESS; } static int IsAlsaDomain(const char * in_pDomainStr) @@ -90,7 +83,6 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp snd_pcm_info_t * pPcmInfo = NULL; int iAlsaRet = 0; const char * pCardName = NULL; - int retVal = 0; snd_ctl_t * ctlHandle = NULL; snd_ctl_card_info_t * ctlInfo = NULL; @@ -121,7 +113,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp if (iAlsaRet < 0) { AFB_WARNING("Error retrieving PCM device info"); - return 1; + return AHL_FAIL; } // get card number @@ -129,7 +121,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp if ( out_pEndpointInfo->alsaInfo.cardNum < 0 ) { AFB_WARNING("No Alsa card number available"); - return 1; + return AHL_FAIL; } // get device number @@ -137,7 +129,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp if ( out_pEndpointInfo->alsaInfo.deviceNum < 0 ) { AFB_WARNING("No Alsa device number available"); - return 1; + return AHL_FAIL; } // get sub-device number @@ -145,7 +137,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp if ( out_pEndpointInfo->alsaInfo.subDeviceNum < 0 ) { AFB_WARNING("No Alsa subdevice number available"); - return 1; + return AHL_FAIL; } char cardName[32]; @@ -154,7 +146,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp if ( iAlsaRet < 0 ) { AFB_WARNING("Could not open ALSA card control"); - return 1; + return AHL_FAIL; } iAlsaRet = snd_ctl_card_info(ctlHandle, ctlInfo); @@ -162,7 +154,7 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp { AFB_WARNING("Could not retrieve ALSA card info"); snd_ctl_close(ctlHandle); - return 1; + return AHL_FAIL; } // Populate unique target card name @@ -171,13 +163,13 @@ static int FillALSAPCMInfo( snd_pcm_t * in_pPcmHandle, EndpointInfoT * out_pEndp { AFB_WARNING("No Alsa card name available"); snd_ctl_close(ctlHandle); - return 1; + return AHL_FAIL; } g_strlcpy(out_pEndpointInfo->gsDeviceName,pCardName,AHL_STR_MAX_LENGTH); snd_ctl_close(ctlHandle); - return retVal; + return AHL_SUCCESS; } EndpointInfoT * InitEndpointInfo() @@ -250,7 +242,7 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi char * pDeviceURIDomain = NULL; char * pFullDeviceURI = NULL; char * pDeviceURIPCM = NULL; - int err = 0; + int err = AHL_SUCCESS; json_object * jDevice = json_object_array_get_idx(in_jDeviceArray,i); if (jDevice == NULL) { @@ -336,5 +328,5 @@ int EnumerateDevices(json_object * in_jDeviceArray, char * in_pAudioRole, Endpoi } // for all devices AFB_DEBUG ("Audio high-level - Enumerate devices done"); - return 0; + return AHL_SUCCESS; }
\ No newline at end of file diff --git a/src/ahl-json.c b/src/ahl-json.c new file mode 100644 index 0000000..5e8bf97 --- /dev/null +++ b/src/ahl-json.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2017 "Audiokinetic Inc" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> +#include "wrap-json.h" +#include <json-c/json.h> +#include <glib.h> +#include "ahl-binding.h" + +static char * DeviceURITypeEnumToStr(DeviceURITypeT in_eDeviceURIType) { + switch(in_eDeviceURIType) { + case DEVICEURITYPE_ALSA_HW: // Alsa hardware device URI + return AHL_DEVICEURITYPE_ALSA_HW; + case DEVICEURITYPE_ALSA_DMIX: // Alsa Dmix device URI (only for playback devices) + return AHL_DEVICEURITYPE_ALSA_DMIX; + case DEVICEURITYPE_ALSA_DSNOOP: // Alsa DSnoop device URI (only for capture devices) + return AHL_DEVICEURITYPE_ALSA_DSNOOP; + case DEVICEURITYPE_ALSA_SOFTVOL: // Alsa softvol device URI + return AHL_DEVICEURITYPE_ALSA_SOFTVOL; + case DEVICEURITYPE_ALSA_PLUG: // Alsa plug device URI + return AHL_DEVICEURITYPE_ALSA_PLUG; + case DEVICEURITYPE_ALSA_OTHER: // Alsa domain URI device of unspecified type + return AHL_DEVICEURITYPE_ALSA_OTHER; + case DEVICEURITYPE_NOT_ALSA: // Unknown (not ALSA domain) + return AHL_DEVICEURITYPE_NOT_ALSA; + default: + return "Unknown"; + } +} + +static char * StreamStateEnumToStr(StreamStateT in_eStreamState) { + switch(in_eStreamState) { + case STREAM_STATE_IDLE: + return AHL_STREAM_STATE_IDLE; + case STREAM_STATE_RUNNING: + return AHL_STREAM_STATE_RUNNING; + case STREAM_STATE_PAUSED: + return AHL_STREAM_STATE_PAUSED; + default: + return "Unknown"; + } +} + +static char * StreamMuteEnumToStr(StreamMuteT in_eStreamMute) { + switch(in_eStreamMute) { + case STREAM_UNMUTED: + return AHL_STREAM_UNMUTED; + case STREAM_MUTED: + return AHL_STREAM_MUTED; + default: + return "Unknown"; + } +} + +static int EndpointPropTableToJSON(GHashTable * pPropTable, json_object **ppProptableJ) +{ + if(pPropTable == NULL) + { + AFB_ERROR("Invalid EndpointPropTableToJSON arguments"); + return AHL_FAIL; + } + + // Create json object for PropTable + *ppProptableJ = json_object_new_array(); + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init (&iter, pPropTable); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + if ( key != NULL && value != NULL) { + json_object *pPropertyJ = NULL; + json_object_get(value); + int err = wrap_json_pack(&pPropertyJ, "{s:s,s:o}", + "property_name", (char*)key, + "property_value", value + ); + if(err) + { + AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); + return AHL_FAIL; + } + json_object_array_add(*ppProptableJ, pPropertyJ); + } + } + + return AHL_SUCCESS; +} + +int EndpointInfoToJSON(EndpointInfoT * pEndpointInfo, json_object **ppEndpointInfoJ) +{ + if(pEndpointInfo == NULL || pEndpointInfo->pPropTable == NULL) + { + AFB_ERROR("Invalid EndpointInfoToJSON arguments"); + return AHL_FAIL; + } + + json_object * pPropTableJ = NULL; + int err = EndpointPropTableToJSON(pEndpointInfo->pPropTable,&pPropTableJ); + if (err) { + return AHL_FAIL; + } + + // Create json object for EndpointInfo + err = wrap_json_pack(ppEndpointInfoJ, "{s:i,s:i,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:o}", + "endpoint_id", pEndpointInfo->endpointID, + "endpoint_type", pEndpointInfo->type, + "device_name", pEndpointInfo->gsDeviceName, + "display_name", pEndpointInfo->gsDisplayName, + "device_uri", pEndpointInfo->gsDeviceURI, + "device_domain", pEndpointInfo->gsDeviceDomain, + "audio_role",pEndpointInfo->pRoleName, + "device_uri_type", pEndpointInfo->deviceURIType, + "hal_api_name", pEndpointInfo->gsHALAPIName, + "alsa_cardNum", pEndpointInfo->alsaInfo.cardNum, + "alsa_deviceNum", pEndpointInfo->alsaInfo.deviceNum, + "alsa_subDeviceNum", pEndpointInfo->alsaInfo.subDeviceNum, + "format_samplerate", pEndpointInfo->format.sampleRate, + "format_numchannels", pEndpointInfo->format.numChannels, + "format_sampletype",pEndpointInfo->format.sampleType, + "volume", pEndpointInfo->iVolume, + "property_table", pPropTableJ + ); + if (err) { + AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); + return AHL_FAIL; + } + + return AHL_SUCCESS; +} + +int StreamInfoToJSON(StreamInfoT * pStreamInfo, json_object **ppStreamInfoJ) +{ + if(pStreamInfo == NULL) + { + AFB_ERROR("Invalid arguments to StreamInfoToJSON"); + return AHL_FAIL; + } + + json_object * pEndpointInfoJ = NULL; + int err = EndpointInfoToJSON(pStreamInfo->pEndpointInfo, &pEndpointInfoJ); + if (err) { + return AHL_FAIL; + } + + // Create json object for stream + err = wrap_json_pack(ppStreamInfoJ, "{s:i,s:i,s:i,s:I,s:i,s:s,s:i,s:i,s:o}", + "stream_id", pStreamInfo->streamID, + "stream_state", pStreamInfo->streamState, + "stream_mute", pStreamInfo->streamMute, + "stream_state_event", &pStreamInfo->streamStateEvent, + "endpoint_sel_mod", pStreamInfo->endpointSelMode, + "role_name", pStreamInfo->pRoleName, + "priority", pStreamInfo->iPriority, + "interrupt_behavior", pStreamInfo->eInterruptBehavior, + "endpoint_info", pEndpointInfoJ + ); + if (err) { + AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); + return AHL_FAIL; + } + + return AHL_SUCCESS; +} + +static int UpdatePropertyList(GHashTable * pPropTable, json_object * pPropTableJ) { + if (pPropTable == NULL || pPropTableJ == NULL) { + AFB_ERROR("Invalid arguments to UpdatePropertyList"); + return AHL_FAIL; + } + // Unpack prop table + int nbProperties = json_object_array_length(pPropTableJ); + for(int i = 0; i < nbProperties; i++) + { + json_object * propJ = json_object_array_get_idx(pPropTableJ,i); + if (propJ) { + char * pPropertyName = NULL; + json_object * pPropertyValueJ = NULL; + int err = wrap_json_unpack(propJ, "{s:s,s:o}", + "property_name", &pPropertyName, + "property_value", &pPropertyValueJ); + if (err) { + AFB_ERROR("Unable to unpack JSON property, = %s", wrap_json_get_error_string(err)); + return AHL_FAIL; + } + + // Object type detection for property value (string = state, numeric = property) + json_type jType = json_object_get_type(pPropertyValueJ); + switch (jType) { + case json_type_double: + g_hash_table_insert(pPropTable, pPropertyName, json_object_new_double(json_object_get_double(pPropertyValueJ))); + break; + case json_type_int: + g_hash_table_insert(pPropTable, pPropertyName, json_object_new_int(json_object_get_int(pPropertyValueJ))); + break; + case json_type_string: + g_hash_table_insert(pPropTable, pPropertyName, json_object_new_string(json_object_get_string(pPropertyValueJ))); + break; + default: + AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(pPropertyValueJ)); + return AHL_FAIL; + } + } + } + + return AHL_SUCCESS; +} + +int UpdateEndpointInfo(EndpointInfoT * pEndpoint, json_object * pEndpointInfoJ) { + + if(pEndpoint == NULL || pEndpointInfoJ == NULL) + { + AFB_ERROR("Invalid arguments to UpdateEndpointInfo"); + return AHL_FAIL; + } + + // Push information to endpoint info struct + json_object * pPropTableJ = NULL; + char * pDisplayName = NULL; + char * pHALName = NULL; + int err = wrap_json_unpack(pEndpointInfoJ,"{s:i,s:s,s:s,s:o}", + "init_volume",&pEndpoint->iVolume, + "display_name",&pDisplayName, + "hal_name", &pHALName, + "property_table",&pPropTableJ); + if (err) { + AFB_ERROR("Unable to create Endpoint Json object error:%s ",wrap_json_get_error_string(err)); + return AHL_FAIL; + } + g_strlcpy(pEndpoint->gsDisplayName,pDisplayName,AHL_STR_MAX_LENGTH); + g_strlcpy(pEndpoint->gsHALAPIName,pHALName,AHL_STR_MAX_LENGTH); + + if (pEndpoint->pPropTable && pPropTableJ) { + err = UpdatePropertyList(pEndpoint->pPropTable,pPropTableJ); + if (err) { + AFB_ERROR("Unable to update property table Json object error:%s ",wrap_json_get_error_string(err)); + return AHL_FAIL; + } + } + + return AHL_SUCCESS; +} + +static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * pAudioFormat) +{ + wrap_json_pack(audioFormatJ, "{s:i,s:i,s:i}", + "sample_rate", pAudioFormat->sampleRate, + "num_channels", pAudioFormat->numChannels, + "sample_type", pAudioFormat->sampleType); +} + +// Package only information that can useful to application clients when selecting endpoint +void JSONPublicPackageEndpoint(EndpointInfoT * pEndpointInfo,json_object **endpointInfoJ) +{ + json_object *formatInfoJ = NULL; + wrap_json_pack(endpointInfoJ, "{s:i,s:s,s:s,s:s,s:s,s:s,s:s}", + "endpoint_id", pEndpointInfo->endpointID, + "endpoint_type", (pEndpointInfo->type == ENDPOINTTYPE_SOURCE) ? AHL_ENDPOINTTYPE_SOURCE : AHL_ENDPOINTTYPE_SINK, + "device_name", pEndpointInfo->gsDeviceName, + "display_name", pEndpointInfo->gsDisplayName, + "audio_role", pEndpointInfo->pRoleName, + "device_domain",pEndpointInfo->gsDeviceDomain, + "device_uri_type", DeviceURITypeEnumToStr(pEndpointInfo->deviceURIType)); + AudioFormatStructToJSON(&formatInfoJ,&pEndpointInfo->format); + json_object_object_add(*endpointInfoJ,"format",formatInfoJ); + + json_object *pPropTableJ = NULL; + EndpointPropTableToJSON(pEndpointInfo->pPropTable,&pPropTableJ); + json_object_object_add(*endpointInfoJ,"properties",pPropTableJ); +} + +// Package only information that can useful to application clients when opening a stream +void JSONPublicPackageStream(StreamInfoT * pStreamInfo,json_object **streamInfoJ) +{ + json_object *endpointInfoJ = NULL; + JSONPublicPackageEndpoint(pStreamInfo->pEndpointInfo,&endpointInfoJ); + wrap_json_pack(streamInfoJ, "{s:i,s:s,s:s,s:s}", + "stream_id", pStreamInfo->streamID, + "state", StreamStateEnumToStr(pStreamInfo->streamState), + "mute", StreamMuteEnumToStr(pStreamInfo->streamMute), + "device_uri",pStreamInfo->pEndpointInfo->gsDeviceURI); // Need to open a stream to have access to the device URI + json_object_object_add(*streamInfoJ,"endpoint_info",endpointInfoJ); +}
\ No newline at end of file diff --git a/src/ahl-json.h b/src/ahl-json.h new file mode 100644 index 0000000..ffd683a --- /dev/null +++ b/src/ahl-json.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 "Audiokinetic Inc" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AHL_POLICY_JSON_INCLUDE +#define AHL_POLICY_JSON_INCLUDE + +int EndpointInfoToJSON(EndpointInfoT * pEndpointInfo, json_object **ppEndpointInfoJ); +int StreamInfoToJSON(StreamInfoT * pStreamInfo, json_object **ppStreamInfoJ); +int UpdateEndpointInfo(EndpointInfoT * pEndpoint,json_object * pEndpointInfoJ); +void JSONPublicPackageEndpoint(EndpointInfoT * pEndpointInfo,json_object **endpointInfoJ); +void JSONPublicPackageStream(StreamInfoT * pStreamInfo,json_object **streamInfoJ); + +#endif // AHL_POLICY_JSON_INCLUDE diff --git a/src/ahl-policy-utils.c b/src/ahl-policy-utils.c index 87fe03f..195c591 100755 --- a/src/ahl-policy-utils.c +++ b/src/ahl-policy-utils.c @@ -14,10 +14,12 @@ * limitations under the License. */ +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> + #include "ahl-policy-utils.h" #include "wrap-json.h" #include <json-c/json.h> -#include <glib.h> void Add_Endpoint_Property_Double( json_object * io_pPropertyArray, char * in_pPropertyName, double in_dPropertyValue) { @@ -56,10 +58,9 @@ int EndpointToJSON(EndPointInterfaceInfoT * pEndpoint, json_object **ppEndpointJ 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}", + // 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, @@ -94,7 +95,6 @@ int StreamToJSON(StreamInterfaceInfoT * pStream, json_object **ppStreamJ) return AHL_POLICY_UTIL_FAIL; } - json_object *EndpointJ = NULL; int err = EndpointToJSON(&pStream->endpoint, &EndpointJ); if (err) { @@ -102,7 +102,7 @@ int StreamToJSON(StreamInterfaceInfoT * pStream, json_object **ppStreamJ) return AHL_POLICY_UTIL_FAIL; } - //Create json object for stream + // 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, @@ -125,10 +125,9 @@ int StreamToJSON(StreamInterfaceInfoT * pStream, json_object **ppStreamJ) //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 InterfaceJSONToEndpoint"); + AFB_ERROR("Invalid arguments for JSONToEndpoint"); return AHL_POLICY_UTIL_FAIL; } @@ -170,7 +169,7 @@ int JSONToStream(json_object *pStreamJ, StreamInterfaceInfoT * pStream) //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}", + 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, @@ -185,9 +184,9 @@ int JSONToStream(json_object *pStreamJ, StreamInterfaceInfoT * pStream) return AHL_POLICY_UTIL_FAIL; } - int iRet = JSONToEndpoint(pEndpointJ,&pStream->endpoint); - if (iRet) { - return iRet; + err = JSONToEndpoint(pEndpointJ,&pStream->endpoint); + if (err) { + return AHL_POLICY_UTIL_FAIL; } return AHL_POLICY_UTIL_SUCCESS; } diff --git a/src/ahl-policy-utils.h b/src/ahl-policy-utils.h index 65b5432..3c20020 100755 --- a/src/ahl-policy-utils.h +++ b/src/ahl-policy-utils.h @@ -17,10 +17,7 @@ #ifndef AHL_POLICY_UTILS_INCLUDE #define AHL_POLICY_UTILS_INCLUDE -#define AFB_BINDING_VERSION 2 #include <json-c/json.h> -#include <afb/afb-binding.h> -#include <glib.h> #define AHL_POLICY_ACCEPT 1 #define AHL_POLICY_REJECT 0 @@ -120,7 +117,6 @@ typedef enum EndpointSelectionMode { 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 @@ -137,7 +133,6 @@ typedef struct EndPointInterfaceInfo { json_object *pPropTableJ; //Property Table } EndPointInterfaceInfoT; - typedef struct StreamInterfaceInfo { streamID_t streamID; // Stream unique ID StreamStateT streamState; // Stream activity state @@ -151,7 +146,7 @@ typedef struct StreamInterfaceInfo { 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 EndpointToJSON(EndPointInterfaceInfoT * pEndpoint, json_object **ppEndpointJ); +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); diff --git a/src/ahl-policy.c b/src/ahl-policy.c index 1e4eb3b..4a34ed8 100644 --- a/src/ahl-policy.c +++ b/src/ahl-policy.c @@ -14,10 +14,12 @@ * limitations under the License. */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> #include <stdbool.h> +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> +#include <glib.h> #include "wrap-json.h" #include "ahl-policy-utils.h" #include "ahl-interface.h" @@ -25,13 +27,14 @@ #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 + streamID_t streamID; + int RolePriority; + char * pAudioRole; + InterruptBehaviorT interruptBehavior; + int iDuckVolume; //duck Volume } StreamPolicyInfoT; typedef struct EndPointPolicyInfo { @@ -44,7 +47,6 @@ typedef struct EndPointPolicyInfo { GArray * streamInfo; //List of playing or duck stream at a given endpoint } EndPointPolicyInfoT; - typedef enum SystemState { SYSTEM_STARTUP = 0, // Startup SYSTEM_SHUTDOWN, // ShutDown @@ -53,7 +55,6 @@ typedef enum SystemState { SYSTEM_MAXVALUE // Enum count, keep at the end } SystemStateT; - typedef struct HalInfo { char *pDevID; char *pAPIName; @@ -74,11 +75,9 @@ typedef struct PolicyLocalCtx { SystemStateT systemState; } PolicyLocalCtxT; - -// Global Context +// Policy context PolicyLocalCtxT g_PolicyCtx; - // Helper Functions static int getStreamConfig(char *pAudioRole, StreamConfigT *pStreamConfig) { @@ -176,15 +175,14 @@ static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName } break; default: - //Set volume to zero for display purpose only. - //Not support yet + // Not supported yet AFB_WARNING("Device Type %i is not support and can't set volume on HalName %s",deviceType, pHalApiName); return POLICY_FAIL; break; } // Set endpoint volume using HAL services (leveraging ramps etc.) - json_object *j_response, *j_query = NULL; + json_object *j_response = NULL, *j_query = NULL; // Package query int err = wrap_json_pack(&j_query,"{s:s,s:i}","label",gsHALControlName->str, "val",iVolume); @@ -194,7 +192,7 @@ static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName return POLICY_FAIL; } - //TODO implement Volume limitation based on policy + // TODO: implement Volume limitation based on policy // Set the volume using the HAL err = afb_service_call_sync(pHalApiName, "ctlset", j_query, &j_response); @@ -236,7 +234,7 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName case DEVICEURITYPE_ALSA_PLUG: case DEVICEURITYPE_ALSA_SOFTVOL: gsHALControlName = g_string_new(AudioRole); - g_string_append(gsHALControlName,"_Vol"); // Or _Vol for direct control (no ramping) + g_string_append(gsHALControlName,"_Vol"); // Return target value break; default: // Set volume to zero for display purpose only. @@ -257,8 +255,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName return POLICY_FAIL; } - //TODO implement Volume limitation based on policy - // Get the volume using the HAL err = afb_service_call_sync(pHalApiName, "ctlget", j_query, &j_response); if (err) @@ -282,8 +278,7 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName if (err) { AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); return POLICY_FAIL; - } - + } } else { @@ -292,7 +287,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); return POLICY_FAIL; } - } *pVolume = val1; @@ -313,7 +307,6 @@ static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName static void PolicyPostStateEvent(int iStreamID, StreamEventT eventState) { - json_object * eventDataJ = NULL; int err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i}","event_name", AHL_STREAM_STATE_EVENT,"stream_id",iStreamID, "state_event",eventState); if (err) @@ -352,7 +345,6 @@ static EndPointPolicyInfoT *PolicySearchEndPoint(EndpointTypeT type, char *pDevi return NULL; } - static int PolicyAddEndPoint(StreamInterfaceInfoT *pStreamInfo) { EndPointPolicyInfoT *pPolicyEndPoint = PolicySearchEndPoint(pStreamInfo->endpoint.type, pStreamInfo->endpoint.gsDeviceName); @@ -366,7 +358,7 @@ static int PolicyAddEndPoint(StreamInterfaceInfoT *pStreamInfo) 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));; + newEndPointPolicyInfo.streamInfo = g_array_new(FALSE, TRUE, sizeof(StreamPolicyInfoT)); if(pStreamInfo->endpoint.type == ENDPOINTTYPE_SINK) { @@ -381,7 +373,6 @@ static int PolicyAddEndPoint(StreamInterfaceInfoT *pStreamInfo) return POLICY_SUCCESS; } - static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInterfaceInfoT *pStreamInfo) { StreamPolicyInfoT newStreamPolicyInfo; @@ -400,11 +391,10 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, int err=0; if(pCurrEndPointPolicy == NULL || pCurrEndPointPolicy->streamInfo->len == 0) { - //Remove endpoint - AFB_ERROR("StreamID not found in active Endpoint when Running to Idle transition is request"); + AFB_ERROR("StreamID not found in active endpoint when running to idle transition is requested"); return POLICY_FAIL; } - //Search for the matching stream + // Search for the matching stream for(int i=0; i<pCurrEndPointPolicy->streamInfo->len; i++) { StreamPolicyInfoT currentPolicyStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,i); @@ -420,7 +410,7 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, { case INTERRUPTBEHAVIOR_CONTINUE: //unduck and set Volume back to original value - err= PolicySetVolume(pCurrEndPointPolicy->endpointID, + err = PolicySetVolume(pCurrEndPointPolicy->endpointID, pCurrEndPointPolicy->type, pCurrEndPointPolicy->pHalApiName, HighPriorityStreamInfo.pAudioRole, @@ -434,10 +424,8 @@ static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, return POLICY_SUCCESS; case INTERRUPTBEHAVIOR_PAUSE: - //pInterruptStreamInfo->streamState = STREAM_STATE_RUNNING; PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_RESUME); return POLICY_SUCCESS; - case INTERRUPTBEHAVIOR_CANCEL: PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_START); return POLICY_SUCCESS; @@ -483,7 +471,7 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, AFB_ERROR("Error getting stream configuration for audiorole: %s", pStreamInfo->pRoleName); return POLICY_FAIL; } - err= PolicySetVolume(pCurrEndPointPolicy->endpointID, + err = PolicySetVolume(pCurrEndPointPolicy->endpointID, pCurrEndPointPolicy->type, pCurrEndPointPolicy->pHalApiName, pCurrentActiveStreamInfo->pAudioRole, @@ -499,7 +487,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, case INTERRUPTBEHAVIOR_PAUSE: PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_PAUSE); break; - case INTERRUPTBEHAVIOR_CANCEL: PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_STOP); g_array_remove_index(pCurrEndPointPolicy->streamInfo, pCurrEndPointPolicy->streamInfo->len-1); @@ -507,8 +494,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, default: AFB_ERROR("Unsupported Intterupt Behavior"); return AHL_POLICY_REJECT; - break; - } //Add the playing stream at last @@ -527,7 +512,6 @@ static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, static void PolicySpeedModify(int speed) { - for(int i=0; i<g_PolicyCtx.pSinkEndpoints->len; i++) { EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSinkEndpoints,EndPointPolicyInfoT,i); @@ -584,9 +568,8 @@ static int RetrieveAssociatedHALAPIName(int iAlsaCardNumber,char ** out_pDisplay static int GetHALList(void) { - json_object *j_response, *j_query = NULL; - int err; - err = afb_service_call_sync("alsacore", "hallist", j_query, &j_response); + json_object *j_response = NULL, *j_query = NULL; + int err = afb_service_call_sync("alsacore", "hallist", j_query, &j_response); if (err) { AFB_ERROR("Could not retrieve list of HAL from ALSA core"); return POLICY_FAIL; @@ -637,7 +620,7 @@ int Policy_OpenStream(json_object *pStreamJ) int err = JSONToStream(pStreamJ, &Stream); if(err == AHL_POLICY_UTIL_FAIL) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } // Example rule -> when system is in shutdown or low power mode, no audio stream can be opened (return AHL_POLICY_REJECT) @@ -651,16 +634,17 @@ int Policy_OpenStream(json_object *pStreamJ) err = getStreamConfig(Stream.pRoleName, &StreamConfig); if(err == POLICY_FAIL) { - return AHL_POLICY_ACCEPT; + 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); + 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; @@ -677,39 +661,38 @@ int Policy_OpenStream(json_object *pStreamJ) int Policy_CloseStream(json_object *pStreamJ) { - //TODO remove Endpoint when there is no stream StreamInterfaceInfoT Stream; int err = JSONToStream(pStreamJ, &Stream); if(err == AHL_POLICY_UTIL_FAIL) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } return AHL_POLICY_ACCEPT; } int Policy_SetStreamState(json_object *pStreamJ) -{ - //TODO - // Optional: Mute endpoint before activation, unmute afterwards (after a delay?) to avoid noises +{ + // 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_ACCEPT; + return AHL_POLICY_REJECT; } - json_object *streamStateJ=NULL; + json_object *streamStateJ = NULL; if(!json_object_object_get_ex(pStreamJ, "arg_stream_state", &streamStateJ)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } streamState = (StreamStateT)json_object_get_int(streamStateJ); - //Change of state + // Change of state if(Stream.streamState != streamState) { //seach corresponding endpoint and gather information on it @@ -738,7 +721,6 @@ int Policy_SetStreamState(json_object *pStreamJ) break; default: return AHL_POLICY_REJECT; - break; } break; case STREAM_STATE_RUNNING: @@ -757,7 +739,6 @@ int Policy_SetStreamState(json_object *pStreamJ) break; default: return AHL_POLICY_REJECT; - break; } break; case STREAM_STATE_PAUSED: @@ -776,12 +757,10 @@ int Policy_SetStreamState(json_object *pStreamJ) break; default: return AHL_POLICY_REJECT; - break; } break; default: return AHL_POLICY_REJECT; - break; } } return AHL_POLICY_ACCEPT; @@ -789,21 +768,21 @@ int Policy_SetStreamState(json_object *pStreamJ) 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_ACCEPT; + return AHL_POLICY_REJECT; } json_object *streamMuteJ=NULL; if(!json_object_object_get_ex(pStreamJ, "mute_state", &streamMuteJ)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } streamMute = (StreamMuteT)json_object_get_int(streamMuteJ); @@ -811,14 +790,13 @@ int Policy_SetStreamMute(json_object *pStreamJ) { if(streamMute == STREAM_MUTED) { - - err= PolicySetVolume(Stream.endpoint.endpointID, + err = PolicySetVolume(Stream.endpoint.endpointID, Stream.endpoint.type, Stream.endpoint.gsHALAPIName, Stream.pRoleName, Stream.endpoint.deviceURIType, - 0, - true); + 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); @@ -828,13 +806,13 @@ int Policy_SetStreamMute(json_object *pStreamJ) } else { - err= PolicySetVolume(Stream.endpoint.endpointID, + err = PolicySetVolume(Stream.endpoint.endpointID, Stream.endpoint.type, Stream.endpoint.gsHALAPIName, Stream.pRoleName, Stream.endpoint.deviceURIType, - Stream.endpoint.iVolume, - true); + 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); @@ -855,31 +833,30 @@ int Policy_SetVolume(json_object *pEndpointJ) int err = JSONToEndpoint(pEndpointJ, &Endpoint); if(err == AHL_POLICY_UTIL_FAIL) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } - json_object *volumeJ=NULL; - + json_object *volumeJ = NULL; if(!json_object_object_get_ex(pEndpointJ, "arg_volume", &volumeJ)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } volumeStr = (char*)json_object_get_string(volumeJ); - // TODO: Parse volume string to support increment/absolute/percent notation (or delegate to action / policy layer to interpret) + // TODO: Parse volume string to support increment/absolute/percent notation int vol = atoi(volumeStr); - //Set the volume - err= PolicySetVolume(Endpoint.endpointID, - Endpoint.type, - Endpoint.gsHALAPIName, - Endpoint.pRoleName, - Endpoint.deviceURIType, - vol, - false); + // Set the volume + err = PolicySetVolume(Endpoint.endpointID, + Endpoint.type, + Endpoint.gsHALAPIName, + Endpoint.pRoleName, + Endpoint.deviceURIType, + vol, + false); // Volume ramp and send events if (err) { - AFB_ERROR("Set Volume return with errorcode%i", err); + AFB_ERROR("Set Volume return with errorcode %i", err); return AHL_POLICY_REJECT; } @@ -888,35 +865,33 @@ int Policy_SetVolume(json_object *pEndpointJ) 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_ACCEPT; + return AHL_POLICY_REJECT; } - json_object *propertyNameJ=NULL; - + json_object *propertyNameJ = NULL; if(!json_object_object_get_ex(pEndpointJ, "arg_property_name", &propertyNameJ)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } propertyName = (char*)json_object_get_string(propertyNameJ); - json_object *propValueJ; + json_object *propValueJ = NULL; if(!json_object_object_get_ex(pEndpointJ, "arg_property_value", &propValueJ)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } json_type currentTypeJ = json_object_get_type(propValueJ); - json_object *propArray; + json_object *propArray = NULL; if(!json_object_object_get_ex(pEndpointJ, "properties", &propArray)) { - return AHL_POLICY_ACCEPT; + return AHL_POLICY_REJECT; } int iPropArrayLen = json_object_array_length(propArray); @@ -937,11 +912,10 @@ int Policy_SetProperty(json_object *pEndpointJ) json_object *propElementValueJ=NULL; if(!json_object_object_get_ex(propElementJ, "property_value", &propElementValueJ)) { - //Get JsonObjectype 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 + // 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"); @@ -961,7 +935,7 @@ int Policy_SetProperty(json_object *pEndpointJ) return AHL_POLICY_REJECT; } - //Create a new Json Object + // Create a new Json Object json_object *pEventDataJ = NULL; err = wrap_json_pack(&pEventDataJ,"{s:s,s:i,s:i,s:s,s:o,s:s}", "event_name", AHL_ENDPOINT_PROPERTY_EVENT, @@ -975,7 +949,8 @@ int Policy_SetProperty(json_object *pEndpointJ) AFB_ERROR("Unable to pack property event"); return AHL_POLICY_REJECT; } - //Raise Event to update HLB + + // Raise Event to update HLB audiohlapi_raise_event(pEventDataJ); return AHL_POLICY_ACCEPT; @@ -1006,6 +981,7 @@ int Policy_PostAction(json_object *pPolicyActionJ) AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); return AHL_POLICY_REJECT; } + audiohlapi_raise_event(pEventDataJ); return AHL_POLICY_ACCEPT; @@ -1016,6 +992,7 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic 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; @@ -1028,7 +1005,7 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic "device_name", &pDeviceName ); if (err) { AFB_ERROR("Unable to unpack JSON endpoint, =%s", wrap_json_get_error_string(err)); - return AHL_POLICY_REJECT; + goto OnError; } StreamConfigT StreamConfig; @@ -1036,20 +1013,18 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic char * pDisplayName = NULL; char * pHALName = NULL; - int iAllocString = 0; if (deviceURIType != DEVICEURITYPE_NOT_ALSA) { // Update Hal Name - err = RetrieveAssociatedHALAPIName(iAlsaCardNumber,&pDisplayName,&pHALName); if (err) { - AFB_WARNING("HAL not found for Device %s", pDeviceName); + 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 Init Volume + // Set initial Volume err = PolicySetVolume(endpointID, endpointType, pHALName, @@ -1057,8 +1032,8 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic deviceURIType, StreamConfig.iVolumeInit, true); // Do not raise event and no volume ramp - if(err) { - return AHL_POLICY_REJECT; + if(err) { + goto OnError; } } } @@ -1069,7 +1044,6 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic iAllocString = 1; } - // Populate special device property (TODO: Should be obtained from HAL) // if (strcasecmp(gsHALAPIName,"Device")==0) // { @@ -1091,37 +1065,53 @@ int Policy_Endpoint_Init(json_object *pInPolicyEndpointJ,json_object **pOutPolic ); if (err) { AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); - return AHL_POLICY_REJECT; + 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; - // TODO: Future policy binding to return request response with pOutPolicyEndpointJ - - return AHL_POLICY_ACCEPT; // No errors } int Policy_Init() { + // Start fresh + memset(&g_PolicyCtx,0,sizeof(g_PolicyCtx)); + // Initialize Ressources - g_PolicyCtx.pSourceEndpoints =g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); + g_PolicyCtx.pSourceEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); g_PolicyCtx.pSinkEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); g_PolicyCtx.pHALList = g_ptr_array_new_with_free_func(g_free); - //Get HalList + //Require AlsaCore Dependency + int err = afb_daemon_require_api_v2(AHL_POLICY_ALSA_API,1) ; + if( err != 0 ) + { + AFB_ERROR("Audio Policy could not set dependency on alsacore API"); + return AHL_POLICY_REJECT; + } + + // Get HalList GetHALList(); - //Set System Normal for now, this should be set by an event - //TODO: Receive event from low level + // TODO: Register events from low level / HAL for dynamic changes + + // Set System Normal for now, this should be set by an event g_PolicyCtx.systemState = SYSTEM_NORMAL; - //register audio backend events - //This is to simulate can bus, only used for demo - json_object *queryurl, *responseJ, *eventsJ; - + + +#ifdef AK_POLICY_DEMO + // Register audio backend events (TODO: should instead do this with signal composer with appropriate dependency) + // This is to simulate can bus, only used for demo + json_object *queryurl = NULL, *responseJ = NULL, *eventsJ = NULL; eventsJ = json_object_new_array(); json_object_array_add(eventsJ, json_object_new_string("audiod_system_event")); queryurl = json_object_new_object(); @@ -1131,12 +1121,15 @@ int Policy_Init() AFB_ERROR("Fail subscribing to Audio Backend System events"); return AHL_POLICY_REJECT; } +#endif + + return AHL_POLICY_ACCEPT; } void Policy_Term() { - //Free Ressources + // Free Ressources if (g_PolicyCtx.pHALList) { g_ptr_array_free(g_PolicyCtx.pHALList,TRUE); g_PolicyCtx.pHALList = NULL; @@ -1162,6 +1155,7 @@ void Policy_Term() g_PolicyCtx.pSinkEndpoints = NULL; } +// For demo purpose only, should be listening to signal composer / CAN events instead void Policy_OnEvent(const char *evtname, json_object *eventJ) { AFB_DEBUG("Policy received event %s", evtname); @@ -1185,7 +1179,7 @@ void Policy_OnEvent(const char *evtname, json_object *eventJ) AFB_WARNING("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(event_parameter)); return; } - //When speed change Modify volume on Endpoint where entertainment change + // When speed change Modify volume on Endpoint where entertainment change PolicySpeedModify(speed); } } diff --git a/src/ahl-policy.h b/src/ahl-policy.h index b46bbb9..0200973 100644 --- a/src/ahl-policy.h +++ b/src/ahl-policy.h @@ -16,6 +16,7 @@ #ifndef AHL_POLICY_INCLUDE #define AHL_POLICY_INCLUDE + #include "ahl-policy-utils.h" #ifndef AHL_DISCONNECT_POLICY @@ -27,6 +28,8 @@ #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); @@ -39,6 +42,8 @@ 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 |