summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--conf.d/project/agl-ahl-config.json8
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/ahl-binding.c71
-rw-r--r--src/ahl-binding.h4
-rw-r--r--src/ahl-config.c21
-rw-r--r--src/ahl-deviceenum.c30
-rw-r--r--src/ahl-json.c296
-rw-r--r--src/ahl-json.h26
-rwxr-xr-xsrc/ahl-policy-utils.c23
-rwxr-xr-xsrc/ahl-policy-utils.h7
-rw-r--r--src/ahl-policy.c234
-rw-r--r--src/ahl-policy.h5
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