diff options
Diffstat (limited to 'ahl-binding/ahl-binding.c')
-rw-r--r-- | ahl-binding/ahl-binding.c | 951 |
1 files changed, 325 insertions, 626 deletions
diff --git a/ahl-binding/ahl-binding.c b/ahl-binding/ahl-binding.c index 264930f..c205c8e 100644 --- a/ahl-binding/ahl-binding.c +++ b/ahl-binding/ahl-binding.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#define _GNU_SOURCE #include <stdio.h> #include <string.h> @@ -22,12 +21,11 @@ #include "ahl-apidef.h" // Generated from JSON OpenAPI #include "wrap-json.h" #include "ahl-policy.h" -#include "ahl-policy-utils.h" +#include "ahl-json.h" // Global high-level binding context AHLCtxT g_AHLCtx; -// TODO: Helpers that could be common static EndpointTypeT EndpointTypeToEnum(char * in_pEndpointTypeStr) { if (in_pEndpointTypeStr == NULL) { @@ -76,108 +74,6 @@ static StreamMuteT StreamMuteToEnum(char * in_pStreamMuteStr) return STREAM_MUTE_MAXVALUE; } -static char * DeviceURITypeEnumToStr(DeviceURITypeT in_eDeviceURIType) { - switch(in_eDeviceURIType) { - case DEVICEURITYPE_ALSA_HW: // Alsa hardware device URI - return AHL_DEVICEURITYPE_ALSA_HW; - case DEVICEURITYPE_ALSA_DMIX: // Alsa Dmix device URI (only for playback devices) - return AHL_DEVICEURITYPE_ALSA_DMIX; - case DEVICEURITYPE_ALSA_DSNOOP: // Alsa DSnoop device URI (only for capture devices) - return AHL_DEVICEURITYPE_ALSA_DSNOOP; - case DEVICEURITYPE_ALSA_SOFTVOL: // Alsa softvol device URI - return AHL_DEVICEURITYPE_ALSA_SOFTVOL; - case DEVICEURITYPE_ALSA_PLUG: // Alsa plug device URI - return AHL_DEVICEURITYPE_ALSA_PLUG; - case DEVICEURITYPE_ALSA_OTHER: // Alsa domain URI device of unspecified type - return AHL_DEVICEURITYPE_ALSA_OTHER; - case DEVICEURITYPE_NOT_ALSA: // Unknown (not ALSA domain) - return AHL_DEVICEURITYPE_NOT_ALSA; - default: - return "Unknown"; - } -} - -static char * StreamStateEnumToStr(StreamStateT in_eStreamState) { - switch(in_eStreamState) { - case STREAM_STATE_IDLE: - return AHL_STREAM_STATE_IDLE; - case STREAM_STATE_RUNNING: - return AHL_STREAM_STATE_RUNNING; - case STREAM_STATE_PAUSED: - return AHL_STREAM_STATE_PAUSED; - default: - return "Unknown"; - } -} - -static char * StreamMuteEnumToStr(StreamMuteT in_eStreamMute) { - switch(in_eStreamMute) { - case STREAM_UNMUTED: - return AHL_STREAM_UNMUTED; - case STREAM_MUTED: - return AHL_STREAM_MUTED; - default: - return "Unknown"; - } -} - -static void AudioFormatStructToJSON(json_object **audioFormatJ, AudioFormatT * pAudioFormat) -{ - wrap_json_pack(audioFormatJ, "{s:i,s:i,s:i}", - "sample_rate", pAudioFormat->sampleRate, - "num_channels", pAudioFormat->numChannels, - "sample_type", pAudioFormat->sampleType); -} - -// Package only information that can useful to application clients when selecting endpoint -static void EndpointInfoStructToJSON(json_object **endpointInfoJ, EndpointInfoT * pEndpointInfo) -{ - json_object *formatInfoJ = NULL; - wrap_json_pack(endpointInfoJ, "{s:i,s:s,s:s,s:s,s:s,s:s,s:s}", - "endpoint_id", pEndpointInfo->endpointID, - "endpoint_type", (pEndpointInfo->type == ENDPOINTTYPE_SOURCE) ? AHL_ENDPOINTTYPE_SOURCE : AHL_ENDPOINTTYPE_SINK, - "device_name", pEndpointInfo->gsDeviceName, - "display_name", pEndpointInfo->gsDisplayName, - "audio_role", pEndpointInfo->pRoleName, - "device_domain",pEndpointInfo->gsDeviceDomain, - "device_uri_type", DeviceURITypeEnumToStr(pEndpointInfo->deviceURIType)); - AudioFormatStructToJSON(&formatInfoJ,&pEndpointInfo->format); - json_object_object_add(*endpointInfoJ,"format",formatInfoJ); - - // Properties - if (pEndpointInfo->pPropTable) { - json_object *pPropTableJ = json_object_new_array(); - - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, pEndpointInfo->pPropTable); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if((key!=NULL) && (value!=NULL)) - { - json_object *pPropertyJ = NULL; - json_object_get((json_object*)value); // Don't let the framework free our object when the request is done - wrap_json_pack(&pPropertyJ, "{s:s,s:o}","property_name", (char*)key, "property_value", (json_object*)value); - json_object_array_add(pPropTableJ, pPropertyJ); - } - } - json_object_object_add(*endpointInfoJ,"properties",pPropTableJ); - } -} - -// Package only information that can useful to application clients when opening a stream -static void StreamInfoStructToJSON(json_object **streamInfoJ, StreamInfoT * pStreamInfo) -{ - json_object *endpointInfoJ = NULL; - EndpointInfoStructToJSON(&endpointInfoJ,pStreamInfo->pEndpointInfo); - wrap_json_pack(streamInfoJ, "{s:i,s:s,s:s,s:s}", - "stream_id", pStreamInfo->streamID, - "state", StreamStateEnumToStr(pStreamInfo->streamState), - "mute", StreamMuteEnumToStr(pStreamInfo->streamMute), - "device_uri",pStreamInfo->pEndpointInfo->gsDeviceURI); // Need to open a stream to have access to the device URI - json_object_object_add(*streamInfoJ,"endpoint_info",endpointInfoJ); -} - static streamID_t CreateNewStreamID() { streamID_t newID = g_AHLCtx.nextStreamID; @@ -209,32 +105,6 @@ static EndpointInfoT * GetEndpointInfoWithRole(endpointID_t in_endpointID, Endpo return pEndpointInfo; } -static int ReplaceEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole, EndpointInfoT * in_pNewEndpoint) -{ - GPtrArray * pDeviceArray = NULL; - if (in_endpointType == ENDPOINTTYPE_SOURCE){ - pDeviceArray = in_pRole->pSourceEndpoints; - } - else { - pDeviceArray = in_pRole->pSinkEndpoints; - } - g_assert_nonnull(pDeviceArray); - - for (int j = 0; j < pDeviceArray->len; j++) { - EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pDeviceArray,j); - g_assert_nonnull(pCurEndpointInfo); - if (pCurEndpointInfo->endpointID == in_endpointID) { - g_ptr_array_insert(pDeviceArray,j,in_pNewEndpoint); - g_ptr_array_remove_index(pDeviceArray,j+1); - TermEndpointInfo(pCurEndpointInfo); - // GLib automatically frees item upon array removal - return AHL_SUCCESS; - } - } - - return AHL_FAIL; -} - static EndpointInfoT * GetEndpointInfo(endpointID_t in_endpointID, EndpointTypeT in_endpointType) { EndpointInfoT * pEndpointInfo = NULL; @@ -267,6 +137,79 @@ static RoleInfoT * GetRole(char * in_pAudioRoleName) return g_hash_table_lookup(g_AHLCtx.policyCtx.pRoleInfo,in_pAudioRoleName); } +static int CloseStream(AHLClientCtxT * in_pClientCtx, streamID_t streamID,struct afb_req * pReq) { + StreamInfoT * pStreamInfo = GetStream(streamID); + if (pStreamInfo == NULL) { + AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); + return AHL_FAIL; + } + +#ifndef AHL_DISCONNECT_POLICY + json_object *pPolicyStreamJ = NULL; + int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream"); + return AHL_FAIL; + } + int policyAllowed = Policy_CloseStream(pPolicyStreamJ); + if (policyAllowed == AHL_POLICY_REJECT) + { + AFB_ERROR("Close stream not allowed in current context"); + return AHL_FAIL; + } +#endif + // Unsubscribe client from stream events + if (pReq != NULL) { + char streamEventName[128]; + snprintf(streamEventName,128,"ahl_streamstate_%d",streamID); + int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent); + if (iValid) { + err = afb_req_unsubscribe(*pReq,pStreamInfo->streamStateEvent); + if (err) { + AFB_ERROR("Could not unsubscribe to stream specific state change event"); + return AHL_FAIL; + } + } + } + + // Remove from stream list (if present) + if (g_AHLCtx.policyCtx.pStreams) + g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID)); + free(pStreamInfo); + pStreamInfo = NULL; + + // Find index for cases where there are multiple streams per client + // Remove from client context stream ID and endpoint ID access rights + if (in_pClientCtx->pStreamAccessList) { + for (int i = 0; i < in_pClientCtx->pStreamAccessList->len ; i++) { + streamID_t iID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,i); + if (iID == streamID) { + g_array_remove_index(in_pClientCtx->pStreamAccessList, i); + } + } + } + + return AHL_SUCCESS; +} + +static int CloseAllClientStreams(AHLClientCtxT * in_pClientCtx, struct afb_req * pReq) +{ + g_assert_nonnull(in_pClientCtx); + if (in_pClientCtx->pStreamAccessList != NULL) { + while( in_pClientCtx->pStreamAccessList->len ) + { + streamID_t streamID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,0); + int err = CloseStream(in_pClientCtx,streamID,pReq); + if (err) { + return err; + } + } + } + + return AHL_SUCCESS; +} + static AHLClientCtxT * AllocateClientContext() { AHLClientCtxT * pClientCtx = malloc(sizeof(AHLClientCtxT)); @@ -278,35 +221,13 @@ static void TerminateClientContext(void * ptr) { AHLClientCtxT * pClientCtx = (AHLClientCtxT *) ptr; if (pClientCtx != NULL) { - - // Avoid having policy in bad state if client loses WS connection (e.g. app termination without close stream) - // Force close streams in those cases. - - if (pClientCtx->pStreamAccessList != NULL) { -#ifndef AHL_DISCONNECT_POLICY - for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++) - { - streamID_t streamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i); - // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); - return; - } - - json_object *pPolicyStreamJ = NULL; - int err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream"); - return; - } - Policy_CloseStream(pPolicyStreamJ); - } -#endif + CloseAllClientStreams(pClientCtx,NULL); + + if (pClientCtx->pStreamAccessList) { g_array_free( pClientCtx->pStreamAccessList, TRUE); pClientCtx->pStreamAccessList = NULL; } + free(pClientCtx); } } @@ -327,30 +248,28 @@ static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t strea static int CreateEvents() { - int err = 0; - g_AHLCtx.policyCtx.propertyEvent = afb_daemon_make_event(AHL_ENDPOINT_PROPERTY_EVENT); - err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); + int err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); if (err) { AFB_ERROR("Could not create endpoint property change event"); - return err; + return AHL_FAIL; } g_AHLCtx.policyCtx.volumeEvent = afb_daemon_make_event(AHL_ENDPOINT_VOLUME_EVENT); err = !afb_event_is_valid(g_AHLCtx.policyCtx.volumeEvent); if (err) { AFB_ERROR("Could not create endpoint volume change event"); - return err; + return AHL_FAIL; } g_AHLCtx.policyCtx.postActionEvent = afb_daemon_make_event(AHL_POST_ACTION_EVENT); err = !afb_event_is_valid(g_AHLCtx.policyCtx.postActionEvent); if (err) { AFB_ERROR("Could not create post action event call event"); - return err; + return AHL_FAIL; } - return err; + return AHL_SUCCESS; } static void AhlBindingTerm() @@ -434,42 +353,36 @@ static void AhlBindingTerm() // Binding initialization PUBLIC int AhlBindingInit() { - int err = 0; - memset(&g_AHLCtx,0,sizeof(g_AHLCtx)); // Register exit function atexit(AhlBindingTerm); - //Create AGL Events - err=CreateEvents(); - if(err) - { - //Error messages already reported inside CreateEvents - return err; + // Create AGL Events + int err = CreateEvents(); + if(err) { + // Error messages already reported inside CreateEvents + return AHL_FAIL; } // Parse high-level binding JSON configuration file (will build device lists) err = ParseHLBConfig(); - if(err) - { - //Error messages already reported inside ParseHLBConfig - return err; + if(err) { + // Error messages already reported inside ParseHLBConfig + return AHL_FAIL; } #ifndef AHL_DISCONNECT_POLICY // Policy initialization err = Policy_Init(); - if(err == AHL_POLICY_REJECT) - { + if(err == AHL_POLICY_REJECT) { //Error messages already reported inside PolicyInit - return err; + return AHL_FAIL; } - // for all audio Roles + // Call policy for initalization of all source + sink endpoints for all audio Roles GHashTableIter iter; gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo); while (g_hash_table_iter_next (&iter, &key, &value)) { @@ -479,63 +392,73 @@ PUBLIC int AhlBindingInit() for (int j = 0; j < pRoleInfo->pSourceEndpoints->len; j++) { EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSourceEndpoints,j); g_assert_nonnull(pCurEndpointInfo); - json_object *pPolicyEndpointJ = NULL; - err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { + json_object *pInPolicyEndpointJ = NULL; + err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ); + if (err) { AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err)); - return err; + return AHL_FAIL; } else { - err = Policy_Endpoint_Init(pPolicyEndpointJ); + json_object * pOutPolicyEndpointJ = NULL; + err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ); if (err == AHL_POLICY_REJECT) { - AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); - } - //free pPolicyEndpointJ - json_object_put(pPolicyEndpointJ); - } + AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); + // continue + } + json_object_put(pInPolicyEndpointJ); + err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ); + if (err) { + AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); + return AHL_FAIL; + } + // json_object_put(pOutPolicyEndpointJ); + } } } + if (pRoleInfo->pSinkEndpoints){ // for all sink endpoints for (int j = 0; j < pRoleInfo->pSinkEndpoints->len; j++) { EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSinkEndpoints,j); g_assert_nonnull(pCurEndpointInfo); - json_object *pPolicyEndpointJ = NULL; - err = PolicyEndpointStructToJSON(pCurEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { + json_object *pInPolicyEndpointJ = NULL; + err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ); + if (err) { AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err)); - return err; + return AHL_FAIL; } else { - err = Policy_Endpoint_Init(pPolicyEndpointJ); - if (err== AHL_POLICY_REJECT) { - AFB_ERROR("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); + json_object *pOutPolicyEndpointJ = NULL; + err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ); + if (err == AHL_POLICY_REJECT) { + AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); + // continue } - //free pPolicyEndpointJ - json_object_put(pPolicyEndpointJ); - } - + json_object_put(pInPolicyEndpointJ); + err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ); + if (err) { + AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); + return AHL_FAIL; + } + //json_object_put(pOutPolicyEndpointJ); + } } } } -#endif +#endif // AHL_DISCONNECT_POLICY // Initialize list of active streams g_AHLCtx.policyCtx.pStreams = g_hash_table_new(g_int_hash, g_int_equal); if(g_AHLCtx.policyCtx.pStreams == NULL) { AFB_ERROR("Unable to create Active Stream List"); - return err; + return AHL_FAIL; } - // TODO: Use AGL persistence framework to retrieve and set initial volumes/properties - AFB_DEBUG("Audio high-level Binding success"); - return err; + return AHL_SUCCESS; } PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ) @@ -550,21 +473,22 @@ PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ) #endif } -PUBLIC void audiohlapi_get_sources(struct afb_req req) +PUBLIC void audiohlapi_get_endpoints(struct afb_req req) { json_object *devicesJ = NULL; json_object *deviceJ = NULL; json_object *queryJ = NULL; char * audioRole = NULL; + char * pEndpointTypeStr = NULL; + EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role", &audioRole); + int err = wrap_json_unpack(queryJ, "{s:s,s:s}", "audio_role", &audioRole,"endpoint_type",&pEndpointTypeStr); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - - AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole); + endpointType = EndpointTypeToEnum(pEndpointTypeStr); RoleInfoT * pRole = GetRole(audioRole); if ( pRole == NULL ) @@ -575,61 +499,25 @@ PUBLIC void audiohlapi_get_sources(struct afb_req req) else { devicesJ = json_object_new_array(); - GPtrArray * pDeviceArray = pRole->pSourceEndpoints; + GPtrArray * pDeviceArray = NULL; + if (endpointType == ENDPOINTTYPE_SOURCE) + pDeviceArray = pRole->pSourceEndpoints; + else + pDeviceArray = pRole->pSinkEndpoints; if (pDeviceArray) { int iNumberDevices = pDeviceArray->len; for ( int j = 0 ; j < iNumberDevices; j++) { EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j); if (pEndpointInfo) { - EndpointInfoStructToJSON(&deviceJ, pEndpointInfo); + JSONPublicPackageEndpoint(pEndpointInfo,&deviceJ); json_object_array_add(devicesJ, deviceJ); } } } } - afb_req_success(req, devicesJ, "List of sources"); -} - -PUBLIC void audiohlapi_get_sinks(struct afb_req req) -{ - json_object *devicesJ = NULL; - json_object *deviceJ = NULL; - json_object *queryJ = NULL; - char * audioRole = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role", &audioRole); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - AFB_DEBUG("Filtering devices according to specified audio role=%s", audioRole); - - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid arguments", "Requested audio role does not exist in current configuration -> %s", json_object_get_string(queryJ)); - return; - } - else - { - devicesJ = json_object_new_array(); - GPtrArray * pDeviceArray = pRole->pSinkEndpoints; - if (pDeviceArray) { - int iNumberDevices = pDeviceArray->len; - for ( int j = 0 ; j < iNumberDevices; j++) - { - EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j); - EndpointInfoStructToJSON(&deviceJ, pEndpointInfo); - json_object_array_add(devicesJ, deviceJ); - } - } - } - - afb_req_success(req, devicesJ, "List of sinks"); + afb_req_success(req, devicesJ, "List of endpoints"); } PUBLIC void audiohlapi_stream_open(struct afb_req req) @@ -650,7 +538,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = audio_role:%s endpoint_type:%s endpoint_id:%d", audioRole,endpointTypeStr,endpointID); endpointType = EndpointTypeToEnum(endpointTypeStr); // Check if there is already an existing context for this client @@ -685,7 +572,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) // Assign a device based on configuration priority (first in the list for requested role and endpoint type) pEndpointInfo = g_ptr_array_index(pDeviceArray,0); endpointSelMode = ENDPOINTSELMODE_AUTO; - } else{ endpointSelMode = ENDPOINTSELMODE_MANUAL; @@ -699,7 +585,6 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) } pEndpointInfo = NULL; } - } if (pEndpointInfo == NULL) { @@ -724,8 +609,8 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) #ifndef AHL_DISCONNECT_POLICY // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions json_object *pPolicyStreamJ = NULL; - err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) + err = StreamInfoToJSON(pStreamInfo,&pPolicyStreamJ); + if (err) { afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_OpenStream"); return; @@ -762,7 +647,8 @@ PUBLIC void audiohlapi_stream_open(struct afb_req req) if (g_AHLCtx.policyCtx.pStreams) g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo ); - StreamInfoStructToJSON(&streamInfoJ,pStreamInfo); + // Package and return stream information to client + JSONPublicPackageStream(pStreamInfo,&streamInfoJ); afb_req_success(req, streamInfoJ, "Stream info structure"); } @@ -773,19 +659,11 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req) streamID_t streamID = AHL_UNDEFINED; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:i}", "stream_id", &streamID); + int err = wrap_json_unpack(queryJ, "{s?i}", "stream_id", &streamID); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID); - - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID); - return; - } // Check if there is already an existing context for this client AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure @@ -795,150 +673,108 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req) return; } - // Verify that this client can control the stream - int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID ); - if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED) - { - afb_req_fail(req, "Access control denied", "Close stream not allowed in current client context"); - return; - } - -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_CloseStream"); - return; - } - // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions - int policyAllowed = Policy_CloseStream(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(req, "Audio policy violation", "Close stream not allowed in current context"); - return; - } -#endif - - // Unsubscribe client from stream events - char streamEventName[128]; - snprintf(streamEventName,128,"ahl_streamstate_%d",streamID); - int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent); - if (iValid) { - err = afb_req_unsubscribe(req,pStreamInfo->streamStateEvent); + if (streamID == AHL_UNDEFINED) { + err = CloseAllClientStreams(pClientCtx,&req); if (err) { - afb_req_fail(req, "Stream event subscription failure", "Could not unsubscribe to stream specific state change event"); + afb_req_fail(req, "Error closing streams", "Streams cannot close"); return; } } - - // Remove from stream list (if present) - if (g_AHLCtx.policyCtx.pStreams) - g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID)); - free(pStreamInfo); - pStreamInfo = NULL; - - // Find index for cases where there are multiple streams per client - // Remove from client context stream ID and endpoint ID access rights - if (pClientCtx->pStreamAccessList) { - for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) { - streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i); - if (iID == streamID) { - g_array_remove_index(pClientCtx->pStreamAccessList, i); - } - } - - if (pClientCtx->pStreamAccessList->len == 0) { - // If no more streams/endpoints owner, clear session - afb_req_context_clear(req); + else { + err = CloseStream(pClientCtx,streamID,&req); + if (err) { + afb_req_fail_f(req, "Error closing stream", "Specified stream cannot close stream_id -> %d",streamID); + return; } } - + afb_req_success(req, NULL, "Stream close completed"); } - PUBLIC void audiohlapi_set_stream_state(struct afb_req req) - { - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - char * streamStateStr = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"state",&streamStateStr); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - AFB_DEBUG("Parsed input arguments = stream_id:%d, state:%s", streamID,streamStateStr); - +static int SetStreamState(AHLClientCtxT * in_pClientCtx,struct afb_req * pReq, streamID_t streamID, char * pStreamStateStr, char * pMuteStr) { + StreamInfoT * pStreamInfo = GetStream(streamID); if (pStreamInfo == NULL) { - afb_req_fail_f(req, "Stream not found", "Specified stream not found stream_id -> %d",streamID); - return; - } - - // Check if there is already an existing context for this client - AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure - if (pClientCtx == NULL) - { - afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)"); - return; + afb_req_fail_f(*pReq, "Stream not found", "Specified stream not found stream_id -> %d",streamID); + return AHL_FAIL; } // Verify that this client can control the stream - int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID ); + int iStreamAccessControl = CheckStreamAccessControl( in_pClientCtx, streamID ); if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED) { - afb_req_fail(req, "Access control denied", "Set stream state not allowed in current client context"); - return; + afb_req_fail(*pReq, "Access control denied", "Set stream state not allowed in current client context"); + return AHL_FAIL; } - StreamStateT streamState = StreamStateToEnum(streamStateStr); + if (pStreamStateStr != NULL) { + StreamStateT streamState = StreamStateToEnum(pStreamStateStr); #ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState"); - return; - } + json_object *pPolicyStreamJ = NULL; + int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + afb_req_fail(*pReq, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState"); + return AHL_FAIL; + } + + json_object *paramJ= json_object_new_int(streamState); + json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ); + + int policyAllowed = Policy_SetStreamState(pPolicyStreamJ); + if (policyAllowed == AHL_POLICY_REJECT) + { + afb_req_fail(*pReq, "Audio policy violation", "Change stream state not allowed in current context"); + return AHL_FAIL; + } +#else + // Simulate that policy returns target state (accepted) + pStreamInfo->streamState = streamState; +#endif + } - json_object *paramJ= json_object_new_int(streamState); - json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ); + if (pMuteStr != NULL) { + StreamMuteT muteState = StreamMuteToEnum(pMuteStr); +#ifndef AHL_DISCONNECT_POLICY + json_object *pPolicyStreamJ = NULL; + int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + afb_req_fail((*pReq), "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute"); + return AHL_FAIL; + } - int policyAllowed = Policy_SetStreamState(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(req, "Audio policy violation", "Change stream state not allowed in current context"); - return; - } + json_object *paramJ= json_object_new_int(muteState); + json_object_object_add(pPolicyStreamJ, "mute_state", paramJ); + + int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ); + if (policyAllowed == AHL_POLICY_REJECT) + { + afb_req_fail(*pReq, "Audio policy violation", "Mute stream not allowed in current context"); + return AHL_FAIL; + } #else - // Simulate that policy returns target state (accepted) - pStreamInfo->streamState = streamState; + // Simulate that policy returns target state (accepted) + pStreamInfo->streamMute = muteState; #endif + } - afb_req_success(req, NULL, "Set stream state"); - } + return AHL_SUCCESS; +} - PUBLIC void audiohlapi_set_stream_mute(struct afb_req req) + PUBLIC void audiohlapi_set_stream_state(struct afb_req req) { json_object *queryJ = NULL; streamID_t streamID = AHL_UNDEFINED; + char * streamStateStr = NULL; char * pMuteStr = NULL; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:i,s:s}", "stream_id", &streamID,"mute",&pMuteStr); + int err = wrap_json_unpack(queryJ, "{s?i,s?s,s?s}", "stream_id", &streamID,"state",&streamStateStr,"mute",&pMuteStr); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = stream_id:%d, mute:%s", streamID,pMuteStr); - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID); - return; - } // Check if there is already an existing context for this client AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure @@ -948,40 +784,27 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req) return; } - // Verify that this client can control the stream - int iStreamAccessControl = CheckStreamAccessControl( pClientCtx, streamID ); - if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED) - { - afb_req_fail(req, "Access control denied", "Set stream mute state not allowed in current client context"); - return; + if (streamID == AHL_UNDEFINED) { + // All stream for this client + if (pClientCtx->pStreamAccessList != NULL) { + for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++) + { + streamID_t curStreamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i); + err = SetStreamState(pClientCtx,&req,curStreamID,streamStateStr,pMuteStr); + if (err) { + return; + } + } + } } - - - StreamMuteT muteState = StreamMuteToEnum(pMuteStr); -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - err = PolicyStreamStructToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute"); - return; - } - - json_object *paramJ= json_object_new_int(muteState); - json_object_object_add(pPolicyStreamJ, "mute_state", paramJ); - - int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(req, "Audio policy violation", "Mute stream not allowed in current context"); - return; + else { + err = SetStreamState(pClientCtx,&req,streamID,streamStateStr,pMuteStr); + if (err) { + return; + } } -#else - // Simulate that policy returns target state (accepted) - pStreamInfo->streamMute = muteState; -#endif - afb_req_success(req, NULL, "Set stream mute completed"); + afb_req_success(req, NULL, "Set stream state"); } PUBLIC void audiohlapi_get_stream_info(struct afb_req req) @@ -996,7 +819,6 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req) afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = stream_id:%d", streamID); StreamInfoT * pStreamInfo = GetStream(streamID); if (pStreamInfo == NULL) { @@ -1004,12 +826,12 @@ PUBLIC void audiohlapi_stream_close(struct afb_req req) return; } - StreamInfoStructToJSON(&streamInfoJ,pStreamInfo); + JSONPublicPackageStream(pStreamInfo,&streamInfoJ); afb_req_success(req, streamInfoJ, "Get stream info completed"); } -PUBLIC void audiohlapi_set_volume(struct afb_req req) +PUBLIC void audiohlapi_volume(struct afb_req req) { json_object *queryJ = NULL; endpointID_t endpointID = AHL_UNDEFINED; @@ -1018,12 +840,11 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req) char * volumeStr = NULL; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr); + int err = wrap_json_unpack(queryJ, "{s:s,s:i,s?s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d volume:%s", pEndpointTypeStr,endpointID,volumeStr); endpointType = EndpointTypeToEnum(pEndpointTypeStr); EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); @@ -1033,62 +854,36 @@ PUBLIC void audiohlapi_set_volume(struct afb_req req) return; } + if (volumeStr != NULL) { #ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyEndpointJ = NULL; - err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); - return; - } + json_object *pPolicyEndpointJ = NULL; + err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); + return; + } - json_object *paramJ= json_object_new_string(volumeStr); - json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ); + json_object *paramJ= json_object_new_string(volumeStr); + json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ); - int policyAllowed = Policy_SetVolume(pPolicyEndpointJ); - if (!policyAllowed) - { - afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context"); - return; - } + int policyAllowed = Policy_SetVolume(pPolicyEndpointJ); + if (!policyAllowed) + { + afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context"); + return; + } #else - // Simulate that policy returns target state (accepted) - pEndpointInfo->iVolume = atoi(volumeStr); + // Simulate that policy returns target state (accepted) + pEndpointInfo->iVolume = atoi(volumeStr); #endif - - afb_req_success(req, NULL, "Set volume completed"); -} - -PUBLIC void audiohlapi_get_volume(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - json_object * volumeJ = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; } - AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID); - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); - if (pEndpointInfo == NULL) - { - afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType); - return; - } - - volumeJ = json_object_new_int(pEndpointInfo->iVolume); - - afb_req_success(req, volumeJ, "Retrieved volume value"); + json_object * volumeJ = json_object_new_int(pEndpointInfo->iVolume); + + afb_req_success(req, volumeJ, "Set/get volume completed"); } -// Properties PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req) { json_object *queryJ = NULL; @@ -1102,7 +897,6 @@ PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req) afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d", pEndpointTypeStr,endpointID); endpointType = EndpointTypeToEnum(pEndpointTypeStr); EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); @@ -1113,12 +907,12 @@ PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req) } json_object *endpointInfoJ = NULL; - EndpointInfoStructToJSON(&endpointInfoJ,pEndpointInfo); + EndpointInfoToJSON(pEndpointInfo,&endpointInfoJ); afb_req_success(req, endpointInfoJ, "Retrieved endpoint information and properties"); } -PUBLIC void audiohlapi_set_property(struct afb_req req) +PUBLIC void audiohlapi_property(struct afb_req req) { json_object *queryJ = NULL; endpointID_t endpointID = AHL_UNDEFINED; @@ -1128,12 +922,11 @@ PUBLIC void audiohlapi_set_property(struct afb_req req) json_object * propValueJ = NULL; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s:o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ); + int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s?o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName); endpointType = EndpointTypeToEnum(pEndpointTypeStr); EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); @@ -1143,59 +936,32 @@ PUBLIC void audiohlapi_set_property(struct afb_req req) return; } -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyEndpointJ = NULL; - err = PolicyEndpointStructToJSON(pEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); - return; - } - - json_object *paramJ= json_object_new_string(propertyName); - json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ); - json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ); - - // Call policy to allow custom policy actions in current context - int policyAllowed = Policy_SetProperty(pPolicyEndpointJ); - if (!policyAllowed) - { - afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context"); - return; - } -#else - // Simulate that policy returns target state (accepted) - if (pEndpointInfo->pPropTable) - g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ); -#endif - - //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,queryJ); + if (propValueJ != NULL) { + #ifndef AHL_DISCONNECT_POLICY + json_object *pPolicyEndpointJ = NULL; + err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); + return; + } - afb_req_success(req, NULL, "Set property completed"); -} + json_object *paramJ= json_object_new_string(propertyName); + json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ); + json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ); -PUBLIC void audiohlapi_get_property(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - char * propertyName = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - AFB_DEBUG("Parsed input arguments = endpoint_type:%s endpoint_id:%d property_name:%s", pEndpointTypeStr,endpointID,propertyName); - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); - if (pEndpointInfo == NULL) - { - afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType); - return; + // Call policy to allow custom policy actions in current context + int policyAllowed = Policy_SetProperty(pPolicyEndpointJ); + if (!policyAllowed) + { + afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context"); + return; + } + #else + // Simulate that policy returns target state (accepted) + if (pEndpointInfo->pPropTable) + g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ); + #endif } // Retrieve cached property value @@ -1206,14 +972,10 @@ PUBLIC void audiohlapi_get_property(struct afb_req req) } json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object - //AFB_WARNING("properties %s", json_object_get_string(propertyValJ)); - //json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object - afb_req_success(req, propertyValJ, "Retrieved property value"); + afb_req_success(req, propertyValJ, "Set/get property completed"); } -// Audio related events - PUBLIC void audiohlapi_get_list_actions(struct afb_req req) { json_object *queryJ = NULL; @@ -1226,7 +988,6 @@ PUBLIC void audiohlapi_get_list_actions(struct afb_req req) afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = audio_role:%s",audioRole); // Build and return list of actions for specific audio role RoleInfoT * pRole = GetRole(audioRole); @@ -1264,7 +1025,6 @@ PUBLIC void audiohlapi_post_action(struct afb_req req) afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; } - AFB_DEBUG("Parsed input arguments = action_name:%s audio_role:%s", actionName,audioRole); // Verify if known action for audio role RoleInfoT * pRole = GetRole(audioRole); @@ -1296,7 +1056,14 @@ PUBLIC void audiohlapi_post_action(struct afb_req req) #ifndef AHL_DISCONNECT_POLICY // Call policy to allow custom policy actions in current context (e.g. cancel playback) - int policyAllowed = Policy_PostAction(queryJ); + json_object * pActionInfo = NULL; + err = wrap_json_pack(&pActionInfo, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); + if (err) { + afb_req_fail_f(req, "Invalid arguments", "Could not create action JSON object arguments"); + return; + } + json_object_get(pActionInfo); + int policyAllowed = Policy_PostAction(pActionInfo); if (!policyAllowed) { afb_req_fail(req, "Audio policy violation", "Post sound action not allowed in current context"); @@ -1304,63 +1071,17 @@ PUBLIC void audiohlapi_post_action(struct afb_req req) } #endif - //afb_event_push(g_AHLCtx.policyCtx.postEvent,queryJ); - afb_req_success(req, NULL, "Posted sound action"); } - -// Monitoring -PUBLIC void audiohlapi_subscribe(struct afb_req req) -{ - json_object *queryJ = NULL; - json_object * eventArrayJ = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:o}", "events", &eventArrayJ); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - int iNumEvents = json_object_array_length(eventArrayJ); - for (int i = 0; i < iNumEvents; i++) - { - char * pEventName = NULL; - json_object * jEvent = json_object_array_get_idx(eventArrayJ,i); - pEventName = (char *)json_object_get_string(jEvent); - if(pEventName == NULL) { - afb_req_fail(req, "failed", "Invalid event"); - return; - } - else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) { - afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent); - AFB_DEBUG("Client subscribed to endpoint property events"); - } - else if(!strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)) { - afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent); - AFB_DEBUG("Client subscribed to endpoint volume events"); - } - else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) { - afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent); - AFB_DEBUG("Client subscribed to post event calls events"); - } - else { - afb_req_fail(req, "failed", "Invalid event"); - return; - } - } - - afb_req_success(req, NULL, "Subscribe to events finished"); -} - -PUBLIC void audiohlapi_unsubscribe(struct afb_req req) +PUBLIC void audiohlapi_event_subscription(struct afb_req req) { json_object *queryJ = NULL; json_object * eventArrayJ = NULL; + int iSubscribe = 1; queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:o}", "events", &eventArrayJ); + int err = wrap_json_unpack(queryJ, "{s:o,s:i}", "events", &eventArrayJ,"subscribe",&iSubscribe); if (err) { afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); return; @@ -1377,16 +1098,22 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req) return; } else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) { - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent); - AFB_DEBUG("Client unsubscribed to endpoint property events"); + if (iSubscribe) + afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent); + else + afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent); } else if(!strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)) { - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent); - AFB_DEBUG("Client unsubscribed to endpoint volume events"); + if (iSubscribe) + afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent); + else + afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent); } else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) { - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent); - AFB_DEBUG("Client unsubscribed to post event calls events"); + if (iSubscribe) + afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent); + else + afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent); } else { afb_req_fail(req, "failed", "Invalid event"); @@ -1394,7 +1121,7 @@ PUBLIC void audiohlapi_unsubscribe(struct afb_req req) } } - afb_req_success(req, NULL, "Unsubscribe to events finished"); + afb_req_success(req, NULL, "Event subscription update finished"); } // Since the policy is currently in the same binding, it cannot raise events on its own @@ -1411,42 +1138,7 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) return; } - if(strcasecmp(pEventName, AHL_ENDPOINT_INIT_EVENT)==0) { - char * pAudioRole = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s}", - "endpoint_id", &endpointID, - "endpoint_type", &endpointType, - "audio_role", &pAudioRole); - if(err) - { - AFB_ERROR("Unable to unpack property init event"); - return; - } - - RoleInfoT * pRole = GetRole(pAudioRole); - if ( pRole == NULL ){ - AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); - return; - } - - EndpointInfoT * pEndpointInfo = InitEndpointInfo(); - g_assert_nonnull(pEndpointInfo); - PolicyCtxJSONToEndpoint(pEventDataJ,pEndpointInfo); - - err = ReplaceEndpointInfoWithRole(endpointID,endpointType,pRole,pEndpointInfo); - if(err == AHL_FAIL) - { - AFB_ERROR("Can't update EndpointInfo aborting"); - return; - } - - // Remove event name from object - // json_object_object_del(pEventDataJ,"event_name"); - //afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ); // Not broadcasted to application at this time - } - else if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) { + if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) { char * pAudioRole = NULL; char * pPropertyName = NULL; endpointID_t endpointID = AHL_UNDEFINED; @@ -1470,18 +1162,18 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) } EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); // update property value - if (pEndpointInfo->pPropTable) + if ((pEndpointInfo!=NULL) && (pEndpointInfo->pPropTable!=NULL)) { json_type jType = json_object_get_type(propValueJ); switch (jType) { case json_type_double: - Add_Endpoint_Property_Double(pEndpointInfo,pPropertyName,json_object_get_double(propValueJ)); + g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_double(json_object_get_double(propValueJ))); break; case json_type_int: - Add_Endpoint_Property_Int(pEndpointInfo,pPropertyName,json_object_get_int(propValueJ)); + g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_int(json_object_get_int(propValueJ))); break; case json_type_string: - Add_Endpoint_Property_String(pEndpointInfo,pPropertyName,json_object_get_string(propValueJ)); + g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_string(json_object_get_string(propValueJ))); break; default: AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(propValueJ)); @@ -1512,9 +1204,16 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); return; } - EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); + EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); // update volume value - pEndpointInfo->iVolume = iVolume; + if(pEndpointInfo) + { + pEndpointInfo->iVolume = iVolume; + } + else + { + AFB_ERROR("Unable to find endpoint"); + } // Remove event name from object json_object_object_del(pEventDataJ,"event_name"); afb_event_push(g_AHLCtx.policyCtx.volumeEvent,pEventDataJ); @@ -1522,6 +1221,7 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) else if(strcasecmp(pEventName, AHL_POST_ACTION_EVENT)==0) { // Remove event name from object json_object_object_del(pEventDataJ,"event_name"); + // BUG: This crashes... afb_event_push(g_AHLCtx.policyCtx.postActionEvent,pEventDataJ); } else if(strcasecmp(pEventName, AHL_STREAM_STATE_EVENT)==0) { @@ -1568,7 +1268,6 @@ PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) // Remove event name from object json_object_object_del(pEventDataJ,"event_name"); - AFB_ERROR("pEventDataJ=%s", json_object_get_string(pEventDataJ)); afb_event_push(pStreamInfo->streamStateEvent,pEventDataJ); } else { |