diff options
author | Tai Vuong <tvuong@audiokinetic.com> | 2017-11-02 16:31:15 -0400 |
---|---|---|
committer | Tai Vuong <tvuong@audiokinetic.com> | 2017-11-02 16:31:15 -0400 |
commit | 5d2ee4455d95771d12cc6058bc19c0d6f7fe43d1 (patch) | |
tree | b4cbc2be7475641edf71ae42c6ce117dba27b91d /src/ahl-binding.c | |
parent | e92aade201ec131c3eb7430305f60a0a4c9c44c1 (diff) | |
parent | ab6e470190f2cc410b1f6fa8f146317a3c3b08b5 (diff) |
merge dev branch with master
Diffstat (limited to 'src/ahl-binding.c')
-rw-r--r-- | src/ahl-binding.c | 1276 |
1 files changed, 0 insertions, 1276 deletions
diff --git a/src/ahl-binding.c b/src/ahl-binding.c deleted file mode 100644 index c205c8e..0000000 --- a/src/ahl-binding.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * Copyright (C) 2017 "Audiokinetic Inc" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <string.h> - -#include "ahl-binding.h" -#include "ahl-apidef.h" // Generated from JSON OpenAPI -#include "wrap-json.h" -#include "ahl-policy.h" -#include "ahl-json.h" - -// Global high-level binding context -AHLCtxT g_AHLCtx; - -static EndpointTypeT EndpointTypeToEnum(char * in_pEndpointTypeStr) -{ - if (in_pEndpointTypeStr == NULL) { - return ENDPOINTTYPE_MAXVALUE; - } - else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SOURCE)==0) { - return ENDPOINTTYPE_SOURCE; - } - else if (strcasecmp(in_pEndpointTypeStr,AHL_ENDPOINTTYPE_SINK)==0) { - return ENDPOINTTYPE_SINK; - } - else - return ENDPOINTTYPE_MAXVALUE; -} - -static StreamStateT StreamStateToEnum(char * in_pStreamStateStr) -{ - if (in_pStreamStateStr == NULL) { - return STREAM_STATE_MAXVALUE; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_IDLE)==0) { - return STREAM_STATE_IDLE; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_RUNNING)==0) { - return STREAM_STATE_RUNNING; - } - else if (strcasecmp(in_pStreamStateStr,AHL_STREAM_STATE_PAUSED)==0) { - return STREAM_STATE_PAUSED; - } - else - return STREAM_STATE_MAXVALUE; -} - -static StreamMuteT StreamMuteToEnum(char * in_pStreamMuteStr) -{ - if (in_pStreamMuteStr == NULL) { - return STREAM_MUTE_MAXVALUE; - } - else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_UNMUTED)==0) { - return STREAM_UNMUTED; - } - else if (strcasecmp(in_pStreamMuteStr,AHL_STREAM_MUTED)==0) { - return STREAM_MUTED; - } - else - return STREAM_MUTE_MAXVALUE; -} - -static streamID_t CreateNewStreamID() -{ - streamID_t newID = g_AHLCtx.nextStreamID; - g_AHLCtx.nextStreamID++; - return newID; -} - -static EndpointInfoT * GetEndpointInfoWithRole(endpointID_t in_endpointID, EndpointTypeT in_endpointType, RoleInfoT * in_pRole) -{ - EndpointInfoT * pEndpointInfo = NULL; - GPtrArray * pDeviceArray = NULL; - if (in_endpointType == ENDPOINTTYPE_SOURCE){ - pDeviceArray = in_pRole->pSourceEndpoints; - } - else { - pDeviceArray = in_pRole->pSinkEndpoints; - } - g_assert_nonnull(pDeviceArray); - - for (int j = 0; j < pDeviceArray->len; j++) { - EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pDeviceArray,j); - g_assert_nonnull(pCurEndpointInfo); - if (pCurEndpointInfo->endpointID == in_endpointID) { - pEndpointInfo = pCurEndpointInfo; - break; - } - } - - return pEndpointInfo; -} - -static EndpointInfoT * GetEndpointInfo(endpointID_t in_endpointID, EndpointTypeT in_endpointType) -{ - EndpointInfoT * pEndpointInfo = NULL; - - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo); - while (pEndpointInfo == NULL && g_hash_table_iter_next (&iter, &key, &value)) - { - RoleInfoT * pRoleInfo = (RoleInfoT*)value; - pEndpointInfo = GetEndpointInfoWithRole(in_endpointID,in_endpointType,pRoleInfo); - } - - return pEndpointInfo; -} - -static StreamInfoT * GetStream(streamID_t in_streamID) -{ - if (g_AHLCtx.policyCtx.pStreams == NULL) - return NULL; - - return g_hash_table_lookup(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&in_streamID)); -} - -static RoleInfoT * GetRole(char * in_pAudioRoleName) -{ - if (g_AHLCtx.policyCtx.pRoleInfo == NULL) - return NULL; - - return g_hash_table_lookup(g_AHLCtx.policyCtx.pRoleInfo,in_pAudioRoleName); -} - -static int CloseStream(AHLClientCtxT * in_pClientCtx, streamID_t streamID,struct afb_req * pReq) { - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); - return AHL_FAIL; - } - -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - AFB_ERROR("Audio policy violation, Unable to get JSON object for Policy_CloseStream"); - return AHL_FAIL; - } - int policyAllowed = Policy_CloseStream(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - AFB_ERROR("Close stream not allowed in current context"); - return AHL_FAIL; - } -#endif - // Unsubscribe client from stream events - if (pReq != NULL) { - char streamEventName[128]; - snprintf(streamEventName,128,"ahl_streamstate_%d",streamID); - int iValid = afb_event_is_valid(pStreamInfo->streamStateEvent); - if (iValid) { - err = afb_req_unsubscribe(*pReq,pStreamInfo->streamStateEvent); - if (err) { - AFB_ERROR("Could not unsubscribe to stream specific state change event"); - return AHL_FAIL; - } - } - } - - // Remove from stream list (if present) - if (g_AHLCtx.policyCtx.pStreams) - g_hash_table_remove(g_AHLCtx.policyCtx.pStreams,GINT_TO_POINTER(&pStreamInfo->streamID)); - free(pStreamInfo); - pStreamInfo = NULL; - - // Find index for cases where there are multiple streams per client - // Remove from client context stream ID and endpoint ID access rights - if (in_pClientCtx->pStreamAccessList) { - for (int i = 0; i < in_pClientCtx->pStreamAccessList->len ; i++) { - streamID_t iID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,i); - if (iID == streamID) { - g_array_remove_index(in_pClientCtx->pStreamAccessList, i); - } - } - } - - return AHL_SUCCESS; -} - -static int CloseAllClientStreams(AHLClientCtxT * in_pClientCtx, struct afb_req * pReq) -{ - g_assert_nonnull(in_pClientCtx); - if (in_pClientCtx->pStreamAccessList != NULL) { - while( in_pClientCtx->pStreamAccessList->len ) - { - streamID_t streamID = g_array_index(in_pClientCtx->pStreamAccessList,streamID_t,0); - int err = CloseStream(in_pClientCtx,streamID,pReq); - if (err) { - return err; - } - } - } - - return AHL_SUCCESS; -} - -static AHLClientCtxT * AllocateClientContext() -{ - AHLClientCtxT * pClientCtx = malloc(sizeof(AHLClientCtxT)); - pClientCtx->pStreamAccessList = g_array_new(FALSE, TRUE, sizeof(streamID_t)); - return pClientCtx; -} - -static void TerminateClientContext(void * ptr) -{ - AHLClientCtxT * pClientCtx = (AHLClientCtxT *) ptr; - if (pClientCtx != NULL) { - CloseAllClientStreams(pClientCtx,NULL); - - if (pClientCtx->pStreamAccessList) { - g_array_free( pClientCtx->pStreamAccessList, TRUE); - pClientCtx->pStreamAccessList = NULL; - } - - free(pClientCtx); - } -} - -static int CheckStreamAccessControl(AHLClientCtxT * pClientCtx, streamID_t streamID) -{ - int iAccessControl = AHL_ACCESS_CONTROL_DENIED; - if (pClientCtx && pClientCtx->pStreamAccessList) { - for (int i = 0; i < pClientCtx->pStreamAccessList->len ; i++) { - streamID_t iID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i); - if (iID == streamID) { - iAccessControl = AHL_ACCESS_CONTROL_GRANTED; - } - } - } - return iAccessControl; -} - -static int CreateEvents() -{ - g_AHLCtx.policyCtx.propertyEvent = afb_daemon_make_event(AHL_ENDPOINT_PROPERTY_EVENT); - int err = !afb_event_is_valid(g_AHLCtx.policyCtx.propertyEvent); - if (err) { - AFB_ERROR("Could not create endpoint property change event"); - return AHL_FAIL; - } - - g_AHLCtx.policyCtx.volumeEvent = afb_daemon_make_event(AHL_ENDPOINT_VOLUME_EVENT); - err = !afb_event_is_valid(g_AHLCtx.policyCtx.volumeEvent); - if (err) { - AFB_ERROR("Could not create endpoint volume change event"); - return AHL_FAIL; - } - - g_AHLCtx.policyCtx.postActionEvent = afb_daemon_make_event(AHL_POST_ACTION_EVENT); - err = !afb_event_is_valid(g_AHLCtx.policyCtx.postActionEvent); - if (err) { - AFB_ERROR("Could not create post action event call event"); - return AHL_FAIL; - } - - return AHL_SUCCESS; -} - -static void AhlBindingTerm() -{ -#ifndef AHL_DISCONNECT_POLICY - // Policy termination - Policy_Term(); -#endif - - // Roles - if (g_AHLCtx.policyCtx.pRoleInfo != NULL) { - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init(&iter, g_AHLCtx.policyCtx.pRoleInfo); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - RoleInfoT * pRole = (RoleInfoT *)value; - if (pRole) - { - if(pRole->pRoleName) { - g_free(pRole->pRoleName); - pRole->pRoleName = NULL; - } - // Actions - if (pRole->pActionList) { - for (int i = 0; i < pRole->pActionList->len; i++) - { - g_ptr_array_remove_index( pRole->pActionList, i ); // Free char * is called by GLib - } - } - // Source endpoints - if (pRole->pSourceEndpoints) { - for (int i = 0; i < pRole->pSourceEndpoints->len; i++) - { - EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSourceEndpoints, i ); // Free endpoint * is called by GLib - if (pEndpoint) { - TermEndpointInfo(pEndpoint); - } - } - } - // Sink endpoints - if (pRole->pSinkEndpoints) { - for (int i = 0; i < pRole->pSinkEndpoints->len; i++) - { - EndpointInfoT * pEndpoint = g_ptr_array_remove_index( pRole->pSinkEndpoints, i ); // Free endpoint * is called by GLib - if (pEndpoint) { - TermEndpointInfo(pEndpoint); - } - } - } - free(pRole); - } - } - g_hash_table_remove_all(g_AHLCtx.policyCtx.pRoleInfo); - g_hash_table_destroy(g_AHLCtx.policyCtx.pRoleInfo); - g_AHLCtx.policyCtx.pRoleInfo = NULL; - } - - if (g_AHLCtx.policyCtx.pStreams) { - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pStreams); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (value) - free(value); - } - g_hash_table_remove_all(g_AHLCtx.policyCtx.pStreams); - g_hash_table_destroy(g_AHLCtx.policyCtx.pStreams); - g_AHLCtx.policyCtx.pStreams = NULL; - } - - if (g_AHLCtx.policyCtx.pHALList) { - g_ptr_array_free(g_AHLCtx.policyCtx.pHALList,TRUE); - g_AHLCtx.policyCtx.pHALList = NULL; - } - - AFB_INFO("Audio high-level binding termination success"); -} - -// Binding initialization -PUBLIC int AhlBindingInit() -{ - memset(&g_AHLCtx,0,sizeof(g_AHLCtx)); - - // Register exit function - atexit(AhlBindingTerm); - - // Create AGL Events - int err = CreateEvents(); - if(err) { - // Error messages already reported inside CreateEvents - return AHL_FAIL; - } - - // Parse high-level binding JSON configuration file (will build device lists) - err = ParseHLBConfig(); - if(err) { - // Error messages already reported inside ParseHLBConfig - return AHL_FAIL; - } - -#ifndef AHL_DISCONNECT_POLICY - // Policy initialization - err = Policy_Init(); - if(err == AHL_POLICY_REJECT) { - //Error messages already reported inside PolicyInit - return AHL_FAIL; - } - - // Call policy for initalization of all source + sink endpoints for all audio Roles - GHashTableIter iter; - gpointer key, value; - g_hash_table_iter_init (&iter, g_AHLCtx.policyCtx.pRoleInfo); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - RoleInfoT * pRoleInfo = (RoleInfoT*)value; - if (pRoleInfo->pSourceEndpoints){ - // for all source endpoints - for (int j = 0; j < pRoleInfo->pSourceEndpoints->len; j++) { - EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSourceEndpoints,j); - g_assert_nonnull(pCurEndpointInfo); - json_object *pInPolicyEndpointJ = NULL; - err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ); - if (err) { - AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err)); - return AHL_FAIL; - } - else - { - json_object * pOutPolicyEndpointJ = NULL; - err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ); - if (err == AHL_POLICY_REJECT) { - AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); - // continue - } - json_object_put(pInPolicyEndpointJ); - err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ); - if (err) { - AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); - return AHL_FAIL; - } - // json_object_put(pOutPolicyEndpointJ); - } - } - } - - if (pRoleInfo->pSinkEndpoints){ - // for all sink endpoints - for (int j = 0; j < pRoleInfo->pSinkEndpoints->len; j++) { - EndpointInfoT * pCurEndpointInfo = g_ptr_array_index(pRoleInfo->pSinkEndpoints,j); - g_assert_nonnull(pCurEndpointInfo); - json_object *pInPolicyEndpointJ = NULL; - err = EndpointInfoToJSON(pCurEndpointInfo, &pInPolicyEndpointJ); - if (err) { - AFB_ERROR("Unable to Create Endpoint Json object error:%s ",wrap_json_get_error_string(err)); - return AHL_FAIL; - } - else - { - json_object *pOutPolicyEndpointJ = NULL; - err = Policy_Endpoint_Init(pInPolicyEndpointJ,&pOutPolicyEndpointJ); - if (err == AHL_POLICY_REJECT) { - AFB_WARNING("Policy endpoint properties initalization failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); - // continue - } - json_object_put(pInPolicyEndpointJ); - err = UpdateEndpointInfo(pCurEndpointInfo,pOutPolicyEndpointJ); - if (err) { - AFB_ERROR("Policy endpoint properties update failed for endpoint_id :%d type:%d",pCurEndpointInfo->endpointID, pCurEndpointInfo->type); - return AHL_FAIL; - } - //json_object_put(pOutPolicyEndpointJ); - } - } - } - } -#endif // AHL_DISCONNECT_POLICY - - // Initialize list of active streams - g_AHLCtx.policyCtx.pStreams = g_hash_table_new(g_int_hash, g_int_equal); - if(g_AHLCtx.policyCtx.pStreams == NULL) - { - AFB_ERROR("Unable to create Active Stream List"); - return AHL_FAIL; - } - - AFB_DEBUG("Audio high-level Binding success"); - return AHL_SUCCESS; -} - -PUBLIC void AhlOnEvent(const char *evtname, json_object *eventJ) -{ - AFB_DEBUG("AHL received event %s", evtname); - - // TODO: Handle event from the policy to update internal information (currently not possible since within the same binding) - -#ifndef AHL_DISCONNECT_POLICY - // Temp: currently forward to policy to handle events (they will be received directly when disconnected into separate binding) - Policy_OnEvent(evtname, eventJ); -#endif -} - -PUBLIC void audiohlapi_get_endpoints(struct afb_req req) -{ - json_object *devicesJ = NULL; - json_object *deviceJ = NULL; - json_object *queryJ = NULL; - char * audioRole = NULL; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:s}", "audio_role", &audioRole,"endpoint_type",&pEndpointTypeStr); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid arguments", "Requested audio role does not exist in current configuration -> %s", json_object_get_string(queryJ)); - return; - } - else - { - devicesJ = json_object_new_array(); - GPtrArray * pDeviceArray = NULL; - if (endpointType == ENDPOINTTYPE_SOURCE) - pDeviceArray = pRole->pSourceEndpoints; - else - pDeviceArray = pRole->pSinkEndpoints; - if (pDeviceArray) { - int iNumberDevices = pDeviceArray->len; - for ( int j = 0 ; j < iNumberDevices; j++) - { - EndpointInfoT * pEndpointInfo = g_ptr_array_index(pDeviceArray,j); - if (pEndpointInfo) { - JSONPublicPackageEndpoint(pEndpointInfo,&deviceJ); - json_object_array_add(devicesJ, deviceJ); - } - } - } - } - - afb_req_success(req, devicesJ, "List of endpoints"); -} - -PUBLIC void audiohlapi_stream_open(struct afb_req req) -{ - json_object *streamInfoJ = NULL; - StreamInfoT * pStreamInfo = NULL; - json_object *queryJ = NULL; - char * audioRole = NULL; - char * endpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointInfoT * pEndpointInfo = NULL; - EndpointSelectionModeT endpointSelMode = ENDPOINTSELMODEMAXVALUE; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?i}", "audio_role", &audioRole, "endpoint_type", &endpointTypeStr, "endpoint_id", &endpointID); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - endpointType = EndpointTypeToEnum(endpointTypeStr); - - // Check if there is already an existing context for this client - AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure - if (pClientCtx == NULL) - { - pClientCtx = AllocateClientContext(); - afb_req_context_set(req, pClientCtx, TerminateClientContext); - } - - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - GPtrArray * pDeviceArray = NULL; - if (endpointType == ENDPOINTTYPE_SOURCE){ - pDeviceArray = pRole->pSourceEndpoints; - } - else{ - pDeviceArray = pRole->pSinkEndpoints; - } - if (pDeviceArray == NULL || pDeviceArray->len == 0) { - afb_req_fail_f(req, "No available devices", "No available devices for role:%s and device type:%s",audioRole,endpointTypeStr); - return; - } - - if (endpointID == AHL_UNDEFINED) - { - // Assign a device based on configuration priority (first in the list for requested role and endpoint type) - pEndpointInfo = g_ptr_array_index(pDeviceArray,0); - endpointSelMode = ENDPOINTSELMODE_AUTO; - } - else{ - endpointSelMode = ENDPOINTSELMODE_MANUAL; - // Find specified endpoint ID in list of devices - int iNumberDevices = pDeviceArray->len; - for ( int j = 0 ; j < iNumberDevices; j++) - { - pEndpointInfo = g_ptr_array_index(pDeviceArray,j); - if (pEndpointInfo && pEndpointInfo->endpointID == endpointID) { - break; - } - pEndpointInfo = NULL; - } - } - - if (pEndpointInfo == NULL) { - afb_req_fail_f(req, "Endpoint not available", "Specified endpoint not available for role:%s and device type:%d endpoint id %d",audioRole,endpointType,endpointID); - return; - } - - pStreamInfo = (StreamInfoT*) malloc(sizeof(StreamInfoT)); - memset(pStreamInfo,0,sizeof(StreamInfoT)); - - // Create stream - pStreamInfo->streamID = CreateNewStreamID(); // create new ID - pStreamInfo->streamState = STREAM_STATE_IDLE; - pStreamInfo->streamMute = STREAM_UNMUTED; - pStreamInfo->pEndpointInfo = pEndpointInfo; - pStreamInfo->endpointSelMode = endpointSelMode; - // Directly from role config for now, but could be programmatically overriden in the future - pStreamInfo->pRoleName = pRole->pRoleName; - pStreamInfo->iPriority = pRole->iPriority; - pStreamInfo->eInterruptBehavior = pRole->eInterruptBehavior; - -#ifndef AHL_DISCONNECT_POLICY - // Call policy to verify whether creating a new audio stream is allowed in current context and possibly take other actions - json_object *pPolicyStreamJ = NULL; - err = StreamInfoToJSON(pStreamInfo,&pPolicyStreamJ); - if (err) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_OpenStream"); - return; - } - - int policyAllowed = Policy_OpenStream(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(req, "Audio policy violation", "Open stream not allowed in current context"); - return; - } -#endif - - char streamEventName[128]; - snprintf(streamEventName,128,"ahl_streamstate_%d",pStreamInfo->streamID); - - pStreamInfo->streamStateEvent = afb_daemon_make_event(streamEventName); - err = !afb_event_is_valid(pStreamInfo->streamStateEvent); - if (err) { - afb_req_fail(req, "Stream event creation failure", "Could not create stream specific state change event"); - return; - } - - err = afb_req_subscribe(req,pStreamInfo->streamStateEvent); - if (err) { - afb_req_fail(req, "Stream event subscription failure", "Could not subscribe to stream specific state change event"); - return; - } - - // Add to client context stream ID access rights - g_array_append_val(pClientCtx->pStreamAccessList, pStreamInfo->streamID); - - // Push stream on active stream list - if (g_AHLCtx.policyCtx.pStreams) - g_hash_table_insert( g_AHLCtx.policyCtx.pStreams, GINT_TO_POINTER(&pStreamInfo->streamID), pStreamInfo ); - - // Package and return stream information to client - JSONPublicPackageStream(pStreamInfo,&streamInfoJ); - - afb_req_success(req, streamInfoJ, "Stream info structure"); -} - -PUBLIC void audiohlapi_stream_close(struct afb_req req) -{ - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s?i}", "stream_id", &streamID); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - // Check if there is already an existing context for this client - AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure - if (pClientCtx == NULL) - { - afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)"); - return; - } - - if (streamID == AHL_UNDEFINED) { - err = CloseAllClientStreams(pClientCtx,&req); - if (err) { - afb_req_fail(req, "Error closing streams", "Streams cannot close"); - return; - } - } - else { - err = CloseStream(pClientCtx,streamID,&req); - if (err) { - afb_req_fail_f(req, "Error closing stream", "Specified stream cannot close stream_id -> %d",streamID); - return; - } - } - - afb_req_success(req, NULL, "Stream close completed"); -} - -static int SetStreamState(AHLClientCtxT * in_pClientCtx,struct afb_req * pReq, streamID_t streamID, char * pStreamStateStr, char * pMuteStr) { - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - afb_req_fail_f(*pReq, "Stream not found", "Specified stream not found stream_id -> %d",streamID); - return AHL_FAIL; - } - - // Verify that this client can control the stream - int iStreamAccessControl = CheckStreamAccessControl( in_pClientCtx, streamID ); - if (iStreamAccessControl == AHL_ACCESS_CONTROL_DENIED) - { - afb_req_fail(*pReq, "Access control denied", "Set stream state not allowed in current client context"); - return AHL_FAIL; - } - - if (pStreamStateStr != NULL) { - StreamStateT streamState = StreamStateToEnum(pStreamStateStr); -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(*pReq, "Audio policy violation", "Unable to get JSON object for Policy_SetStreamState"); - return AHL_FAIL; - } - - json_object *paramJ= json_object_new_int(streamState); - json_object_object_add(pPolicyStreamJ, "arg_stream_state", paramJ); - - int policyAllowed = Policy_SetStreamState(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(*pReq, "Audio policy violation", "Change stream state not allowed in current context"); - return AHL_FAIL; - } -#else - // Simulate that policy returns target state (accepted) - pStreamInfo->streamState = streamState; -#endif - } - - if (pMuteStr != NULL) { - StreamMuteT muteState = StreamMuteToEnum(pMuteStr); -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyStreamJ = NULL; - int err = StreamInfoToJSON(pStreamInfo, &pPolicyStreamJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail((*pReq), "Audio policy violation", "Unable to get JSON object for Policy_SetStreamMute"); - return AHL_FAIL; - } - - json_object *paramJ= json_object_new_int(muteState); - json_object_object_add(pPolicyStreamJ, "mute_state", paramJ); - - int policyAllowed = Policy_SetStreamMute(pPolicyStreamJ); - if (policyAllowed == AHL_POLICY_REJECT) - { - afb_req_fail(*pReq, "Audio policy violation", "Mute stream not allowed in current context"); - return AHL_FAIL; - } -#else - // Simulate that policy returns target state (accepted) - pStreamInfo->streamMute = muteState; -#endif - } - - return AHL_SUCCESS; -} - - PUBLIC void audiohlapi_set_stream_state(struct afb_req req) - { - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - char * streamStateStr = NULL; - char * pMuteStr = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s?i,s?s,s?s}", "stream_id", &streamID,"state",&streamStateStr,"mute",&pMuteStr); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - // Check if there is already an existing context for this client - AHLClientCtxT * pClientCtx = afb_req_context_get(req); // Retrieve client-specific data structure - if (pClientCtx == NULL) - { - afb_req_fail(req, "Bad state", "No client context associated with the request (is there an opened stream by this client?)"); - return; - } - - if (streamID == AHL_UNDEFINED) { - // All stream for this client - if (pClientCtx->pStreamAccessList != NULL) { - for (int i = 0; i < pClientCtx->pStreamAccessList->len; i++) - { - streamID_t curStreamID = g_array_index(pClientCtx->pStreamAccessList,streamID_t,i); - err = SetStreamState(pClientCtx,&req,curStreamID,streamStateStr,pMuteStr); - if (err) { - return; - } - } - } - } - else { - err = SetStreamState(pClientCtx,&req,streamID,streamStateStr,pMuteStr); - if (err) { - return; - } - } - - afb_req_success(req, NULL, "Set stream state"); - } - - PUBLIC void audiohlapi_get_stream_info(struct afb_req req) - { - json_object *queryJ = NULL; - streamID_t streamID = AHL_UNDEFINED; - json_object * streamInfoJ = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:i}", "stream_id", &streamID); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - afb_req_fail_f(req, "Stream not found", "Specified stream not currently active stream_id -> %d",streamID); - return; - } - - JSONPublicPackageStream(pStreamInfo,&streamInfoJ); - - afb_req_success(req, streamInfoJ, "Get stream info completed"); - } - -PUBLIC void audiohlapi_volume(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - char * volumeStr = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i,s?s}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"volume",&volumeStr); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); - if (pEndpointInfo == NULL) - { - afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType); - return; - } - - if (volumeStr != NULL) { -#ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyEndpointJ = NULL; - err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); - return; - } - - json_object *paramJ= json_object_new_string(volumeStr); - json_object_object_add(pPolicyEndpointJ, "arg_volume", paramJ); - - int policyAllowed = Policy_SetVolume(pPolicyEndpointJ); - if (!policyAllowed) - { - afb_req_fail(req, "Audio policy violation", "Set volume not allowed in current context"); - return; - } -#else - // Simulate that policy returns target state (accepted) - pEndpointInfo->iVolume = atoi(volumeStr); -#endif - } - - json_object * volumeJ = json_object_new_int(pEndpointInfo->iVolume); - - afb_req_success(req, volumeJ, "Set/get volume completed"); -} - -PUBLIC void audiohlapi_get_endpoint_info(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); - if (pEndpointInfo == NULL) - { - afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType); - return; - } - - json_object *endpointInfoJ = NULL; - EndpointInfoToJSON(pEndpointInfo,&endpointInfoJ); - - afb_req_success(req, endpointInfoJ, "Retrieved endpoint information and properties"); -} - -PUBLIC void audiohlapi_property(struct afb_req req) -{ - json_object *queryJ = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - char * pEndpointTypeStr = NULL; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - char * propertyName = NULL; - json_object * propValueJ = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:i,s:s,s?o}", "endpoint_type", &pEndpointTypeStr,"endpoint_id",&endpointID,"property_name",&propertyName,"value",&propValueJ); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - endpointType = EndpointTypeToEnum(pEndpointTypeStr); - - EndpointInfoT * pEndpointInfo = GetEndpointInfo(endpointID,endpointType); - if (pEndpointInfo == NULL) - { - afb_req_fail_f(req, "Endpoint not found", "Endpoint information not found for id:%d type%d",endpointID,endpointType); - return; - } - - if (propValueJ != NULL) { - #ifndef AHL_DISCONNECT_POLICY - json_object *pPolicyEndpointJ = NULL; - err = EndpointInfoToJSON(pEndpointInfo, &pPolicyEndpointJ); - if (err == AHL_POLICY_UTIL_FAIL) - { - afb_req_fail(req, "Audio policy violation", "Unable to get JSON object for Policy_SetVolume"); - return; - } - - json_object *paramJ= json_object_new_string(propertyName); - json_object_object_add(pPolicyEndpointJ, "arg_property_name", paramJ); - json_object_object_add(pPolicyEndpointJ, "arg_property_value", propValueJ); - - // Call policy to allow custom policy actions in current context - int policyAllowed = Policy_SetProperty(pPolicyEndpointJ); - if (!policyAllowed) - { - afb_req_fail(req, "Audio policy violation", "Set endpoint property not allowed in current context"); - return; - } - #else - // Simulate that policy returns target state (accepted) - if (pEndpointInfo->pPropTable) - g_hash_table_insert(pEndpointInfo->pPropTable, propertyName, propValueJ); - #endif - } - - // Retrieve cached property value - json_object * propertyValJ = (json_object *)g_hash_table_lookup(pEndpointInfo->pPropTable,propertyName); - if (propertyValJ == NULL) { - afb_req_fail_f(req, "Property not found", "Property information not found: %s",propertyName); - return; - } - - json_object_get(propertyValJ); // Increase ref count so that framework does not free our JSON object - - afb_req_success(req, propertyValJ, "Set/get property completed"); -} - -PUBLIC void audiohlapi_get_list_actions(struct afb_req req) -{ - json_object *queryJ = NULL; - char * audioRole = NULL; - json_object * roleActionsJ = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s}", "audio_role",&audioRole); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - // Build and return list of actions for specific audio role - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - roleActionsJ = json_object_new_array(); - if (pRole->pActionList) { - int iNumberActions = pRole->pActionList->len; - for ( int i = 0 ; i < iNumberActions; i++) - { - char * pActionName = g_ptr_array_index(pRole->pActionList,i); - json_object * actionJ = json_object_new_string(pActionName); - json_object_array_add(roleActionsJ, actionJ); - } - } - - afb_req_success(req, roleActionsJ, "Retrieved action list for audio role"); -} - -PUBLIC void audiohlapi_post_action(struct afb_req req) -{ - json_object *queryJ = NULL; - char * actionName = NULL; - char * audioRole = NULL; - char * mediaName = NULL; - json_object *actionContext = NULL; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - // Verify if known action for audio role - RoleInfoT * pRole = GetRole(audioRole); - if ( pRole == NULL ) - { - afb_req_fail_f(req, "Invalid audio role", "Audio role was not found in configuration -> %s",audioRole); - return; - } - - // Check to find specific action - int iActionFound = 0; - if (pRole->pActionList) { - int iNumberActions = pRole->pActionList->len; - char * pTargetActionName = NULL; - for ( int i = 0 ; i < iNumberActions; i++) - { - pTargetActionName = g_ptr_array_index(pRole->pActionList,i); - if ( strcasecmp(pTargetActionName,actionName)==0) { - iActionFound = 1; - break; - } - } - } - - if (!iActionFound) { - afb_req_fail_f(req, "Event not found for audio role", "Event -> %s not found for role:%s",actionName,audioRole); - return; - } - -#ifndef AHL_DISCONNECT_POLICY - // Call policy to allow custom policy actions in current context (e.g. cancel playback) - json_object * pActionInfo = NULL; - err = wrap_json_pack(&pActionInfo, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Could not create action JSON object arguments"); - return; - } - json_object_get(pActionInfo); - int policyAllowed = Policy_PostAction(pActionInfo); - if (!policyAllowed) - { - afb_req_fail(req, "Audio policy violation", "Post sound action not allowed in current context"); - return; - } -#endif - - afb_req_success(req, NULL, "Posted sound action"); - } - -PUBLIC void audiohlapi_event_subscription(struct afb_req req) -{ - json_object *queryJ = NULL; - json_object * eventArrayJ = NULL; - int iSubscribe = 1; - - queryJ = afb_req_json(req); - int err = wrap_json_unpack(queryJ, "{s:o,s:i}", "events", &eventArrayJ,"subscribe",&iSubscribe); - if (err) { - afb_req_fail_f(req, "Invalid arguments", "Args not a valid json object query=%s", json_object_get_string(queryJ)); - return; - } - - int iNumEvents = json_object_array_length(eventArrayJ); - for (int i = 0; i < iNumEvents; i++) - { - char * pEventName = NULL; - json_object * jEvent = json_object_array_get_idx(eventArrayJ,i); - pEventName = (char *)json_object_get_string(jEvent); - if(pEventName == NULL) { - afb_req_fail(req, "failed", "Invalid event"); - return; - } - else if(!strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)) { - if (iSubscribe) - afb_req_subscribe(req, g_AHLCtx.policyCtx.propertyEvent); - else - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.propertyEvent); - } - else if(!strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)) { - if (iSubscribe) - afb_req_subscribe(req, g_AHLCtx.policyCtx.volumeEvent); - else - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.volumeEvent); - } - else if(!strcasecmp(pEventName, AHL_POST_ACTION_EVENT)) { - if (iSubscribe) - afb_req_subscribe(req, g_AHLCtx.policyCtx.postActionEvent); - else - afb_req_unsubscribe(req, g_AHLCtx.policyCtx.postActionEvent); - } - else { - afb_req_fail(req, "failed", "Invalid event"); - return; - } - } - - afb_req_success(req, NULL, "Event subscription update finished"); -} - -// Since the policy is currently in the same binding, it cannot raise events on its own -// This is a first step toward isolation, when policy is migrated in its own binding it can simply raise AGL events -// This binding will register for these policy events and will execute the code below upon event reception -PUBLIC void audiohlapi_raise_event(json_object * pEventDataJ) -{ - char * pEventName = NULL; - - int err = wrap_json_unpack(pEventDataJ,"{s:s}","event_name", &pEventName); - if(err) - { - AFB_ERROR("Unable to retrieve event name"); - return; - } - - if(strcasecmp(pEventName, AHL_ENDPOINT_PROPERTY_EVENT)==0) { - char * pAudioRole = NULL; - char * pPropertyName = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - json_object * propValueJ = NULL; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:s,s:o,s:s}", - "endpoint_id", &endpointID, - "endpoint_type", &endpointType, - "property_name", &pPropertyName, - "value",&propValueJ, - "audio_role", &pAudioRole); - if(err) - { - AFB_ERROR("Unable to unpack property event"); - return; - } - RoleInfoT * pRole = GetRole(pAudioRole); - if ( pRole == NULL ){ - AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); - return; - } - EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); - // update property value - if ((pEndpointInfo!=NULL) && (pEndpointInfo->pPropTable!=NULL)) - { - json_type jType = json_object_get_type(propValueJ); - switch (jType) { - case json_type_double: - g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_double(json_object_get_double(propValueJ))); - break; - case json_type_int: - g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_int(json_object_get_int(propValueJ))); - break; - case json_type_string: - g_hash_table_insert(pEndpointInfo->pPropTable, pPropertyName, json_object_new_string(json_object_get_string(propValueJ))); - break; - default: - AFB_ERROR("Invalid property argument Property value not a valid json object query=%s", json_object_get_string(propValueJ)); - return ; - } - } - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - afb_event_push(g_AHLCtx.policyCtx.propertyEvent,pEventDataJ); - } - else if(strcasecmp(pEventName, AHL_ENDPOINT_VOLUME_EVENT)==0) { - char * pAudioRole = NULL; - endpointID_t endpointID = AHL_UNDEFINED; - EndpointTypeT endpointType = ENDPOINTTYPE_MAXVALUE; - int iVolume = 0; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i,s:i,s:s}", - "endpoint_id", &endpointID, - "endpoint_type", &endpointType, - "value",&iVolume, - "audio_role", &pAudioRole); - if(err) - { - AFB_ERROR("Unable to unpack volume event data"); - return; - } - RoleInfoT * pRole = GetRole(pAudioRole); - if ( pRole == NULL ){ - AFB_ERROR("Requested audio role does not exist in current configuration -> %s", pAudioRole); - return; - } - EndpointInfoT * pEndpointInfo = GetEndpointInfoWithRole(endpointID,endpointType,pRole); - // update volume value - if(pEndpointInfo) - { - pEndpointInfo->iVolume = iVolume; - } - else - { - AFB_ERROR("Unable to find endpoint"); - } - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - afb_event_push(g_AHLCtx.policyCtx.volumeEvent,pEventDataJ); - } - else if(strcasecmp(pEventName, AHL_POST_ACTION_EVENT)==0) { - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - // BUG: This crashes... - afb_event_push(g_AHLCtx.policyCtx.postActionEvent,pEventDataJ); - } - else if(strcasecmp(pEventName, AHL_STREAM_STATE_EVENT)==0) { - streamID_t streamID = AHL_UNDEFINED; - StreamEventT streamEvent = STREAM_EVENT_MAXVALUE; - int err = wrap_json_unpack(pEventDataJ,"{s:i,s:i}", - "stream_id", &streamID, - "state_event", &streamEvent); - if(err) - { - AFB_ERROR("Unable to unpack stream event data"); - return; - } - - StreamInfoT * pStreamInfo = GetStream(streamID); - if (pStreamInfo == NULL) { - AFB_ERROR("Specified stream not currently active stream_id -> %d",streamID); - return; - } - - // update streamstate value - switch (streamEvent) { - case STREAM_EVENT_START: - pStreamInfo->streamState = STREAM_STATE_RUNNING; - break; - case STREAM_EVENT_STOP: - pStreamInfo->streamState = STREAM_STATE_IDLE; - break; - case STREAM_EVENT_PAUSE: - pStreamInfo->streamState = STREAM_STATE_PAUSED; - break; - case STREAM_EVENT_RESUME: - pStreamInfo->streamState = STREAM_STATE_RUNNING; - break; - case STREAM_EVENT_MUTED: - pStreamInfo->streamMute = STREAM_MUTED; - break; - case STREAM_EVENT_UNMUTED: - pStreamInfo->streamMute = STREAM_UNMUTED; - break; - default: - AFB_ERROR("Unknown stream event"); - } - - // Remove event name from object - json_object_object_del(pEventDataJ,"event_name"); - afb_event_push(pStreamInfo->streamStateEvent,pEventDataJ); - } - else { - AFB_ERROR("Unknown event name"); - } -}
\ No newline at end of file |