summaryrefslogtreecommitdiffstats
path: root/src/ahl-binding.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ahl-binding.c')
-rw-r--r--src/ahl-binding.c1245
1 files changed, 886 insertions, 359 deletions
diff --git a/src/ahl-binding.c b/src/ahl-binding.c
index fe3dcee..cd89b64 100644
--- a/src/ahl-binding.c
+++ b/src/ahl-binding.c
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2017 "Audiokinetic Inc"
- * Author Francois Thibault <fthibault@audiokinetic.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,10 +21,106 @@
#include "ahl-binding.h"
#include "ahl-apidef.h" // Generated from JSON OpenAPI
#include "wrap-json.h"
+#include "ahl-policy.h"
+#include "ahl-policy-utils.h"
// Global high-level binding context
AHLCtxT g_AHLCtx;
+// TODO: Helpers that could be common
+static EndpointTypeT EndpointTypeToEnum(char * in_pEndpointTypeStr)
+{
+ if (in_pEndpointTypeStr == NULL) {
+ return ENDPOINTTYPE_MAXVALUE;
+ }
+ else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SOURCE)==0) {
+ return ENDPOINTTYPE_SOURCE;
+ }
+ else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SINK)==0) {
+ return ENDPOINTTYPE_SINK;
+ }
+ else
+ return ENDPOINTTYPE_MAXVALUE;
+}
+
+static StreamStateT StreamStateToEnum(char * in_pStreamStateStr)
+{
+ if (in_pStreamStateStr == NULL) {
+ return STREAM_STATE_MAXVALUE;
+ }
+ else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_IDLE)==0) {
+ return STREAM_STATE_IDLE;
+ }
+ else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_RUNNING)==0) {
+ return STREAM_STATE_RUNNING;
+ }
+ else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_PAUSED)==0) {
+ return STREAM_STATE_PAUSED;
+ }
+ else
+ return STREAM_STATE_MAXVALUE;
+}
+
+static StreamMuteT StreamMuteToEnum(char * in_pStreamMuteStr)
+{
+ if (in_pStreamMuteStr == NULL) {
+ return STREAM_MUTE_MAXVALUE;
+ }
+ else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_UNMUTED)==0) {
+ return STREAM_UNMUTED;
+ }
+ else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_MUTED)==0) {
+ return STREAM_MUTED;
+ }
+ else
+ return STREAM_MUTE_MAXVALUE;
+}
+
+static char * DeviceURITypeEnumToStr(DeviceURITypeT in_eDeviceURIType) {
+ switch(in_eDeviceURIType) {
+ case DEVICEURITYPE_ALSA_HW: // Alsa hardware device URI
+ return AHL_DEVICEURITYPE_ALSA_HW;
+ case DEVICEURITYPE_ALSA_DMIX: // Alsa Dmix device URI (only for playback devices)
+ return AHL_DEVICEURITYPE_ALSA_DMIX;
+ case DEVICEURITYPE_ALSA_DSNOOP: // Alsa DSnoop device URI (only for capture devices)
+ return AHL_DEVICEURITYPE_ALSA_DSNOOP;
+ case DEVICEURITYPE_ALSA_SOFTVOL: // Alsa softvol device URI
+ return AHL_DEVICEURITYPE_ALSA_SOFTVOL;
+ case DEVICEURITYPE_ALSA_PLUG: // Alsa plug device URI
+ return AHL_DEVICEURITYPE_ALSA_PLUG;
+ case DEVICEURITYPE_ALSA_OTHER: // Alsa domain URI device of unspecified type
+ return AHL_DEVICEURITYPE_ALSA_OTHER;
+ case DEVICEURITYPE_NOT_ALSA: // Unknown (not ALSA domain)
+ return AHL_DEVICEURITYPE_NOT_ALSA;
+ default:
+ return "Unknown";
+ }
+}
+
+static char * StreamStateEnumToStr(StreamStateT in_eStreamState) {
+ switch(in_eStreamState) {
+ case STREAM_STATE_IDLE:
+ return AHL_STREAM_STATE_IDLE;
+ case STREAM_STATE_RUNNING:
+ return AHL_STREAM_STATE_RUNNING;
+ case STREAM_STATE_PAUSED:
+ return AHL_STREAM_STATE_PAUSED;
+ default:
+ return "Unknown";
+ }
+}
+
+static char * StreamMuteEnumToStr(StreamMuteT in_eStreamMute) {
+ switch(in_eStreamMute) {
+ case STREAM_UNMUTED:
+ return AHL_STREAM_UNMUTED;
+ case STREAM_MUTED:
+ return AHL_STREAM_MUTED;
+ default:
+ return "Unknown";
+ }
+}
+
static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * pAudioFormat)
{
wrap_json_pack(audioFormatJ, "{s:i,s:i,s:i}",
@@ -34,29 +129,52 @@ static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * p
"sample_type", pAudioFormat->sampleType);
}
-// Helper macros/func for packaging JSON objects from C structures
+// Package only information that can useful to application clients when selecting endpoint
static void EndpointInfoStructToJSON(json_object **endpointInfoJ, EndpointInfoT * pEndpointInfo)
{
json_object *formatInfoJ = NULL;
- wrap_json_pack(endpointInfoJ, "{s:i,s:i,s:s,s:s,s:i}",
+ 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,
- "device_name", pEndpointInfo->gsDeviceName->str,
- "display_name", pEndpointInfo->gsDisplayName->str,
- "device_uri_type", pEndpointInfo->deviceURIType);
+ "endpoint_type", (pEndpointInfo->type == ENDPOINTTYPE_SOURCE) ? AHL_ENDPOINTTYPE_SOURCE : AHL_ENDPOINTTYPE_SINK,
+ "device_name", pEndpointInfo->gsDeviceName,
+ "display_name", pEndpointInfo->gsDisplayName,
+ "audio_role", pEndpointInfo->pRoleName,
+ "device_domain",pEndpointInfo->gsDeviceDomain,
+ "device_uri_type", DeviceURITypeEnumToStr(pEndpointInfo->deviceURIType));
AudioFormatStructToJSON(&formatInfoJ,&pEndpointInfo->format);
json_object_object_add(*endpointInfoJ,"format",formatInfoJ);
+
+ // Properties
+ if (pEndpointInfo->pPropTable) {
+ json_object *pPropTableJ = json_object_new_array();
+
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init (&iter, pEndpointInfo->pPropTable);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if((key!=NULL) && (value!=NULL))
+ {
+ json_object *pPropertyJ = NULL;
+ json_object_get((json_object*)value); // Don't let the framework free our object when the request is done
+ wrap_json_pack(&pPropertyJ, "{s:s,s:o}","property_name", (char*)key, "property_value", (json_object*)value);
+ json_object_array_add(pPropTableJ, pPropertyJ);
+ }
+ }
+ json_object_object_add(*endpointInfoJ,"properties",pPropTableJ);
+ }
}
+// Package only information that can useful to application clients when opening a stream
static void StreamInfoStructToJSON(json_object **streamInfoJ, StreamInfoT * pStreamInfo)
{
json_object *endpointInfoJ = NULL;
EndpointInfoStructToJSON(&endpointInfoJ,pStreamInfo->pEndpointInfo);
- wrap_json_pack(streamInfoJ, "{s:i,s:i,s:i,s:s}",
+ wrap_json_pack(streamInfoJ, "{s:i,s:s,s:s,s:s}",
"stream_id", pStreamInfo->streamID,
- "state", pStreamInfo->streamState,
- "mute", pStreamInfo->streamMute,
- "device_uri",pStreamInfo->pEndpointInfo->gsDeviceURI->str);
+ "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);
}
@@ -67,62 +185,91 @@ static streamID_t CreateNewStreamID()
return newID;
}
-static int FindRoleIndex( const char * in_pAudioRole)
+static EndpointInfoT * GetEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole)
{
- int index = -1; // Not found
- for (int i = 0; i < g_AHLCtx.policyCtx.iNumberRoles; i++)
- {
- GString gs = g_array_index( g_AHLCtx.policyCtx.pAudioRoles, GString, i );
- if ( strcasecmp(gs.str,in_pAudioRole) == 0 )
- {
- index = i;
+ EndpointInfoT * pEndpointInfo = NULL;
+ GPtrArray * pDeviceArray = NULL;
+ if (in_endpointType == ENDPOINTTYPE_SOURCE){
+ pDeviceArray = in_pRole->pSourceEndpoints;
+ }
+ else {
+ pDeviceArray = in_pRole->pSinkEndpoints;
+ }
+ g_assert_nonnull(pDeviceArray);
+
+ for (int j = 0; j < pDeviceArray->len; j++) {
+ EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pDeviceArray,j);
+ g_assert_nonnull(pCurEndpointInfo);
+ if (pCurEndpointInfo->endpointID == in_endpointID) {
+ pEndpointInfo = pCurEndpointInfo;
break;
}
}
- return index;
+
+ return pEndpointInfo;
+}
+
+static int ReplaceEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole, EndpointInfoT * in_pNewEndpoint)
+{
+ GPtrArray * pDeviceArray = NULL;
+ if (in_endpointType == ENDPOINTTYPE_SOURCE){
+ pDeviceArray = in_pRole->pSourceEndpoints;
+ }
+ else {
+ pDeviceArray = in_pRole->pSinkEndpoints;
+ }
+ g_assert_nonnull(pDeviceArray);
+
+ for (int j = 0; j < pDeviceArray->len; j++) {
+ EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pDeviceArray,j);
+ g_assert_nonnull(pCurEndpointInfo);
+ if (pCurEndpointInfo->endpointID == in_endpointID) {
+ g_ptr_array_insert(pDeviceArray,j,in_pNewEndpoint);
+ g_ptr_array_remove_index(pDeviceArray,j+1);
+ TermEndpointInfo(pCurEndpointInfo);
+ // GLib automatically frees item upon array removal
+ return AHL_SUCCESS;
+ }
+ }
+
+ return AHL_FAIL;
}
static EndpointInfoT * GetEndpointInfo(endpointID_t in_endpointID, EndpointTypeT in_endpointType)
{
EndpointInfoT * pEndpointInfo = NULL;
- for (int i = 0; i < g_AHLCtx.policyCtx.iNumberRoles; i++)
+
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo);
+ while (pEndpointInfo == NULL && g_hash_table_iter_next (&iter, &key, &value))
{
- GArray * pRoleDeviceArray = NULL;
- if (in_endpointType == ENDPOINTTYPE_SOURCE){
- pRoleDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSourceEndpoints, i );
- }
- else{
- pRoleDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSinkEndpoints, i );
- }
- for (int j = 0; j < pRoleDeviceArray->len; j++) {
- EndpointInfoT * pCurEndpointInfo = &g_array_index(pRoleDeviceArray,EndpointInfoT,j);
- if (pCurEndpointInfo->endpointID == in_endpointID) {
- pEndpointInfo = pCurEndpointInfo;
- break;
- }
- }
+ RoleInfoT * pRoleInfo = (RoleInfoT*)value;
+ pEndpointInfo = GetEndpointInfoWithRole(in_endpointID,in_endpointType,pRoleInfo);
}
+
return pEndpointInfo;
}
-static StreamInfoT * GetActiveStream(streamID_t in_streamID)
+static StreamInfoT * GetStream(streamID_t in_streamID)
{
- int iNumActiveStreams = g_AHLCtx.policyCtx.pActiveStreams->len;
- StreamInfoT * pStreamInfo = NULL;
- for ( int i = 0; i < iNumActiveStreams ; i++ ) {
- StreamInfoT * pCurStreamInfo = &g_array_index(g_AHLCtx.policyCtx.pActiveStreams,StreamInfoT,i);
- if (pCurStreamInfo->streamID == in_streamID){
- pStreamInfo = pCurStreamInfo;
- break;
- }
- }
- return pStreamInfo;
+ if (g_AHLCtx.policyCtx.pStreams == NULL)
+ return NULL;
+
+ return g_hash_table_lookup(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&in_streamID));
+}
+
+static RoleInfoT * GetRole(char * in_pAudioRoleName)
+{
+ if (g_AHLCtx.policyCtx.pRoleInfo == NULL)
+ return NULL;
+
+ return g_hash_table_lookup(g_AHLCtx.policyCtx.pRoleInfo,in_pAudioRoleName);
}
static AHLClientCtxT * AllocateClientContext()
{
AHLClientCtxT * pClientCtx = malloc(sizeof(AHLClientCtxT));
- pClientCtx->pEndpointAccessList = g_array_new(FALSE, TRUE, sizeof(endpointID_t));
pClientCtx->pStreamAccessList = g_array_new(FALSE, TRUE, sizeof(streamID_t));
return pClientCtx;
}
@@ -130,31 +277,50 @@ static AHLClientCtxT * AllocateClientContext()
static void TerminateClientContext(void * ptr)
{
AHLClientCtxT * pClientCtx = (AHLClientCtxT *) ptr;
- g_array_free( pClientCtx->pEndpointAccessList, TRUE);
- g_array_free( pClientCtx->pStreamAccessList, TRUE);
- free(ptr);
-}
+ if (pClientCtx != NULL) {
-static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t streamID)
-{
- int iAccessControl = AHL_ACCESS_CONTROL_DENIED;
- for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) {
- streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
- if (iID == streamID) {
- iAccessControl = AHL_ACCESS_CONTROL_GRANTED;
- }
+ // Avoid having policy in bad state if client loses WS connection (e.g. app termination without close stream)
+ // Force close streams in those cases.
+
+ if (pClientCtx->pStreamAccessList != NULL) {
+#ifndef AHL_DISCONNECT_POLICY
+ for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++)
+ {
+ streamID_t streamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
+ // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
+ StreamInfoT * pStreamInfo = GetStream(streamID);
+ if (pStreamInfo == NULL) {
+ AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID);
+ return;
+ }
+
+ json_object *pPolicyStreamJ = NULL;
+ int err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_FAIL)
+ {
+ AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream");
+ return;
+ }
+ Policy_CloseStream(pPolicyStreamJ);
+ }
+#endif
+ g_array_free( pClientCtx->pStreamAccessList, TRUE);
+ pClientCtx->pStreamAccessList = NULL;
+ }
+ free(pClientCtx);
}
- return iAccessControl;
}
-static int CheckEndpointAccessControl(AHLClientCtxT * pClientCtx, endpointID_t endpointID)
+static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t streamID)
{
int iAccessControl = AHL_ACCESS_CONTROL_DENIED;
- for (int i = 0; i < pClientCtx->pEndpointAccessList->len ; i++) {
- endpointID_t iID = g_array_index(pClientCtx->pEndpointAccessList,endpointID_t,i);
- if (iID == endpointID) {
- iAccessControl = AHL_ACCESS_CONTROL_GRANTED;
- }
+ if (pClientCtx && pClientCtx->pStreamAccessList) {
+ for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) {
+ streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
+ if (iID == streamID) {
+ iAccessControl = AHL_ACCESS_CONTROL_GRANTED;
+ }
+ }
}
return iAccessControl;
}
@@ -167,21 +333,21 @@ static int CreateEvents()
err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent);
if (err) {
AFB_ERROR("Could not create endpoint property change event");
- err++;
+ return err;
}
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");
- err++;
+ return err;
}
- g_AHLCtx.policyCtx.postEvent = afb_daemon_make_event(AHL_POST_EVENT);
- err = !afb_event_is_valid(g_AHLCtx.policyCtx.postEvent);
+ 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 event call event");
- err++;
+ AFB_ERROR("Could not create post action event call event");
+ return err;
}
return err;
@@ -189,90 +355,205 @@ static int CreateEvents()
static void AhlBindingTerm()
{
+#ifndef AHL_DISCONNECT_POLICY
// Policy termination
Policy_Term();
-
- // Events
- for (int i = 0; i < g_AHLCtx.policyCtx.pEventList->len; i++)
- {
- // For each event within the role
- GArray * pRoleEventArray = g_ptr_array_index( g_AHLCtx.policyCtx.pEventList, i );
- for (int j = 0 ; j < pRoleEventArray->len; j++)
+#endif
+
+ // Roles
+ if (g_AHLCtx.policyCtx.pRoleInfo != NULL) {
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init(&iter, g_AHLCtx.policyCtx.pRoleInfo);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- GString * gsEventName = &g_array_index(pRoleEventArray,GString,j);
- g_string_free(gsEventName,TRUE);
+ RoleInfoT * pRole = (RoleInfoT *)value;
+ if (pRole)
+ {
+ if(pRole->pRoleName) {
+ g_free(pRole->pRoleName);
+ pRole->pRoleName = NULL;
+ }
+ // Actions
+ if (pRole->pActionList) {
+ for (int i = 0; i < pRole->pActionList->len; i++)
+ {
+ g_ptr_array_remove_index( pRole->pActionList, i ); // Free char * is called by GLib
+ }
+ }
+ // Source endpoints
+ if (pRole->pSourceEndpoints) {
+ for (int i = 0; i < pRole->pSourceEndpoints->len; i++)
+ {
+ EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSourceEndpoints, i ); // Free endpoint * is called by GLib
+ if (pEndpoint) {
+ TermEndpointInfo(pEndpoint);
+ }
+ }
+ }
+ // Sink endpoints
+ if (pRole->pSinkEndpoints) {
+ for (int i = 0; i < pRole->pSinkEndpoints->len; i++)
+ {
+ EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSinkEndpoints, i ); // Free endpoint * is called by GLib
+ if (pEndpoint) {
+ TermEndpointInfo(pEndpoint);
+ }
+ }
+ }
+ free(pRole);
+ }
}
- g_array_free(pRoleEventArray,TRUE);
- pRoleEventArray = NULL;
- }
- g_ptr_array_free(g_AHLCtx.policyCtx.pEventList,TRUE);
- g_AHLCtx.policyCtx.pEventList = NULL;
-
- // Endpoints
- TermEndpoints();
-
- // TODO: Need to free g_strings in HAL list
- g_array_free(g_AHLCtx.pHALList,TRUE);
- g_AHLCtx.pHALList = NULL;
- g_hash_table_remove_all(g_AHLCtx.policyCtx.pRolePriority);
- g_hash_table_destroy(g_AHLCtx.policyCtx.pRolePriority);
- g_AHLCtx.policyCtx.pRolePriority = NULL;
- // TODO: Need to free g_strings in audio roles list
- g_array_free(g_AHLCtx.policyCtx.pAudioRoles,TRUE);
- g_AHLCtx.policyCtx.pAudioRoles = NULL;
- g_array_free(g_AHLCtx.policyCtx.pInterruptBehavior,TRUE);
- g_AHLCtx.policyCtx.pInterruptBehavior = NULL;
- g_array_free(g_AHLCtx.policyCtx.pActiveStreams,TRUE);
- g_AHLCtx.policyCtx.pActiveStreams = NULL;
-
- AFB_INFO("Audio high-level Binding succesTermination");
+ g_hash_table_remove_all(g_AHLCtx.policyCtx.pRoleInfo);
+ g_hash_table_destroy(g_AHLCtx.policyCtx.pRoleInfo);
+ g_AHLCtx.policyCtx.pRoleInfo = NULL;
+ }
+
+ if (g_AHLCtx.policyCtx.pStreams) {
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pStreams);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if (value)
+ free(value);
+ }
+ g_hash_table_remove_all(g_AHLCtx.policyCtx.pStreams);
+ g_hash_table_destroy(g_AHLCtx.policyCtx.pStreams);
+ g_AHLCtx.policyCtx.pStreams = NULL;
+ }
+
+ if (g_AHLCtx.policyCtx.pHALList) {
+ g_ptr_array_free(g_AHLCtx.policyCtx.pHALList,TRUE);
+ g_AHLCtx.policyCtx.pHALList = NULL;
+ }
+
+ AFB_INFO("Audio high-level binding termination success");
}
// Binding initialization
PUBLIC int AhlBindingInit()
{
- int errcount = 0;
+ int err = 0;
+ memset(&g_AHLCtx,0,sizeof(g_AHLCtx));
+
+ // Register exit function
atexit(AhlBindingTerm);
- // This API uses services from low level audio. TODO: This dependency can be removed.
- errcount = afb_daemon_require_api_v2("alsacore",1) ;
- if( errcount != 0 )
+ //Create AGL Events
+ err=CreateEvents();
+ if(err)
{
- AFB_ERROR("Audio high level API requires alsacore API to be available");
- return 1;
+ //Error messages already reported inside CreateEvents
+ return err;
}
- errcount += CreateEvents();
-
// Parse high-level binding JSON configuration file (will build device lists)
- errcount += ParseHLBConfig();
-
+ err = ParseHLBConfig();
+ if(err)
+ {
+ //Error messages already reported inside ParseHLBConfig
+ return err;
+ }
+
+#ifndef AHL_DISCONNECT_POLICY
// Policy initialization
- errcount += Policy_Init();
+ err = Policy_Init();
+ if(err == AHL_POLICY_REJECT)
+ {
+ //Error messages already reported inside PolicyInit
+ return err;
+ }
+
+ // for all audio Roles
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ RoleInfoT * pRoleInfo = (RoleInfoT*)value;
+ if (pRoleInfo->pSourceEndpoints){
+ // for all source endpoints
+ for (int j = 0; j < pRoleInfo->pSourceEndpoints->len; j++) {
+ EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSourceEndpoints,j);
+ g_assert_nonnull(pCurEndpointInfo);
+ json_object *pPolicyEndpointJ = NULL;
+ err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_FAIL)
+ {
+ AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err));
+ return err;
+ }
+ else
+ {
+ err = Policy_Endpoint_Init(pPolicyEndpointJ);
+ if (err == AHL_POLICY_REJECT) {
+ AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ }
+ //free pPolicyEndpointJ
+ json_object_put(pPolicyEndpointJ);
+ }
+ }
+ }
+ if (pRoleInfo->pSinkEndpoints){
+ // for all sink endpoints
+ for (int j = 0; j < pRoleInfo->pSinkEndpoints->len; j++) {
+ EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSinkEndpoints,j);
+ g_assert_nonnull(pCurEndpointInfo);
+ json_object *pPolicyEndpointJ = NULL;
+ err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_FAIL)
+ {
+ AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err));
+ return err;
+ }
+ else
+ {
+ err = Policy_Endpoint_Init(pPolicyEndpointJ);
+ if (err== AHL_POLICY_REJECT) {
+ AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type);
+ }
+ //free pPolicyEndpointJ
+ json_object_put(pPolicyEndpointJ);
+ }
+
+ }
+ }
+ }
+#endif
// Initialize list of active streams
- g_AHLCtx.iNumActiveClients = 0;
- g_AHLCtx.policyCtx.pActiveStreams = g_array_new(FALSE,TRUE,sizeof(StreamInfoT));
+ g_AHLCtx.policyCtx.pStreams = g_hash_table_new(g_int_hash, g_int_equal);
+ if(g_AHLCtx.policyCtx.pStreams == NULL)
+ {
+ AFB_ERROR("Unable to create Active Stream List");
+ return err;
+ }
// TODO: Use AGL persistence framework to retrieve and set initial volumes/properties
- AFB_DEBUG("Audio high-level Binding success errcount=%d", errcount);
- return errcount;
+ AFB_DEBUG("Audio high-level Binding success");
+ return err;
}
PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ)
{
AFB_DEBUG("AHL received event %s", evtname);
+
+ // TODO: Handle event from the policy to update internal information (currently not possible since within the same binding)
- //forward to policy to handle events
+#ifndef AHL_DISCONNECT_POLICY
+ // Temp: currently forward to policy to handle events (they will be received directly when disconnected into separate binding)
Policy_OnEvent(evtname, eventJ);
+#endif
}
PUBLIC void audiohlapi_get_sources(struct afb_req req)
{
- json_object *sourcesJ = NULL;
- json_object *sourceJ = NULL;
+ json_object *devicesJ = NULL;
+ json_object *deviceJ = NULL;
json_object *queryJ = NULL;
char * audioRole = NULL;
@@ -284,36 +565,40 @@ PUBLIC void audiohlapi_get_sources(struct afb_req req)
}
AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole);
- // List device only for current audio role and device type (pick the role device list)
- int iRoleIndex = FindRoleIndex(audioRole);
- if ( iRoleIndex < 0)
+
+ RoleInfoT * pRole = GetRole(audioRole);
+ if ( pRole == NULL )
{
afb_req_fail_f(req, "Invalid arguments", "Requested audio role does not exist in current configuration -> %s", json_object_get_string(queryJ));
return;
}
else
{
- sourcesJ = json_object_new_array();
- GArray * pRoleSourceDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSourceEndpoints, iRoleIndex );
- int iNumberDevices = pRoleSourceDeviceArray->len;
- for ( int j = 0 ; j < iNumberDevices; j++)
- {
- EndpointInfoT sourceInfo = g_array_index(pRoleSourceDeviceArray,EndpointInfoT,j);
- EndpointInfoStructToJSON(&sourceJ, &sourceInfo);
- json_object_array_add(sourcesJ, sourceJ);
+ devicesJ = json_object_new_array();
+ GPtrArray * pDeviceArray = pRole->pSourceEndpoints;
+ if (pDeviceArray) {
+ int iNumberDevices = pDeviceArray->len;
+ for ( int j = 0 ; j < iNumberDevices; j++)
+ {
+ EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j);
+ if (pEndpointInfo) {
+ EndpointInfoStructToJSON(&deviceJ, pEndpointInfo);
+ json_object_array_add(devicesJ, deviceJ);
+ }
+ }
}
}
- afb_req_success(req, sourcesJ, "List of sources");
+ afb_req_success(req, devicesJ, "List of sources");
}
PUBLIC void audiohlapi_get_sinks(struct afb_req req)
{
- json_object *sinksJ = NULL;
- json_object *sinkJ = NULL;
+ json_object *devicesJ = NULL;
+ json_object *deviceJ = NULL;
json_object *queryJ = NULL;
char * audioRole = NULL;
-
+
queryJ = afb_req_json(req);
int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role", &audioRole);
if (err) {
@@ -322,136 +607,162 @@ PUBLIC void audiohlapi_get_sinks(struct afb_req req)
}
AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole);
- // List device only for current audio role and device type (pick the role device list)
- int iRoleIndex = FindRoleIndex(audioRole);
- if ( iRoleIndex < 0)
+
+ RoleInfoT * pRole = GetRole(audioRole);
+ if ( pRole == NULL )
{
afb_req_fail_f(req, "Invalid arguments", "Requested audio role does not exist in current configuration -> %s", json_object_get_string(queryJ));
return;
}
else
{
- sinksJ = json_object_new_array();
- GArray * pRoleSinkDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSinkEndpoints, iRoleIndex );
- int iNumberDevices = pRoleSinkDeviceArray->len;
- for ( int j = 0 ; j < iNumberDevices; j++)
- {
- EndpointInfoT sinkInfo = g_array_index(pRoleSinkDeviceArray,EndpointInfoT,j);
- EndpointInfoStructToJSON(&sinkJ, &sinkInfo);
- json_object_array_add(sinksJ, sinkJ);
+ devicesJ = json_object_new_array();
+ GPtrArray * pDeviceArray = pRole->pSinkEndpoints;
+ if (pDeviceArray) {
+ int iNumberDevices = pDeviceArray->len;
+ for ( int j = 0 ; j < iNumberDevices; j++)
+ {
+ EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j);
+ EndpointInfoStructToJSON(&deviceJ, pEndpointInfo);
+ json_object_array_add(devicesJ, deviceJ);
+ }
}
}
- afb_req_success(req, sinksJ, "List of sinks");
+ afb_req_success(req, devicesJ, "List of sinks");
}
PUBLIC void audiohlapi_stream_open(struct afb_req req)
{
json_object *streamInfoJ = NULL;
- StreamInfoT streamInfo;
+ StreamInfoT * pStreamInfo = NULL;
json_object *queryJ = NULL;
char * audioRole = NULL;
+ char * endpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
endpointID_t endpointID = AHL_UNDEFINED;
- int policyAllowed = AHL_POLICY_REJECT;
EndpointInfoT * pEndpointInfo = NULL;
+ EndpointSelectionModeT endpointSelMode = ENDPOINTSELMODEMAXVALUE;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:i,s?i}", "audio_role", &audioRole, "endpoint_type", &endpointType, "endpoint_id", &endpointID);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?i}", "audio_role", &audioRole, "endpoint_type", &endpointTypeStr, "endpoint_id", &endpointID);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = audio_role:%s endpoint_type:%d endpoint_id:%d", audioRole,endpointType,endpointID);
+ AFB_DEBUG("Parsed input arguments = audio_role:%s endpoint_type:%s endpoint_id:%d", audioRole,endpointTypeStr,endpointID);
+ endpointType = EndpointTypeToEnum(endpointTypeStr);
// Check if there is already an existing context for this client
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
if (pClientCtx == NULL)
{
- g_AHLCtx.iNumActiveClients++;
pClientCtx = AllocateClientContext();
afb_req_context_set(req, pClientCtx, TerminateClientContext);
}
- int iRoleIndex = FindRoleIndex(audioRole);
- if (iRoleIndex < 0) {
+ RoleInfoT * pRole = GetRole(audioRole);
+ if ( pRole == NULL )
+ {
afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole);
return;
}
- GArray * pRoleDeviceArray = NULL;
+ GPtrArray * pDeviceArray = NULL;
if (endpointType == ENDPOINTTYPE_SOURCE){
- pRoleDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSourceEndpoints, iRoleIndex );
+ pDeviceArray = pRole->pSourceEndpoints;
}
else{
- pRoleDeviceArray = g_ptr_array_index( g_AHLCtx.policyCtx.pSinkEndpoints, iRoleIndex );
+ pDeviceArray = pRole->pSinkEndpoints;
}
- if (pRoleDeviceArray->len == 0) {
- afb_req_fail_f(req, "No available devices", "No available devices for role:%s and device type:%d",audioRole,endpointType);
+ if (pDeviceArray == NULL || pDeviceArray->len == 0) {
+ afb_req_fail_f(req, "No available devices", "No available devices for role:%s and device type:%s",audioRole,endpointTypeStr);
return;
}
if (endpointID == AHL_UNDEFINED)
{
// Assign a device based on configuration priority (first in the list for requested role and endpoint type)
- pEndpointInfo = &g_array_index(pRoleDeviceArray,EndpointInfoT,0);
- streamInfo.endpointSelMode = AHL_ENDPOINTSELMODE_AUTO;
+ pEndpointInfo = g_ptr_array_index(pDeviceArray,0);
+ endpointSelMode = ENDPOINTSELMODE_AUTO;
+
}
else{
- streamInfo.endpointSelMode = AHL_ENDPOINTSELMODE_MANUAL;
+ endpointSelMode = ENDPOINTSELMODE_MANUAL;
// Find specified endpoint ID in list of devices
- int iNumberDevices = pRoleDeviceArray->len;
+ int iNumberDevices = pDeviceArray->len;
for ( int j = 0 ; j < iNumberDevices; j++)
{
- pEndpointInfo = &g_array_index(pRoleDeviceArray,EndpointInfoT,j);
- if (pEndpointInfo->endpointID == endpointID) {
+ pEndpointInfo = g_ptr_array_index(pDeviceArray,j);
+ if (pEndpointInfo && pEndpointInfo->endpointID == endpointID) {
break;
}
+ pEndpointInfo = NULL;
}
- if (pEndpointInfo == NULL) {
- afb_req_fail_f(req, "Endpoint not available", "Specified endpoint not available for role:%s and device type:%d endpoint id %d",audioRole,endpointType,endpointID);
- return;
- }
+
}
- // Create stream
- streamInfo.streamID = CreateNewStreamID(); // create new ID
- streamInfo.streamState = STREAM_STATE_IDLE;
- streamInfo.streamMute = STREAM_UNMUTED;
- streamInfo.pEndpointInfo = pEndpointInfo;
+ if (pEndpointInfo == NULL) {
+ afb_req_fail_f(req, "Endpoint not available", "Specified endpoint not available for role:%s and device type:%d endpoint id %d",audioRole,endpointType,endpointID);
+ return;
+ }
+ pStreamInfo = (StreamInfoT*) malloc(sizeof(StreamInfoT));
+ memset(pStreamInfo,0,sizeof(StreamInfoT));
+
+ // Create stream
+ pStreamInfo->streamID = CreateNewStreamID(); // create new ID
+ pStreamInfo->streamState = STREAM_STATE_IDLE;
+ pStreamInfo->streamMute = STREAM_UNMUTED;
+ pStreamInfo->pEndpointInfo = pEndpointInfo;
+ pStreamInfo->endpointSelMode = endpointSelMode;
+ // Directly from role config for now, but could be programmatically overriden in the future
+ pStreamInfo->pRoleName = pRole->pRoleName;
+ pStreamInfo->iPriority = pRole->iPriority;
+ pStreamInfo->eInterruptBehavior = pRole->eInterruptBehavior;
+
+#ifndef AHL_DISCONNECT_POLICY
// Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
- policyAllowed = Policy_OpenStream(&streamInfo);
+ json_object *pPolicyStreamJ = NULL;
+ err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_OpenStream");
+ return;
+ }
+
+ int policyAllowed = Policy_OpenStream(pPolicyStreamJ);
if (policyAllowed == AHL_POLICY_REJECT)
{
afb_req_fail(req, "Audio policy violation", "Open stream not allowed in current context");
return;
- }
+ }
+#endif
char streamEventName[128];
- snprintf(streamEventName,128,"ahl_streamstate_%d",streamInfo.streamID);
+ snprintf(streamEventName,128,"ahl_streamstate_%d",pStreamInfo->streamID);
- streamInfo.streamStateEvent = afb_daemon_make_event(streamEventName);
- err = !afb_event_is_valid(streamInfo.streamStateEvent);
+ pStreamInfo->streamStateEvent = afb_daemon_make_event(streamEventName);
+ err = !afb_event_is_valid(pStreamInfo->streamStateEvent);
if (err) {
afb_req_fail(req, "Stream event creation failure", "Could not create stream specific state change event");
return;
}
- err = afb_req_subscribe(req,streamInfo.streamStateEvent);
+ err = afb_req_subscribe(req,pStreamInfo->streamStateEvent);
if (err) {
afb_req_fail(req, "Stream event subscription failure", "Could not subscribe to stream specific state change event");
return;
}
- // Add to client context stream ID and endpoint ID access rights
- g_array_append_val(pClientCtx->pStreamAccessList, streamInfo.streamID);
- g_array_append_val(pClientCtx->pEndpointAccessList, streamInfo.pEndpointInfo->endpointID);
+ // Add to client context stream ID access rights
+ g_array_append_val(pClientCtx->pStreamAccessList, pStreamInfo->streamID);
// Push stream on active stream list
- g_array_append_val( g_AHLCtx.policyCtx.pActiveStreams, streamInfo );
+ if (g_AHLCtx.policyCtx.pStreams)
+ g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo );
- StreamInfoStructToJSON(&streamInfoJ,&streamInfo);
+ StreamInfoStructToJSON(&streamInfoJ,pStreamInfo);
afb_req_success(req, streamInfoJ, "Stream info structure");
}
@@ -460,7 +771,6 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
{
json_object *queryJ = NULL;
streamID_t streamID = AHL_UNDEFINED;
- int policyAllowed = AHL_POLICY_REJECT;
queryJ = afb_req_json(req);
int err = wrap_json_unpack(queryJ, "{s:i}", "stream_id", &streamID);
@@ -470,11 +780,18 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
}
AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID);
+
+ StreamInfoT * pStreamInfo = GetStream(streamID);
+ if (pStreamInfo == NULL) {
+ afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
+ return;
+ }
+
// Check if there is already an existing context for this client
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
if (pClientCtx == NULL)
{
- afb_req_fail(req, "No context associated with the request", "No context associated with the request");
+ afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)");
return;
}
@@ -486,67 +803,55 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
return;
}
- // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
- StreamInfoT * pStreamInfo = GetActiveStream(streamID);
- if (pStreamInfo == NULL) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyStreamJ = NULL;
+ err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_CloseStream");
return;
- }
-
- policyAllowed = Policy_CloseStream(pStreamInfo);
+ }
+ // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions
+ int policyAllowed = Policy_CloseStream(pPolicyStreamJ);
if (policyAllowed == AHL_POLICY_REJECT)
{
afb_req_fail(req, "Audio policy violation", "Close stream not allowed in current context");
return;
}
+#endif
- // Remove from active stream list (if present)
- int iNumActiveStreams = g_AHLCtx.policyCtx.pActiveStreams->len;
- int iStreamFound = 0;
- for ( int i = 0; i < iNumActiveStreams ; i++ ) {
- StreamInfoT streamInfo = g_array_index(g_AHLCtx.policyCtx.pActiveStreams,StreamInfoT,i);
- if (streamInfo.streamID == streamID){
- // Unsubscribe client from stream events
- char streamEventName[128];
- snprintf(streamEventName,128,"ahl_streamstate_%d",streamInfo.streamID);
- int iValid = afb_event_is_valid(streamInfo.streamStateEvent);
- if (iValid) {
- err = afb_req_unsubscribe(req,streamInfo.streamStateEvent);
- if (err) {
- afb_req_fail(req, "Stream event subscription failure", "Could not unsubscribe to stream specific state change event");
- return;
- }
- }
- else{
- AFB_WARNING("Stream event no longer valid and therefore not unsubscribed");
- break;
- }
-
- g_array_remove_index(g_AHLCtx.policyCtx.pActiveStreams,i);
- iStreamFound = 1;
- break;
+ // Unsubscribe client from stream events
+ char streamEventName[128];
+ snprintf(streamEventName,128,"ahl_streamstate_%d",streamID);
+ int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent);
+ if (iValid) {
+ err = afb_req_unsubscribe(req,pStreamInfo->streamStateEvent);
+ if (err) {
+ afb_req_fail(req, "Stream event subscription failure", "Could not unsubscribe to stream specific state change event");
+ return;
}
}
- if (iStreamFound == 0) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
- return;
- }
+ // Remove from stream list (if present)
+ if (g_AHLCtx.policyCtx.pStreams)
+ g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID));
+ free(pStreamInfo);
+ pStreamInfo = NULL;
// Find index for cases where there are multiple streams per client
// Remove from client context stream ID and endpoint ID access rights
- for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) {
- streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
- if (iID == streamID) {
- g_array_remove_index(pClientCtx->pStreamAccessList, i);
- g_array_remove_index(pClientCtx->pEndpointAccessList, i);
- }
- }
+ if (pClientCtx->pStreamAccessList) {
+ for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) {
+ streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i);
+ if (iID == streamID) {
+ g_array_remove_index(pClientCtx->pStreamAccessList, i);
+ }
+ }
- if (pClientCtx->pStreamAccessList->len == 0 && pClientCtx->pEndpointAccessList == 0) {
- // If no more streams/endpoints owner, clear session
- afb_req_context_clear(req);
- g_AHLCtx.iNumActiveClients--;
+ if (pClientCtx->pStreamAccessList->len == 0) {
+ // If no more streams/endpoints owner, clear session
+ afb_req_context_clear(req);
+ }
}
afb_req_success(req, NULL, "Stream close completed");
@@ -556,20 +861,19 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
{
json_object *queryJ = NULL;
streamID_t streamID = AHL_UNDEFINED;
- StreamStateT streamState = STREAM_STATUS_MAXVALUE;
- int policyAllowed = AHL_POLICY_REJECT;
+ char * streamStateStr = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i}", "stream_id", &streamID,"state",&streamState);
+ int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"state",&streamStateStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = stream_id:%d, state:%d", streamID,streamState);
-
- StreamInfoT * pStreamInfo = GetActiveStream(streamID);
+ AFB_DEBUG("Parsed input arguments = stream_id:%d, state:%s", streamID,streamStateStr);
+
+ StreamInfoT * pStreamInfo = GetStream(streamID);
if (pStreamInfo == NULL) {
- afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
+ afb_req_fail_f(req, "Stream not found", "Specified stream not found stream_id -> %d",streamID);
return;
}
@@ -577,7 +881,7 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
if (pClientCtx == NULL)
{
- afb_req_fail(req, "No context associated with the request", "No context associated with the request");
+ afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)");
return;
}
@@ -588,14 +892,30 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
afb_req_fail(req, "Access control denied", "Set stream state not allowed in current client context");
return;
}
- int AudioRoleIndex = FindRoleIndex(pStreamInfo->pEndpointInfo->gsAudioRole->str);
- policyAllowed = Policy_SetStreamState(pStreamInfo, AudioRoleIndex, streamState);
+ StreamStateT streamState = StreamStateToEnum(streamStateStr);
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyStreamJ = NULL;
+ err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState");
+ return;
+ }
+
+ json_object *paramJ= json_object_new_int(streamState);
+ json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ);
+
+ int policyAllowed = Policy_SetStreamState(pPolicyStreamJ);
if (policyAllowed == AHL_POLICY_REJECT)
{
afb_req_fail(req, "Audio policy violation", "Change stream state not allowed in current context");
return;
}
+#else
+ // Simulate that policy returns target state (accepted)
+ pStreamInfo->streamState = streamState;
+#endif
afb_req_success(req, NULL, "Set stream state");
}
@@ -604,18 +924,17 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
{
json_object *queryJ = NULL;
streamID_t streamID = AHL_UNDEFINED;
- StreamMuteT muteState = STREAM_MUTE_MAXVALUE;
- int policyAllowed = AHL_POLICY_REJECT;
+ char * pMuteStr = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i}", "stream_id", &streamID,"mute",&muteState);
+ int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"mute",&pMuteStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = stream_id:%d, mute:%d", streamID,muteState);
+ AFB_DEBUG("Parsed input arguments = stream_id:%d, mute:%s", streamID,pMuteStr);
- StreamInfoT * pStreamInfo = GetActiveStream(streamID);
+ StreamInfoT * pStreamInfo = GetStream(streamID);
if (pStreamInfo == NULL) {
afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
return;
@@ -625,7 +944,7 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
if (pClientCtx == NULL)
{
- afb_req_fail(req, "No context associated with the request", "No context associated with the request");
+ afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)");
return;
}
@@ -637,12 +956,30 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
return;
}
- policyAllowed = Policy_SetStreamMute(pStreamInfo,muteState);
+
+ StreamMuteT muteState = StreamMuteToEnum(pMuteStr);
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyStreamJ = NULL;
+ err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ);
+ if (err == AHL_FAIL)
+ {
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute");
+ return;
+ }
+
+ json_object *paramJ= json_object_new_int(muteState);
+ json_object_object_add(pPolicyStreamJ, "mute_state", paramJ);
+
+ int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ);
if (policyAllowed == AHL_POLICY_REJECT)
{
afb_req_fail(req, "Audio policy violation", "Mute stream not allowed in current context");
return;
}
+#else
+ // Simulate that policy returns target state (accepted)
+ pStreamInfo->streamMute = muteState;
+#endif
afb_req_success(req, NULL, "Set stream mute completed");
}
@@ -661,7 +998,7 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req)
}
AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID);
- StreamInfoT * pStreamInfo = GetActiveStream(streamID);
+ StreamInfoT * pStreamInfo = GetStream(streamID);
if (pStreamInfo == NULL) {
afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID);
return;
@@ -676,17 +1013,18 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
+ char * pEndpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
char * volumeStr = NULL;
- int policyAllowed = AHL_POLICY_REJECT;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i,s:s}", "endpoint_type", &endpointType,"endpoint_id",&endpointID,"volume",&volumeStr);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%d endpoint_id:%d volume:%s", endpointType,endpointID,volumeStr);
+ AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d volume:%s", pEndpointTypeStr,endpointID,volumeStr);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
if (pEndpointInfo == NULL)
@@ -695,28 +1033,28 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req)
return;
}
- // Check if there is already an existing context for this client
- AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
- if (pClientCtx == NULL)
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyEndpointJ = NULL;
+ err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_FAIL)
{
- afb_req_fail(req, "No context associated with the request", "No context associated with the request");
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
return;
- }
+ }
- // Verify that this client can control the stream
- int iEndpointAccessControl = CheckEndpointAccessControl( pClientCtx, endpointID );
- if (iEndpointAccessControl == AHL_ACCESS_CONTROL_DENIED)
- {
- afb_req_fail(req, "Access control denied", "Set volume not allowed in current client context");
- return;
- }
+ json_object *paramJ= json_object_new_string(volumeStr);
+ json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ);
- policyAllowed = Policy_SetVolume(pEndpointInfo, volumeStr);
+ int policyAllowed = Policy_SetVolume(pPolicyEndpointJ);
if (!policyAllowed)
{
afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context");
return;
}
+#else
+ // Simulate that policy returns target state (accepted)
+ pEndpointInfo->iVolume = atoi(volumeStr);
+#endif
afb_req_success(req, NULL, "Set volume completed");
}
@@ -725,16 +1063,18 @@ PUBLIC void audiohlapi_get_volume(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
+ char * pEndpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
json_object * volumeJ = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i}", "endpoint_type", &endpointType,"endpoint_id",&endpointID);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%d endpoint_id:%d", endpointType,endpointID);
+ AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
if (pEndpointInfo == NULL)
@@ -743,26 +1083,27 @@ PUBLIC void audiohlapi_get_volume(struct afb_req req)
return;
}
- volumeJ = json_object_new_double((double)pEndpointInfo->iVolume);
+ volumeJ = json_object_new_int(pEndpointInfo->iVolume);
afb_req_success(req, volumeJ, "Retrieved volume value");
}
// Properties
-PUBLIC void audiohlapi_get_list_properties(struct afb_req req)
+PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
+ char * pEndpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
- json_object * endpointPropsJ = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i}", "endpoint_type", &endpointType,"endpoint_id",&endpointID);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%d endpoint_id:%d", endpointType,endpointID);
+ AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
if (pEndpointInfo == NULL)
@@ -771,38 +1112,29 @@ PUBLIC void audiohlapi_get_list_properties(struct afb_req req)
return;
}
- // Build and return list of properties for specific endpoint
- GHashTableIter iter;
- gpointer key, value;
-
- g_hash_table_iter_init (&iter, pEndpointInfo->pPropTable);
- endpointPropsJ = json_object_new_array();
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- json_object * propJ = json_object_new_string(key);
- json_object_array_add(endpointPropsJ, propJ);
- }
+ json_object *endpointInfoJ = NULL;
+ EndpointInfoStructToJSON(&endpointInfoJ,pEndpointInfo);
- afb_req_success(req, endpointPropsJ, "Retrieved property list for endpoint");
+ afb_req_success(req, endpointInfoJ, "Retrieved endpoint information and properties");
}
PUBLIC void audiohlapi_set_property(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
+ char * pEndpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
char * propertyName = NULL;
json_object * propValueJ = NULL;
- int policyAllowed = AHL_POLICY_REJECT;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i,s:s,s:o}", "endpoint_type", &endpointType,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s:o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%d endpoint_id:%d property_name:%s", endpointType,endpointID,propertyName);
-
+ AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
if (pEndpointInfo == NULL)
@@ -811,31 +1143,33 @@ PUBLIC void audiohlapi_set_property(struct afb_req req)
return;
}
- // Check if there is already an existing context for this client
- AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure
- if (pClientCtx == NULL)
+#ifndef AHL_DISCONNECT_POLICY
+ json_object *pPolicyEndpointJ = NULL;
+ err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ);
+ if (err == AHL_FAIL)
{
- afb_req_fail(req, "No context associated with the request", "No context associated with the request");
+ afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume");
return;
- }
+ }
- // Verify that this client can control the stream
- int iEndpointAccessControl = CheckEndpointAccessControl( pClientCtx, endpointID );
- if (iEndpointAccessControl == AHL_ACCESS_CONTROL_DENIED)
- {
- afb_req_fail(req, "Access control denied", "Set property not allowed in current client context");
- return;
- }
+ json_object *paramJ= json_object_new_string(propertyName);
+ json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ);
+ json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ);
// Call policy to allow custom policy actions in current context
- policyAllowed = Policy_SetProperty(pEndpointInfo, propertyName, propValueJ);
+ int policyAllowed = Policy_SetProperty(pPolicyEndpointJ);
if (!policyAllowed)
{
afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context");
return;
}
+#else
+ // Simulate that policy returns target state (accepted)
+ if (pEndpointInfo->pPropTable)
+ g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ);
+#endif
- afb_event_push(g_AHLCtx.policyCtx.propertyEvent,queryJ);
+ //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,queryJ);
afb_req_success(req, NULL, "Set property completed");
}
@@ -844,16 +1178,18 @@ PUBLIC void audiohlapi_get_property(struct afb_req req)
{
json_object *queryJ = NULL;
endpointID_t endpointID = AHL_UNDEFINED;
+ char * pEndpointTypeStr = NULL;
EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
char * propertyName = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:i,s:i,s:s}", "endpoint_type", &endpointType,"endpoint_id",&endpointID,"property_name",&propertyName);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = endpoint_type:%d endpoint_id:%d property_name:%s", endpointType,endpointID,propertyName);
+ AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName);
+ endpointType = EndpointTypeToEnum(pEndpointTypeStr);
EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType);
if (pEndpointInfo == NULL)
@@ -870,17 +1206,19 @@ PUBLIC void audiohlapi_get_property(struct afb_req req)
}
json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object
+ //AFB_WARNING("properties %s", json_object_get_string(propertyValJ));
+ //json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object
afb_req_success(req, propertyValJ, "Retrieved property value");
}
// Audio related events
-PUBLIC void audiohlapi_get_list_events(struct afb_req req)
+PUBLIC void audiohlapi_get_list_actions(struct afb_req req)
{
json_object *queryJ = NULL;
char * audioRole = NULL;
- json_object * roleEventsJ = NULL;
+ json_object * roleActionsJ = NULL;
queryJ = afb_req_json(req);
int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role",&audioRole);
@@ -890,83 +1228,85 @@ PUBLIC void audiohlapi_get_list_events(struct afb_req req)
}
AFB_DEBUG("Parsed input arguments = audio_role:%s",audioRole);
- // Build and return list of events for specific audio role
- int iRoleIndex = FindRoleIndex(audioRole);
- if (iRoleIndex < 0) {
+ // Build and return list of actions for specific audio role
+ RoleInfoT * pRole = GetRole(audioRole);
+ if ( pRole == NULL )
+ {
afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole);
return;
}
- GArray * pRoleEventArray = g_ptr_array_index( g_AHLCtx.policyCtx.pEventList, iRoleIndex );
- roleEventsJ = json_object_new_array();
- int iNumberEvents = pRoleEventArray->len;
- for ( int i = 0 ; i < iNumberEvents; i++)
- {
- GString gsEventName = g_array_index(pRoleEventArray,GString,i);
- json_object * eventJ = json_object_new_string(gsEventName.str);
- json_object_array_add(roleEventsJ, eventJ);
+ roleActionsJ = json_object_new_array();
+ if (pRole->pActionList) {
+ int iNumberActions = pRole->pActionList->len;
+ for ( int i = 0 ; i < iNumberActions; i++)
+ {
+ char * pActionName = g_ptr_array_index(pRole->pActionList,i);
+ json_object * actionJ = json_object_new_string(pActionName);
+ json_object_array_add(roleActionsJ, actionJ);
+ }
}
- afb_req_success(req, roleEventsJ, "Retrieved event list for audio role");
+ afb_req_success(req, roleActionsJ, "Retrieved action list for audio role");
}
-PUBLIC void audiohlapi_post_event(struct afb_req req)
+PUBLIC void audiohlapi_post_action(struct afb_req req)
{
json_object *queryJ = NULL;
- char * eventName = NULL;
+ char * actionName = NULL;
char * audioRole = NULL;
char * mediaName = NULL;
- json_object *eventContext = NULL;
- int policyAllowed = AHL_POLICY_REJECT;
+ json_object *actionContext = NULL;
queryJ = afb_req_json(req);
- int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?s,s?o}", "event_name", &eventName,"audio_role",&audioRole,"media_name",&mediaName,"event_context",&eventContext);
+ int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext);
if (err) {
afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ));
return;
}
- AFB_DEBUG("Parsed input arguments = event_name:%s audio_role:%s", eventName,audioRole);
+ AFB_DEBUG("Parsed input arguments = action_name:%s audio_role:%s", actionName,audioRole);
- // Verify if known event for audio role
- int iRoleIndex = FindRoleIndex(audioRole);
- if (iRoleIndex < 0) {
+ // Verify if known action for audio role
+ RoleInfoT * pRole = GetRole(audioRole);
+ if ( pRole == NULL )
+ {
afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole);
return;
}
- GArray * pRoleEventArray = NULL;
- pRoleEventArray = g_ptr_array_index( g_AHLCtx.policyCtx.pEventList, iRoleIndex );
- if (pRoleEventArray->len == 0) {
- afb_req_fail_f(req, "No available events", "No available events for role:%s",audioRole);
- return;
- }
- // Check to find specific event
- int iEventFound = 0;
- for (int i = 0; i < pRoleEventArray->len; i++)
- {
- GString gs = g_array_index( pRoleEventArray, GString, i );
- if ( strcasecmp(gs.str,eventName) == 0 )
+ // Check to find specific action
+ int iActionFound = 0;
+ if (pRole->pActionList) {
+ int iNumberActions = pRole->pActionList->len;
+ char * pTargetActionName = NULL;
+ for ( int i = 0 ; i < iNumberActions; i++)
{
- iEventFound = 1;
- break;
+ pTargetActionName = g_ptr_array_index(pRole->pActionList,i);
+ if ( strcasecmp(pTargetActionName,actionName)==0) {
+ iActionFound = 1;
+ break;
+ }
}
}
- if (!iEventFound) {
- afb_req_fail_f(req, "Event not found for audio role", "Event not found for roke:%s",audioRole);
+
+ if (!iActionFound) {
+ afb_req_fail_f(req, "Event not found for audio role", "Event -> %s not found for role:%s",actionName,audioRole);
return;
}
+#ifndef AHL_DISCONNECT_POLICY
// Call policy to allow custom policy actions in current context (e.g. cancel playback)
- policyAllowed = Policy_PostEvent(eventName, audioRole, mediaName, (void*)eventContext);
+ int policyAllowed = Policy_PostAction(queryJ);
if (!policyAllowed)
{
- afb_req_fail(req, "Audio policy violation", "Post sound event not allowed in current context");
+ afb_req_fail(req, "Audio policy violation", "Post sound action not allowed in current context");
return;
}
+#endif
- afb_event_push(g_AHLCtx.policyCtx.postEvent,queryJ);
+ //afb_event_push(g_AHLCtx.policyCtx.postEvent,queryJ);
- afb_req_success(req, NULL, "Posted sound event");
+ afb_req_success(req, NULL, "Posted sound action");
}
@@ -989,7 +1329,11 @@ PUBLIC void audiohlapi_subscribe(struct afb_req req)
char * pEventName = NULL;
json_object * jEvent = json_object_array_get_idx(eventArrayJ,i);
pEventName = (char *)json_object_get_string(jEvent);
- if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
+ if(pEventName == NULL) {
+ afb_req_fail(req, "failed", "Invalid event");
+ return;
+ }
+ else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent);
AFB_DEBUG("Client subscribed to endpoint property events");
}
@@ -997,8 +1341,8 @@ PUBLIC void audiohlapi_subscribe(struct afb_req req)
afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent);
AFB_DEBUG("Client subscribed to endpoint volume events");
}
- else if(!strcasecmp(pEventName, AHL_POST_EVENT)) {
- afb_req_subscribe(req, g_AHLCtx.policyCtx.postEvent);
+ else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) {
+ afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent);
AFB_DEBUG("Client subscribed to post event calls events");
}
else {
@@ -1028,7 +1372,11 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
char * pEventName = NULL;
json_object * jEvent = json_object_array_get_idx(eventArrayJ,i);
pEventName = (char *)json_object_get_string(jEvent);
- if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
+ if(pEventName == NULL) {
+ afb_req_fail(req, "failed", "Invalid event");
+ return;
+ }
+ else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) {
afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent);
AFB_DEBUG("Client unsubscribed to endpoint property events");
}
@@ -1036,8 +1384,8 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent);
AFB_DEBUG("Client unsubscribed to endpoint volume events");
}
- else if(!strcasecmp(pEventName, AHL_POST_EVENT)) {
- afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postEvent);
+ else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) {
+ afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent);
AFB_DEBUG("Client unsubscribed to post event calls events");
}
else {
@@ -1048,3 +1396,182 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req)
afb_req_success(req, NULL, "Unsubscribe to events finished");
}
+
+// Since the policy is currently in the same binding, it cannot raise events on its own
+// This is a first step toward isolation, when policy is migrated in its own binding it can simply raise AGL events
+// This binding will register for these policy events and will execute the code below upon event reception
+PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ)
+{
+ char * pEventName = NULL;
+
+ int err = wrap_json_unpack(pEventDataJ,"{s:s}","event_name", &pEventName);
+ if(err)
+ {
+ AFB_ERROR("Unable to retrieve event name");
+ return;
+ }
+
+ if(strcasecmp(pEventName, AHL_ENDPOINT_INIT_EVENT)==0) {
+ char * pAudioRole = NULL;
+ endpointID_t endpointID = AHL_UNDEFINED;
+ EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
+ int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s}",
+ "endpoint_id", &endpointID,
+ "endpoint_type", &endpointType,
+ "audio_role", &pAudioRole);
+ if(err)
+ {
+ AFB_ERROR("Unable to unpack property init event");
+ return;
+ }
+
+ RoleInfoT * pRole = GetRole(pAudioRole);
+ if ( pRole == NULL ){
+ AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole);
+ return;
+ }
+
+ EndpointInfoT * pEndpointInfo = InitEndpointInfo();
+ g_assert_nonnull(pEndpointInfo);
+ PolicyCtxJSONToEndpoint(pEventDataJ,pEndpointInfo);
+
+ err = ReplaceEndpointInfoWithRole(endpointID,endpointType,pRole,pEndpointInfo);
+ if(err == AHL_FAIL)
+ {
+ AFB_ERROR("Can't update EndpointInfo aborting");
+ return;
+ }
+
+ // Remove event name from object
+ // json_object_object_del(pEventDataJ,"event_name");
+ //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ); // Not broadcasted to application at this time
+ }
+ else if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) {
+ char * pAudioRole = NULL;
+ char * pPropertyName = NULL;
+ endpointID_t endpointID = AHL_UNDEFINED;
+ EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
+ json_object * propValueJ = NULL;
+ int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s,s:o,s:s}",
+ "endpoint_id", &endpointID,
+ "endpoint_type", &endpointType,
+ "property_name", &pPropertyName,
+ "value",&propValueJ,
+ "audio_role", &pAudioRole);
+ if(err)
+ {
+ AFB_ERROR("Unable to unpack property event");
+ return;
+ }
+ RoleInfoT * pRole = GetRole(pAudioRole);
+ if ( pRole == NULL ){
+ AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole);
+ return;
+ }
+ EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole);
+ // update property value
+ if (pEndpointInfo->pPropTable)
+ {
+ json_type jType = json_object_get_type(propValueJ);
+ switch (jType) {
+ case json_type_double:
+ Add_Endpoint_Property_Double(pEndpointInfo,pPropertyName,json_object_get_double(propValueJ));
+ break;
+ case json_type_int:
+ Add_Endpoint_Property_Int(pEndpointInfo,pPropertyName,json_object_get_int(propValueJ));
+ break;
+ case json_type_string:
+ Add_Endpoint_Property_String(pEndpointInfo,pPropertyName,json_object_get_string(propValueJ));
+ break;
+ default:
+ AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(propValueJ));
+ return ;
+ }
+ }
+ // Remove event name from object
+ json_object_object_del(pEventDataJ,"event_name");
+ afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ);
+ }
+ else if(strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)==0) {
+ char * pAudioRole = NULL;
+ endpointID_t endpointID = AHL_UNDEFINED;
+ EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE;
+ int iVolume = 0;
+ int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:i,s:s}",
+ "endpoint_id", &endpointID,
+ "endpoint_type", &endpointType,
+ "value",&iVolume,
+ "audio_role", &pAudioRole);
+ if(err)
+ {
+ AFB_ERROR("Unable to unpack volume event data");
+ return;
+ }
+ RoleInfoT * pRole = GetRole(pAudioRole);
+ if ( pRole == NULL ){
+ AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole);
+ return;
+ }
+ EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole);
+ // update volume value
+ pEndpointInfo->iVolume = iVolume;
+ // Remove event name from object
+ json_object_object_del(pEventDataJ,"event_name");
+ afb_event_push(g_AHLCtx.policyCtx.volumeEvent,pEventDataJ);
+ }
+ else if(strcasecmp(pEventName, AHL_POST_ACTION_EVENT)==0) {
+ // Remove event name from object
+ json_object_object_del(pEventDataJ,"event_name");
+ afb_event_push(g_AHLCtx.policyCtx.postActionEvent,pEventDataJ);
+ }
+ else if(strcasecmp(pEventName, AHL_STREAM_STATE_EVENT)==0) {
+ streamID_t streamID = AHL_UNDEFINED;
+ StreamEventT streamEvent = STREAM_EVENT_MAXVALUE;
+ int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i}",
+ "stream_id", &streamID,
+ "state_event", &streamEvent);
+ if(err)
+ {
+ AFB_ERROR("Unable to unpack stream event data");
+ return;
+ }
+
+ StreamInfoT * pStreamInfo = GetStream(streamID);
+ if (pStreamInfo == NULL) {
+ AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID);
+ return;
+ }
+
+ // update streamstate value
+ switch (streamEvent) {
+ case STREAM_EVENT_START:
+ pStreamInfo->streamState = STREAM_STATE_RUNNING;
+ break;
+ case STREAM_EVENT_STOP:
+ pStreamInfo->streamState = STREAM_STATE_IDLE;
+ break;
+ case STREAM_EVENT_PAUSE:
+ pStreamInfo->streamState = STREAM_STATE_PAUSED;
+ break;
+ case STREAM_EVENT_RESUME:
+ pStreamInfo->streamState = STREAM_STATE_RUNNING;
+ break;
+ case STREAM_EVENT_MUTED:
+ pStreamInfo->streamMute = STREAM_MUTED;
+ break;
+ case STREAM_EVENT_UNMUTED:
+ pStreamInfo->streamMute = STREAM_UNMUTED;
+ break;
+ default:
+ AFB_ERROR("Unknown stream event");
+ }
+
+ // Remove event name from object
+ json_object_object_del(pEventDataJ,"event_name");
+ AFB_ERROR("pEventDataJ=%s", json_object_get_string(pEventDataJ));
+ afb_event_push(pStreamInfo->streamStateEvent,pEventDataJ);
+ }
+ else {
+ AFB_ERROR("Unknown event name");
+ }
+} \ No newline at end of file