From c68316b787706d49bbddb387af45e25804678ce6 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Mon, 30 Oct 2017 21:18:41 +0100 Subject: Code Reorganisation preparing transfer to gerrit --- ahl-policy/CMakeLists.txt | 40 ++ ahl-policy/ahl-policy.c | 1138 +++++++++++++++++++++++++++++++++++++++++++++ ahl-policy/ahl-policy.h | 45 ++ 3 files changed, 1223 insertions(+) create mode 100644 ahl-policy/CMakeLists.txt create mode 100644 ahl-policy/ahl-policy.c create mode 100644 ahl-policy/ahl-policy.h (limited to 'ahl-policy') diff --git a/ahl-policy/CMakeLists.txt b/ahl-policy/CMakeLists.txt new file mode 100644 index 0000000..aa3ab9c --- /dev/null +++ b/ahl-policy/CMakeLists.txt @@ -0,0 +1,40 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# 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. +########################################################################### + + +# Add target to project dependency list +PROJECT_TARGET_ADD(ahl-policy) + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} STATIC ahl-policy.c) + + # Define target includes + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} + PUBLIC ${GLIB_PKG_INCLUDE_DIRS} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + ahl-utilities + afb-utilities + ) + + # Define target includes for this target client + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ) diff --git a/ahl-policy/ahl-policy.c b/ahl-policy/ahl-policy.c new file mode 100644 index 0000000..5d2e324 --- /dev/null +++ b/ahl-policy/ahl-policy.c @@ -0,0 +1,1138 @@ +/* + * Copyright (C) 2017 "Audiokinetic Inc" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "wrap-json.h" +#include "ahl-policy-utils.h" +#include "ahl-interface.h" +#include "ahl-policy.h" + + +typedef enum SystemState { + SYSTEM_STARTUP = 0, // Startup + SYSTEM_SHUTDOWN, // ShutDown + SYSTEM_NORMAL, // Normal + SYSTEM_LOW_POWER, // Low Power, save mode + SYSTEM_MAXVALUE // Enum count, keep at the end +} SystemStateT; + + +typedef struct HalInfo { + char *pDevID; + char *pAPIName; + char *pDisplayName; +} HalInfoT; + +typedef struct StreamConfig { + int iNbMaxStream; + int iVolumeInit; + int iVolumeDuckValue; +} StreamConfigT; + +// Global Policy Local context +typedef struct PolicyLocalCtx { + GArray * pSourceEndpoints; // List of Source Endpoint with playing stream or interrupted stream + GArray * pSinkEndpoints; // List of Sink Endpoint with playing stream or interrupted stream + GPtrArray * pHALList; + SystemStateT systemState; +} PolicyLocalCtxT; + +#ifndef AHL_DISCONNECT_POLICY + +// Global Context +PolicyLocalCtxT g_PolicyCtx; + + +// Helper Functions +static int getStreamConfig(char *pAudioRole, StreamConfigT *pStreamConfig) +{ + if(pAudioRole == NULL || pStreamConfig==NULL) + { + return POLICY_FAIL; + } + + if ( strcasecmp(pAudioRole,AHL_ROLE_WARNING) == 0 ) + { + pStreamConfig->iNbMaxStream = 4; + pStreamConfig->iVolumeInit = 80; + pStreamConfig->iVolumeDuckValue = 0; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_GUIDANCE) == 0 ) + { + pStreamConfig->iNbMaxStream = 10; + pStreamConfig->iVolumeInit = 70; + pStreamConfig->iVolumeDuckValue = 30; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_NOTIFICATION) == 0 ) + { + pStreamConfig->iNbMaxStream = 4; + pStreamConfig->iVolumeInit = 80; + pStreamConfig->iVolumeDuckValue = 10; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_COMMUNICATION) == 0 ) + { + pStreamConfig->iNbMaxStream = 10; + pStreamConfig->iVolumeInit = 70; + pStreamConfig->iVolumeDuckValue = 10; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_ENTERTAINMENT) == 0 ) + { + pStreamConfig->iNbMaxStream = MAX_ACTIVE_STREAM_POLICY; + pStreamConfig->iVolumeInit = 60; + pStreamConfig->iVolumeDuckValue = 40; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_SYSTEM) == 0 ) + { + pStreamConfig->iNbMaxStream = 2; + pStreamConfig->iVolumeInit = 100; + pStreamConfig->iVolumeDuckValue = 0; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_STARTUP) == 0 ) + { + pStreamConfig->iNbMaxStream = 1; + pStreamConfig->iVolumeInit = 90; + pStreamConfig->iVolumeDuckValue = 0; + } + else if ( strcasecmp(pAudioRole,AHL_ROLE_SHUTDOWN) == 0 ) + { + pStreamConfig->iNbMaxStream = 1; + pStreamConfig->iVolumeInit = 90; + pStreamConfig->iVolumeDuckValue = 0; + } + return POLICY_SUCCESS; +} + +static int PolicySetVolume(int iEndpointID, int iEndpointType, char *pHalApiName, char *AudioRole, DeviceURITypeT deviceType, int iVolume, bool bMute) +{ + if(pHalApiName == NULL) + { + AFB_WARNING("SetVolume cannot be accomplished without proper HAL association"); + return POLICY_FAIL; + } + + if(AudioRole == NULL) + { + AFB_ERROR("Invalid AudioRole : %s",AudioRole); + return POLICY_FAIL; + } + + // Using audio role available from endpoint to target the right HAL control (build string based on convention) + GString * gsHALControlName = NULL; + switch(deviceType) + { + case DEVICEURITYPE_ALSA_HW: + gsHALControlName = g_string_new("Master_Playback_Volume"); + break; + case DEVICEURITYPE_ALSA_DMIX: + case DEVICEURITYPE_ALSA_DSNOOP: + case DEVICEURITYPE_ALSA_PLUG: + case DEVICEURITYPE_ALSA_SOFTVOL: + gsHALControlName = g_string_new(AudioRole); + if(bMute == false) + { + AFB_DEBUG("Using ramp"); + g_string_append(gsHALControlName,"_Ramp"); + } + else + { + AFB_DEBUG("Not using ramp"); + g_string_append(gsHALControlName,"_Vol"); // no ramping + } + break; + default: + //Set volume to zero for display purpose only. + //Not support yet + AFB_WARNING("Device Type %i is not support and can't set volume on HalName %s",deviceType, pHalApiName); + return POLICY_FAIL; + break; + } + + // Set endpoint volume using HAL services (leveraging ramps etc.) + json_object *j_response, *j_query = NULL; + + // Package query + int err = wrap_json_pack(&j_query,"{s:s,s:i}","label",gsHALControlName->str, "val",iVolume); + if (err) + { + AFB_ERROR("Invalid query for HAL ctlset: %s with errorcode: %i",json_object_to_json_string(j_query), err); + return POLICY_FAIL; + } + + //TODO implement Volume limitation based on policy + + // Set the volume using the HAL + err = afb_service_call_sync(pHalApiName, "ctlset", j_query, &j_response); + if (err) + { + AFB_ERROR("Could not ctlset on HAL: %s with errorcode: %i",pHalApiName, err); + return POLICY_FAIL; + } + AFB_DEBUG("HAL ctlset response=%s", json_object_to_json_string(j_response)); + + if (bMute == false) { + // Package event data + json_object * eventDataJ = NULL; + err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i,s:i,s:s}","event_name", AHL_ENDPOINT_VOLUME_EVENT,"endpoint_id", iEndpointID, "endpoint_type", iEndpointType,"value",iVolume, "audio_role", AudioRole); + if (err) + { + AFB_ERROR("Invalid event data for volume event %s with errorcode: %i",json_object_to_json_string(eventDataJ), err); + return POLICY_FAIL; + } + + audiohlapi_raise_event(eventDataJ); + } + + return POLICY_SUCCESS; +} + +static int PolicyGetVolume(int iEndpointID, int iEndpointType, char *pHalApiName, char *AudioRole, DeviceURITypeT deviceType, int *pVolume) +{ + GString * gsHALControlName = NULL; + + // Using audio role available from endpoint to target the right HAL control (build string based on convention) + switch(deviceType) + { + case DEVICEURITYPE_ALSA_HW: + gsHALControlName = g_string_new("Master_Playback_Volume"); + break; + case DEVICEURITYPE_ALSA_DMIX: + case DEVICEURITYPE_ALSA_DSNOOP: + case DEVICEURITYPE_ALSA_PLUG: + case DEVICEURITYPE_ALSA_SOFTVOL: + gsHALControlName = g_string_new(AudioRole); + g_string_append(gsHALControlName,"_Vol"); // Or _Vol for direct control (no ramping) + break; + default: + // Set volume to zero for display purpose only. + // Not supported yet + *pVolume = 0; + AFB_WARNING("Can't get volume on HAL: %s for device type: %d",pHalApiName,deviceType); + return POLICY_FAIL; + } + + // Set endpoint volume using HAL services (leveraging ramps etc.) + json_object *j_response = NULL, *j_query = NULL; + + // Package query + int err = wrap_json_pack(&j_query,"{s:s}","label",gsHALControlName->str); + if (err) + { + AFB_WARNING("Invalid query for HAL ctlset: %s, errorcode: %i",json_object_to_json_string(j_query),err); + return POLICY_FAIL; + } + + //TODO implement Volume limitation based on policy + + // Get the volume using the HAL + err = afb_service_call_sync(pHalApiName, "ctlget", j_query, &j_response); + if (err) + { + AFB_WARNING("Could not ctlset on HAL: %s, errorcode: %i",pHalApiName, err); + return POLICY_FAIL; + } + AFB_DEBUG("HAL ctlget response=%s", json_object_to_json_string(j_response)); + + // Parse response + json_object * jRespObj = NULL; + json_object_object_get_ex(j_response, "response", &jRespObj); + json_object * jVal = NULL; + int val1 = 0, val2 = 0; // Why 2 values? + + json_object_object_get_ex(jRespObj, "val", &jVal); + int nbElement = json_object_array_length(jVal); + if(nbElement == 2) + { + err = wrap_json_unpack(jVal, "[ii]", &val1, &val2); + if (err) { + AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); + return POLICY_FAIL; + } + + } + else + { + err = wrap_json_unpack(jVal, "[i]", &val1); + if (err) { + AFB_ERROR("Volume retrieve failed Could not retrieve volume value -> %s", json_object_get_string(jVal)); + return POLICY_FAIL; + } + + } + + *pVolume = val1; + + // Package event data + json_object * eventDataJ = NULL; + err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i,s:i,s:s}","event_name", AHL_ENDPOINT_VOLUME_EVENT,"endpoint_id", iEndpointID, "endpoint_type", iEndpointType,"value",*pVolume, "audio_role", AudioRole); + if (err) + { + AFB_ERROR("Invalid event data for volume event %s with errorcode: %i",json_object_to_json_string(eventDataJ), err); + return POLICY_FAIL; + } + + audiohlapi_raise_event(eventDataJ); + + return POLICY_SUCCESS; +} + +static void PolicyPostStateEvent(int iStreamID, StreamEventT eventState) +{ + + json_object * eventDataJ = NULL; + int err = wrap_json_pack(&eventDataJ,"{s:s,s:i,s:i}","event_name", AHL_STREAM_STATE_EVENT,"stream_id",iStreamID, "state_event",eventState); + if (err) + { + AFB_ERROR("Invalid event data for stream state event: %s",json_object_to_json_string(eventDataJ)); + } + else + { + audiohlapi_raise_event(eventDataJ); + } +} + +static EndPointPolicyInfoT *PolicySearchEndPoint(EndpointTypeT type, char *pDeviceName) +{ + GArray *pcurEndpointArray = NULL; + + if(type==ENDPOINTTYPE_SINK) + { + pcurEndpointArray = g_PolicyCtx.pSinkEndpoints; + } + else + { + pcurEndpointArray = g_PolicyCtx.pSourceEndpoints; + } + + for(int i=0; ilen; i++) + { + EndPointPolicyInfoT * pCurEndpoint = &g_array_index(pcurEndpointArray,EndPointPolicyInfoT,i); + + if(strcasecmp(pCurEndpoint->pDeviceName,pDeviceName)==0) + { + return pCurEndpoint; + } + } + + return NULL; +} + + +static int PolicyAddEndPoint(StreamInfoT *pStreamInfo) +{ + EndPointPolicyInfoT *pPolicyEndPoint = PolicySearchEndPoint(pStreamInfo->pEndpointInfo->type, pStreamInfo->pEndpointInfo->gsDeviceName); + if(pPolicyEndPoint == NULL) + { + //create EndPoint and add playing stream + EndPointPolicyInfoT newEndPointPolicyInfo; + newEndPointPolicyInfo.endpointID = pStreamInfo->pEndpointInfo->endpointID; + newEndPointPolicyInfo.type = pStreamInfo->pEndpointInfo->type; + newEndPointPolicyInfo.deviceType = pStreamInfo->pEndpointInfo->deviceURIType; + newEndPointPolicyInfo.pDeviceName = strdup(pStreamInfo->pEndpointInfo->gsDeviceName); + newEndPointPolicyInfo.pHalApiName = strdup(pStreamInfo->pEndpointInfo->gsHALAPIName); + newEndPointPolicyInfo.iVolume = pStreamInfo->pEndpointInfo->iVolume; + newEndPointPolicyInfo.streamInfo = g_array_new(FALSE, TRUE, sizeof(StreamPolicyInfoT));; + + if(pStreamInfo->pEndpointInfo->type == ENDPOINTTYPE_SINK) + { + g_array_append_val(g_PolicyCtx.pSinkEndpoints, newEndPointPolicyInfo); + } + else + { + g_array_append_val(g_PolicyCtx.pSourceEndpoints, newEndPointPolicyInfo); + } + + } + return POLICY_SUCCESS; +} + + +static int PolicyAddStream(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInfoT *pStreamInfo) +{ + StreamPolicyInfoT newStreamPolicyInfo; + + newStreamPolicyInfo.streamID = pStreamInfo->streamID; + newStreamPolicyInfo.RolePriority = pStreamInfo->iPriority; + newStreamPolicyInfo.pAudioRole = pStreamInfo->pRoleName; + newStreamPolicyInfo.interruptBehavior = pStreamInfo->eInterruptBehavior; + newStreamPolicyInfo.iDuckVolume = 0; + g_array_append_val(pCurrEndPointPolicy->streamInfo, newStreamPolicyInfo); + return POLICY_SUCCESS; +} + +static int PolicyRunningIdleTransition(EndPointPolicyInfoT *pCurrEndPointPolicy,StreamInfoT * pStreamInfo) +{ + int err=0; + if(pCurrEndPointPolicy == NULL || pCurrEndPointPolicy->streamInfo->len == 0) + { + //Remove endpoint + AFB_ERROR("StreamID not found in active Endpoint when Running to Idle transition is request"); + return POLICY_FAIL; + } + //Search for the matching stream + for(int i=0; istreamInfo->len; i++) + { + StreamPolicyInfoT currentPolicyStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,i); + if(currentPolicyStreamInfo.streamID == pStreamInfo->streamID) + { + //remove the current stream + g_array_remove_index(pCurrEndPointPolicy->streamInfo, i); + if(pCurrEndPointPolicy->streamInfo->len > 0) //need to unduck + { + //check the last element(Akways highest priority) + StreamPolicyInfoT HighPriorityStreamInfo = g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,pCurrEndPointPolicy->streamInfo->len-1); + switch(currentPolicyStreamInfo.interruptBehavior) + { + case INTERRUPTBEHAVIOR_CONTINUE: + //unduck and set Volume back to original value + err= PolicySetVolume(pCurrEndPointPolicy->endpointID, + pCurrEndPointPolicy->type, + pCurrEndPointPolicy->pHalApiName, + HighPriorityStreamInfo.pAudioRole, + pCurrEndPointPolicy->deviceType, + HighPriorityStreamInfo.iDuckVolume, + false); + if(err) + { + return POLICY_FAIL; + } + + return POLICY_SUCCESS; + break; + case INTERRUPTBEHAVIOR_PAUSE: + //pInterruptStreamInfo->streamState = STREAM_STATE_RUNNING; + PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_RESUME); + return POLICY_SUCCESS; + break; + + case INTERRUPTBEHAVIOR_CANCEL: + PolicyPostStateEvent(HighPriorityStreamInfo.streamID,STREAM_EVENT_START); + return POLICY_SUCCESS; + break; + default: + AFB_ERROR("Unsupported Intterupt Behavior"); + return POLICY_FAIL; + break; + } + } + } + } + return POLICY_SUCCESS; +} + +static int PolicyIdleRunningTransition(EndPointPolicyInfoT *pCurrEndPointPolicy, StreamInfoT * pStreamInfo) +{ + int err=0; + if(pCurrEndPointPolicy->streamInfo == NULL) + { + AFB_ERROR("pCurrEndPointPolicy->streamInfo is null on an active endpoint"); + return POLICY_FAIL; + } + + if(pCurrEndPointPolicy->streamInfo->len == 0) //No stream is playing on this endpoint + { + PolicyAddStream(pCurrEndPointPolicy, pStreamInfo); + } + else //Interrupt case + { + //check the last element + StreamPolicyInfoT *pCurrentActiveStreamInfo = &g_array_index(pCurrEndPointPolicy->streamInfo,StreamPolicyInfoT,pCurrEndPointPolicy->streamInfo->len-1); + g_assert_nonnull(pCurrentActiveStreamInfo); + if(pStreamInfo->iPriority >= pCurrentActiveStreamInfo->RolePriority) + { + switch(pStreamInfo->eInterruptBehavior) + { + case INTERRUPTBEHAVIOR_CONTINUE: + //Save the current Volume and set the docking volume + pCurrentActiveStreamInfo->iDuckVolume = pStreamInfo->pEndpointInfo->iVolume; + StreamConfigT StreamConfig; + err = getStreamConfig(pStreamInfo->pRoleName, &StreamConfig); + if(err == POLICY_FAIL) + { + AFB_ERROR("Error getting stream configuration for audiorole: %s", pStreamInfo->pRoleName); + return POLICY_FAIL; + } + err= PolicySetVolume(pCurrEndPointPolicy->endpointID, + pCurrEndPointPolicy->type, + pCurrEndPointPolicy->pHalApiName, + pCurrentActiveStreamInfo->pAudioRole, + pCurrEndPointPolicy->deviceType, + StreamConfig.iVolumeDuckValue, + false); + if(err) + { + AFB_ERROR("Set Volume return with errorcode%i for streamID: %i and Hal:%s", err, pCurrentActiveStreamInfo->streamID, pCurrEndPointPolicy->pHalApiName); + return POLICY_FAIL; + } + break; + case INTERRUPTBEHAVIOR_PAUSE: + PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_PAUSE); + break; + + case INTERRUPTBEHAVIOR_CANCEL: + PolicyPostStateEvent(pCurrentActiveStreamInfo->streamID,STREAM_EVENT_STOP); + g_array_remove_index(pCurrEndPointPolicy->streamInfo, pCurrEndPointPolicy->streamInfo->len-1); + break; + default: + AFB_ERROR("Unsupported Intterupt Behavior"); + return AHL_POLICY_REJECT; + break; + + } + + //Add the playing stream at last + PolicyAddStream(pCurrEndPointPolicy, pStreamInfo); + } + else + { + //Higher Priority Stream is playing + AFB_ERROR("Higher Priority Stream is playing"); + return POLICY_FAIL; + } + + + } + + return POLICY_SUCCESS; +} + +static void PolicySpeedModify(int speed) +{ + + for(int i=0; ilen; i++) + { + EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSinkEndpoints,EndPointPolicyInfoT,i); + if(pCurEndpoint == NULL) + { + AFB_WARNING("Sink Endpoint not found"); + return; + } + + //check if active + if(pCurEndpoint->streamInfo->len > 0 ) + { + StreamPolicyInfoT * pCurStream = &g_array_index(pCurEndpoint->streamInfo,StreamPolicyInfoT,pCurEndpoint->streamInfo->len-1); + if(strcasecmp(pCurStream->pAudioRole,AHL_ROLE_ENTERTAINMENT)==0) + { + if(speed > 30 && speed < 100) + { + int volume =speed; + PolicySetVolume(pCurEndpoint->endpointID, + pCurEndpoint->type, + pCurEndpoint->pHalApiName, + pCurStream->pAudioRole, + pCurEndpoint->deviceType, + volume, + false); + } + } + } + } +} + +static int RetrieveAssociatedHALAPIName(EndpointInfoT * io_pEndpointInfo) +{ + if(g_PolicyCtx.pHALList) + { + for(int i=0; ilen; i++) + { + HalInfoT *pHalInfo = g_ptr_array_index(g_PolicyCtx.pHALList, i); + // Retrieve card number (e.g. hw:0) + int iCardNum = atoi(pHalInfo->pDevID+3); + if (iCardNum == io_pEndpointInfo->alsaInfo.cardNum) { + io_pEndpointInfo->gsHALAPIName=strdup(pHalInfo->pAPIName); + io_pEndpointInfo->gsDisplayName=strdup(pHalInfo->pDisplayName); + return POLICY_SUCCESS; + } + } + } + + io_pEndpointInfo->gsHALAPIName=strdup(AHL_POLICY_UNDEFINED_HALNAME); + io_pEndpointInfo->gsDisplayName=strdup(AHL_POLICY_UNDEFINED_DISPLAYNAME); + + return POLICY_FAIL; +} + +static int GetHALList(void) +{ + json_object *j_response, *j_query = NULL; + int err; + err = afb_service_call_sync("alsacore", "hallist", j_query, &j_response); + if (err) { + AFB_ERROR("Could not retrieve list of HAL from ALSA core"); + return POLICY_FAIL; + } + AFB_DEBUG("ALSAcore hallist response=%s", json_object_to_json_string(j_response)); + + // Look through returned list for matching card + json_object * jRespObj = NULL; + json_object_object_get_ex(j_response, "response", &jRespObj); + int iNumHAL = json_object_array_length(jRespObj); + for ( int i = 0 ; i < iNumHAL; i++) + { + json_object * jHAL = json_object_array_get_idx(jRespObj,i); + char * pDevIDStr = NULL; + char * pAPIName = NULL; + char * pShortName = NULL; + + int err = wrap_json_unpack(jHAL, "{s:s,s:s,s:s}", "devid", &pDevIDStr,"api", &pAPIName,"shortname",&pShortName); + if (err) { + AFB_ERROR("Could not retrieve devid string=%s", json_object_get_string(jHAL)); + return POLICY_FAIL; + } + + HalInfoT *pHalInfo = (HalInfoT*)malloc(sizeof(HalInfoT)); + if(pHalInfo == NULL) + { + AFB_ERROR("Unable to allocate memory for HalInfo"); + return POLICY_FAIL; + } + + pHalInfo->pDevID = strdup(pDevIDStr); + pHalInfo->pAPIName = strdup(pAPIName); + pHalInfo->pDisplayName = strdup(pShortName); + + g_ptr_array_add( g_PolicyCtx.pHALList, pHalInfo); + } + + return POLICY_SUCCESS; +} + +// +// Policy API Functions +// +int Policy_OpenStream(json_object *pPolicyStreamJ) +{ + StreamInfoT PolicyStream; + EndpointInfoT EndpointInfo; + PolicyStream.pEndpointInfo =&EndpointInfo; + + int err = PolicyCtxJSONToStream(pPolicyStreamJ, &PolicyStream); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + // Example rule -> when system is in shutdown or low power mode, no audio stream can be opened (return AHL_POLICY_REJECT) + // Should receive event from lower level layer + if(g_PolicyCtx.systemState != SYSTEM_NORMAL) + { + return AHL_POLICY_REJECT; + } + + StreamConfigT StreamConfig; + err = getStreamConfig(PolicyStream.pRoleName, &StreamConfig); + if(err == POLICY_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + if(PolicyStream.pEndpointInfo->deviceURIType != DEVICEURITYPE_NOT_ALSA) { + err=PolicyGetVolume(PolicyStream.pEndpointInfo->endpointID, + PolicyStream.pEndpointInfo->type, + PolicyStream.pEndpointInfo->gsHALAPIName, + PolicyStream.pEndpointInfo->pRoleName, + PolicyStream.pEndpointInfo->deviceURIType, + &PolicyStream.pEndpointInfo->iVolume); + if(err == POLICY_FAIL) + { + return AHL_POLICY_REJECT; + } + } + + err = PolicyAddEndPoint(&PolicyStream); + if(err == POLICY_FAIL) + { + return AHL_POLICY_REJECT; + } + return AHL_POLICY_ACCEPT; +} + +int Policy_CloseStream(json_object *pPolicyStreamJ) +{ + //TODO remove Endpoint when there is no stream + StreamInfoT PolicyStream; + EndpointInfoT EndpointInfo; + PolicyStream.pEndpointInfo =&EndpointInfo; + int err = PolicyCtxJSONToStream(pPolicyStreamJ, &PolicyStream); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + return AHL_POLICY_ACCEPT; +} + +int Policy_SetStreamState(json_object *pPolicyStreamJ) +{ + //TODO + // Optional: Mute endpoint before activation, unmute afterwards (after a delay?) to avoid noises + StreamInfoT PolicyStream; + EndpointInfoT EndpointInfo; + PolicyStream.pEndpointInfo =&EndpointInfo; + + + StreamStateT streamState = 0; + StreamInfoT * pPolicyStream = &PolicyStream; + int err = PolicyCtxJSONToStream(pPolicyStreamJ, pPolicyStream); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + json_object *streamStateJ=NULL; + + if(!json_object_object_get_ex(pPolicyStreamJ, "arg_stream_state", &streamStateJ)) + { + return AHL_POLICY_ACCEPT; + } + streamState = (StreamStateT)json_object_get_int(streamStateJ); + + //Change of state + if(pPolicyStream->streamState != streamState) + { + //seach corresponding endpoint and gather information on it + EndPointPolicyInfoT *pCurrEndPointPolicy = PolicySearchEndPoint(pPolicyStream->pEndpointInfo->type , pPolicyStream->pEndpointInfo->gsDeviceName); + + switch(pPolicyStream->streamState) + { + case STREAM_STATE_IDLE: + switch(streamState) + { + case STREAM_STATE_RUNNING: + err = PolicyIdleRunningTransition(pCurrEndPointPolicy, pPolicyStream); + if(err) + { + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_START); + break; + case STREAM_STATE_PAUSED: + err = PolicyIdleRunningTransition(pCurrEndPointPolicy, pPolicyStream); + if(err) + { + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_PAUSE); + break; + default: + return AHL_POLICY_REJECT; + break; + } + break; + case STREAM_STATE_RUNNING: + switch(streamState) + { + case STREAM_STATE_IDLE: + err = PolicyRunningIdleTransition(pCurrEndPointPolicy, pPolicyStream); + if(err) + { + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_STOP); + break; + case STREAM_STATE_PAUSED: + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_PAUSE); + break; + default: + return AHL_POLICY_REJECT; + break; + } + break; + case STREAM_STATE_PAUSED: + switch(streamState) + { + case STREAM_STATE_IDLE: + err = PolicyRunningIdleTransition(pCurrEndPointPolicy, pPolicyStream); + if(err) + { + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_STOP); + break; + case STREAM_STATE_RUNNING: + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_RESUME); + break; + default: + return AHL_POLICY_REJECT; + break; + } + break; + default: + return AHL_POLICY_REJECT; + break; + } + } + return AHL_POLICY_ACCEPT; +} + +int Policy_SetStreamMute(json_object *pPolicyStreamJ) +{ + StreamMuteT streamMute = 0; + StreamInfoT PolicyStream; + EndpointInfoT EndpointInfo; + PolicyStream.pEndpointInfo =&EndpointInfo; + StreamInfoT * pPolicyStream = &PolicyStream; + + int err = PolicyCtxJSONToStream(pPolicyStreamJ, pPolicyStream); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + json_object *streamMuteJ=NULL; + + if(!json_object_object_get_ex(pPolicyStreamJ, "mute_state", &streamMuteJ)) + { + return AHL_POLICY_ACCEPT; + } + streamMute = (StreamMuteT)json_object_get_int(streamMuteJ); + + if(streamMute != pPolicyStream->streamMute) + { + if(streamMute == STREAM_MUTED) + { + + err= PolicySetVolume(pPolicyStream->pEndpointInfo->endpointID, + pPolicyStream->pEndpointInfo->type, + pPolicyStream->pEndpointInfo->gsHALAPIName, + pPolicyStream->pRoleName, + pPolicyStream->pEndpointInfo->deviceURIType, + 0, + true); + if(err) + { + AFB_ERROR("StreamID:%i Set Volume return with errorcode%i",pPolicyStream->streamID, err); + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_MUTED); + } + else + { + err= PolicySetVolume(pPolicyStream->pEndpointInfo->endpointID, + pPolicyStream->pEndpointInfo->type, + pPolicyStream->pEndpointInfo->gsHALAPIName, + pPolicyStream->pRoleName, + pPolicyStream->pEndpointInfo->deviceURIType, + pPolicyStream->pEndpointInfo->iVolume, + true); + if(err) + { + AFB_ERROR("Endpoint:%i Set Volume return with errorcode%i",pPolicyStream->streamID, err); + return AHL_POLICY_REJECT; + } + PolicyPostStateEvent(pPolicyStream->streamID,STREAM_EVENT_UNMUTED); + + } + + pPolicyStream->streamMute = streamMute; + } + + return AHL_POLICY_ACCEPT; +} + +int Policy_SetVolume(json_object *pPolicyEndpointJ) +{ + char *volumeStr = NULL; + EndpointInfoT EndpointInfo; + + int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + json_object *volumeJ=NULL; + + if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_volume", &volumeJ)) + { + return AHL_POLICY_ACCEPT; + } + volumeStr = (char*)json_object_get_string(volumeJ); + + // TODO: Parse volume string to support increment/absolute/percent notation (or delegate to action / policy layer to interpret) + int vol = atoi(volumeStr); + + //Set the volume + err= PolicySetVolume(EndpointInfo.endpointID, + EndpointInfo.type, + EndpointInfo.gsHALAPIName, + EndpointInfo.pRoleName, + EndpointInfo.deviceURIType, + vol, + false); + if (err) + { + AFB_ERROR("Set Volume return with errorcode%i", err); + return AHL_POLICY_REJECT; + } + + return AHL_POLICY_ACCEPT; +} + +int Policy_SetProperty(json_object *pPolicyEndpointJ) +{ + + char *propertyName = NULL; + EndpointInfoT EndpointInfo; + + int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_ACCEPT; + } + + json_object *propertyNameJ=NULL; + + if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_property_name", &propertyNameJ)) + { + return AHL_POLICY_ACCEPT; + } + propertyName = (char*)json_object_get_string(propertyNameJ); + + json_object *propValueJ; + if(!json_object_object_get_ex(pPolicyEndpointJ, "arg_property_value", &propValueJ)) + { + return AHL_POLICY_ACCEPT; + } + + gpointer *key_value=NULL; + + key_value = g_hash_table_lookup(EndpointInfo.pPropTable,propertyName); + if(key_value == NULL) + { + AFB_ERROR("Can't find property %s, request will be rejected", propertyName); + return AHL_POLICY_REJECT; + } + + //Get JsonObjectype + json_type currentjType = json_object_get_type((json_object*)key_value); + json_type newjType = json_object_get_type(propValueJ); + + //Apply policy on set property if needed here + //Here we only validate that the type is the same + if(currentjType != newjType) + { + AFB_ERROR("Property Value Type is wrong"); + return AHL_POLICY_REJECT; + } + + + //Create a new Json Object + json_object *pEventDataJ = NULL; + err = wrap_json_pack(&pEventDataJ,"{s:s,s:i,s:i,s:s,s:o,s:s}", + "event_name", AHL_ENDPOINT_PROPERTY_EVENT, + "endpoint_id", EndpointInfo.endpointID, + "endpoint_type", EndpointInfo.type, + "property_name", propertyName, + "value",propValueJ, + "audio_role", EndpointInfo.pRoleName); + if(err) + { + AFB_ERROR("Unable to pack property event"); + return AHL_POLICY_REJECT; + } + //Raise Event to update HLB + audiohlapi_raise_event(pEventDataJ); + + return AHL_POLICY_ACCEPT; +} + +int Policy_PostAction(json_object *pPolicyActionJ) +{ + char * actionName = NULL; + char * audioRole = NULL; + char * mediaName = NULL; + json_object *actionContext = NULL; + + int err = wrap_json_unpack(pPolicyActionJ, "{s:s,s:s,s?s,s?o}", "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); + if (err) { + AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); + return AHL_POLICY_REJECT; + } + + // TODO: Any event with media specified should trigger action on provided rendering services (e.g. Wwise binding, gstreamer file player wrapper, MPDC? simple ALSA player (aplay)?) + // Example (when the policy is hooked to CAN events). Post audio playback events other than safety during reverse gear engaged declined + // Example post HMI audio role playback events declined when higher priority streams are active + + //In this use case just return the action back to highlevel binding. + + json_object *pEventDataJ = NULL; + err = wrap_json_pack(&pEventDataJ, "{s:s,s:s,s:s,s?s,s?o}", "event_name", AHL_POST_ACTION_EVENT, "action_name", &actionName,"audio_role",&audioRole,"media_name",&mediaName,"action_context",&actionContext); + if (err) { + AFB_ERROR("Unable to pack JSON endpoint, =%s", wrap_json_get_error_string(err)); + return AHL_POLICY_REJECT; + } + audiohlapi_raise_event(pEventDataJ); + + return AHL_POLICY_ACCEPT; +} + +int Policy_Endpoint_Init(json_object *pPolicyEndpointJ) +{ + EndpointInfoT EndpointInfo; + + int err = PolicyCtxJSONToEndpoint(pPolicyEndpointJ, &EndpointInfo); + if(err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_REJECT; + } + + if (EndpointInfo.deviceURIType != DEVICEURITYPE_NOT_ALSA) { + // Update Hal Name + err = RetrieveAssociatedHALAPIName(&EndpointInfo); + if (err) { + AFB_ERROR("HAL not found for Device %s", EndpointInfo.gsDeviceName); + return AHL_POLICY_REJECT; + } + + //Set Init Volume + StreamConfigT StreamConfig; + getStreamConfig(EndpointInfo.pRoleName, &StreamConfig); + err = PolicySetVolume(EndpointInfo.endpointID, + EndpointInfo.type, + EndpointInfo.gsHALAPIName, + EndpointInfo.pRoleName, + EndpointInfo.deviceURIType, + StreamConfig.iVolumeInit, + false); + if(err) { + return AHL_POLICY_REJECT; + } + } + + // Test example + Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_LOW,3); + Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_MID,0); + Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_EQ_HIGH,6); + Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_BALANCE,0); + Add_Endpoint_Property_Int(&EndpointInfo,AHL_PROPERTY_FADE,30); + Add_Endpoint_Property_String(&EndpointInfo,"preset_name","flat"); + + + gpointer *key_value = g_hash_table_lookup(EndpointInfo.pPropTable,AHL_PROPERTY_BALANCE); + if(key_value == NULL) + { + AFB_ERROR("Can't find property %s, request will be rejected", AHL_PROPERTY_BALANCE); + return AHL_POLICY_REJECT; + } + + //Create a new Json Object + json_object *pNewPolicyEndpointJ = NULL; + err = PolicyEndpointStructToJSON(&EndpointInfo, &pNewPolicyEndpointJ); + if (err == AHL_POLICY_UTIL_FAIL) + { + return AHL_POLICY_REJECT; + } + json_object *paramJ= json_object_new_string(AHL_ENDPOINT_INIT_EVENT); + json_object_object_add(pNewPolicyEndpointJ, "event_name", paramJ); + + //Raise Event to update HLB + audiohlapi_raise_event(pNewPolicyEndpointJ); + + return AHL_POLICY_ACCEPT; // No errors +} + +int Policy_Init() +{ + // Initialize Ressources + g_PolicyCtx.pSourceEndpoints =g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); + g_PolicyCtx.pSinkEndpoints = g_array_new(FALSE,TRUE,sizeof(EndPointPolicyInfoT)); + g_PolicyCtx.pHALList = g_ptr_array_new_with_free_func(g_free); + + //Get HalList + GetHALList(); + + //Set System Normal for now, this should be set by an event + //TODO: Receive event from low level + g_PolicyCtx.systemState = SYSTEM_NORMAL; + + //register audio backend events + //This is to simulate can bus, only used for demo + json_object *queryurl, *responseJ, *eventsJ; + + eventsJ = json_object_new_array(); + json_object_array_add(eventsJ, json_object_new_string("audiod_system_event")); + queryurl = json_object_new_object(); + json_object_object_add(queryurl, "events", eventsJ); + int returnResult = afb_service_call_sync("audiod", "subscribe", queryurl, &responseJ); + if (returnResult) { + AFB_ERROR("Fail subscribing to Audio Backend System events"); + return AHL_POLICY_REJECT; + } + return AHL_POLICY_ACCEPT; +} + +void Policy_Term() +{ + //Free Ressources + if (g_PolicyCtx.pHALList) { + g_ptr_array_free(g_PolicyCtx.pHALList,TRUE); + g_PolicyCtx.pHALList = NULL; + } + + for(int i=0; ilen; i++) + { + EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSourceEndpoints,EndPointPolicyInfoT,i); + g_array_free(pCurEndpoint->streamInfo,TRUE); + pCurEndpoint->streamInfo= NULL; + } + + for(int i=0; ilen; i++) + { + EndPointPolicyInfoT * pCurEndpoint = &g_array_index(g_PolicyCtx.pSinkEndpoints,EndPointPolicyInfoT,i); + g_array_free(pCurEndpoint->streamInfo,TRUE); + pCurEndpoint->streamInfo = NULL; + } + + g_array_free(g_PolicyCtx.pSourceEndpoints,TRUE); + g_PolicyCtx.pSourceEndpoints = NULL; + g_array_free(g_PolicyCtx.pSinkEndpoints,TRUE); + g_PolicyCtx.pSinkEndpoints = NULL; +} + +void Policy_OnEvent(const char *evtname, json_object *eventJ) +{ + AFB_DEBUG("Policy received event %s", evtname); + char *eventName = NULL; + json_object *event_parameter = NULL; + int speed = 0; + + if(strcasecmp(evtname, "audiod/system_events")==0) + { + int err = wrap_json_unpack(eventJ, "{s:s,s:o}", "event_name", &eventName, "event_parameter", &event_parameter); + if (err) { + AFB_WARNING("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(eventJ)); + return; + } + + if(strcasecmp(eventName, "speed")==0) + { + AFB_NOTICE("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(event_parameter)); + err = wrap_json_unpack(event_parameter, "{s:i}", "speed_value", &speed); + if (err) { + AFB_WARNING("Invalid arguments, Args not a valid json object query=%s", json_object_get_string(event_parameter)); + return; + } + //When speed change Modify volume on Endpoint where entertainment change + PolicySpeedModify(speed); + } + } +} + +#endif // AHL_DISCONNECT_POLICY \ No newline at end of file diff --git a/ahl-policy/ahl-policy.h b/ahl-policy/ahl-policy.h new file mode 100644 index 0000000..942055a --- /dev/null +++ b/ahl-policy/ahl-policy.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 "Audiokinetic Inc" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AHL_POLICY_INCLUDE +#define AHL_POLICY_INCLUDE +#include "ahl-policy-utils.h" + +#ifndef AHL_DISCONNECT_POLICY + +#define MAX_ACTIVE_STREAM_POLICY 30 +#define POLICY_FAIL 1 +#define POLICY_SUCCESS 0 + +#define AHL_POLICY_UNDEFINED_HALNAME "UNDEFINED" +#define AHL_POLICY_UNDEFINED_DISPLAYNAME "DeviceNotFound" + + +int Policy_Endpoint_Init(json_object *pPolicyEndpointJ); +int Policy_OpenStream(json_object *pPolicyStreamJ); +int Policy_CloseStream(json_object *pPolicyStreamJ); +int Policy_SetStreamState(json_object *pPolicyStreamJ); +int Policy_SetStreamMute(json_object *pPolicyStreamJ); +int Policy_PostAction(json_object *pPolicyActionJ); +int Policy_SetVolume(json_object *pPolicyEndpointJ); +int Policy_SetProperty(json_object *pPolicyEndpointJ); +int Policy_Init(); +void Policy_Term(); +void Policy_OnEvent(const char *evtname, json_object *eventJ); + +extern void audiohlapi_raise_event(json_object * pEventDataJ); +#endif // AHL_DISCONNECT_POLICY +#endif // AHL_POLICY_INCLUDE \ No newline at end of file -- cgit 1.2.3-korg From ab6e470190f2cc410b1f6fa8f146317a3c3b08b5 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 1 Nov 2017 22:18:54 +0100 Subject: Integration with AlsaHookPlugin (work in progress) --- ahl-binding/ahl-config.c | 59 ++++++++-- ahl-policy/ahl-interface.h | 99 ++++++++++++++++ ahl-utilities/ahl-interface.h | 99 ---------------- conf.d/cmake/config.cmake | 4 +- conf.d/project/.asoundrc | 164 -------------------------- conf.d/project/.asoundrc-audiok | 164 ++++++++++++++++++++++++++ conf.d/project/.asounrc-fulup | 198 ++++++++++++++++++++++++++++++++ conf.d/project/README.md | 15 +++ conf.d/project/agl-ahl-config.json | 128 --------------------- conf.d/project/ahl-audiok4a-config.json | 128 +++++++++++++++++++++ conf.d/project/ahl-fulup4a-config.json | 39 +++++++ nbproject/configurations.xml | 3 - nbproject/project.xml | 2 +- 13 files changed, 698 insertions(+), 404 deletions(-) create mode 100644 ahl-policy/ahl-interface.h delete mode 100644 ahl-utilities/ahl-interface.h delete mode 100644 conf.d/project/.asoundrc create mode 100644 conf.d/project/.asoundrc-audiok create mode 100644 conf.d/project/.asounrc-fulup create mode 100644 conf.d/project/README.md delete mode 100644 conf.d/project/agl-ahl-config.json create mode 100644 conf.d/project/ahl-audiok4a-config.json create mode 100644 conf.d/project/ahl-fulup4a-config.json (limited to 'ahl-policy') diff --git a/ahl-binding/ahl-config.c b/ahl-binding/ahl-config.c index 5e3de08..2a61b5e 100644 --- a/ahl-binding/ahl-config.c +++ b/ahl-binding/ahl-config.c @@ -19,6 +19,7 @@ #include #include #include "wrap-json.h" +#include "filescan-utils.h" #include "ahl-binding.h" @@ -40,21 +41,63 @@ static InterruptBehaviorT InterruptBehaviorToEnum(char * in_pInterruptBehaviorSt return INTERRUPTBEHAVIOR_MAXVALUE; } +static json_object* CtlConfigScan(const char *dirList, const char *prefix) { + char controlFile [CONTROL_MAXPATH_LEN]; + strncpy(controlFile, prefix, CONTROL_MAXPATH_LEN); + strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); + + // search for default dispatch config file + json_object* responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, controlFile, ".json"); + + return responseJ; +} + +static char* CtlConfigSearch(const char *dirList, const char *prefix) { + int index, err; + + // search for default dispatch config file + json_object* responseJ = CtlConfigScan (dirList, prefix); + if (!responseJ) return NULL; + + // We load 1st file others are just warnings + for (index = 0; index < json_object_array_length(responseJ); index++) { + json_object *entryJ = json_object_array_get_idx(responseJ, index); + + char *filename; + char*fullpath; + err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); + if (err) { + AFB_ERROR("CTL-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); + return NULL; + } + + if (index == 0) { + char filepath[CONTROL_MAXPATH_LEN]; + strncpy(filepath, fullpath, sizeof (filepath)); + strncat(filepath, "/", sizeof (filepath)); + strncat(filepath, filename, sizeof (filepath)); + return (strdup(filepath)); + } + } + // no config found + return NULL; +} + int ParseHLBConfig() { char * versionStr = NULL; json_object * jAudioRoles = NULL; json_object * jHALList = NULL; char * policyModule = NULL; - // TODO: This should be retrieve from binding startup arguments - char configfile_path[256]; - if(getenv("AHL_CONFIG_FILE") == NULL) - { - AFB_ERROR("Please Set Environnement Variable AHL_CONFIG_FILE"); - return 1; - } + const char *dirList=getenv("AAAA_CONFIG_PATH"); + if (!dirList) dirList=CONTROL_CONFIG_PATH; - sprintf(configfile_path, "%s", getenv("AHL_CONFIG_FILE")); + const char *configfile_path =CtlConfigSearch(dirList, "ahl-"); + if (!configfile_path) { + AFB_ERROR("Error: No control-* config found invalid JSON %s ", dirList); + return 1; + } + AFB_INFO("High-level config file -> %s\n", configfile_path); // Open configuration file diff --git a/ahl-policy/ahl-interface.h b/ahl-policy/ahl-interface.h new file mode 100644 index 0000000..0488e96 --- /dev/null +++ b/ahl-policy/ahl-interface.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 "Audiokinetic Inc" + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AHL_INTERFACE_INCLUDE +#define AHL_INTERFACE_INCLUDE + +///// API ///// + +// Endpoint types +#define AHL_ENDPOINTTYPE_SOURCE "source" // source devices +#define AHL_ENDPOINTTYPE_SINK "sink" // sink devices + +// Stream state +#define AHL_STREAM_STATE_IDLE "idle" // Stream is inactive +#define AHL_STREAM_STATE_RUNNING "running" // Stream is active and running +#define AHL_STREAM_STATE_PAUSED "paused" // Stream is active but paused + +// Stream mute state +#define AHL_STREAM_UNMUTED "off" // Stream is not muted +#define AHL_STREAM_MUTED "on" // Stream is muted + +// Property/Volume/Action events +#define AHL_ENDPOINT_PROPERTY_EVENT "ahl_endpoint_property_event" +#define AHL_ENDPOINT_VOLUME_EVENT "ahl_endpoint_volume_event" +#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event" +#define AHL_POST_ACTION_EVENT "ahl_post_action" +#define AHL_STREAM_STATE_EVENT "ahl_stream_state_event" +#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event" + + +// Stream state event types +#define AHL_STREAM_EVENT_START "start" // Stream is inactive +#define AHL_STREAM_EVENT_STOP "stop" // Stream is running +#define AHL_STREAM_EVENT_PAUSE "pause" // Audio stream paused +#define AHL_STREAM_EVENT_RESUME "resume" // Audio stream resumed +#define AHL_STREAM_EVENT_MUTE "mute" // Audio stream muted +#define AHL_STREAM_EVENT_UNMUTE "unmute" // Audio stream unmuted + +///// Interpret returned or configuration information ///// + +// Known audio domain string definitions (for configuration file format and device URI interpretation) +#define AHL_DOMAIN_ALSA "alsa" +#define AHL_DOMAIN_PULSE "pulse" +#define AHL_DOMAIN_GSTREAMER "gstreamer" +#define AHL_DOMAIN_EXTERNAL "external" + +// ALSA Device URI type +#define AHL_DEVICEURITYPE_ALSA_HW "hw" // Alsa hardware device URI +#define AHL_DEVICEURITYPE_ALSA_DMIX "dmix" // Alsa Dmix device URI (only for playback devices) +#define AHL_DEVICEURITYPE_ALSA_DSNOOP "dsnoop" // Alsa DSnoop device URI (only for capture devices) +#define AHL_DEVICEURITYPE_ALSA_SOFTVOL "softvol" // Alsa softvol device URI +#define AHL_DEVICEURITYPE_ALSA_PLUG "plug" // Alsa plug device URI +#define AHL_DEVICEURITYPE_ALSA_OTHER "other" // Alsa domain URI device of unspecified type +#define AHL_DEVICEURITYPE_NOT_ALSA "nonalsa" + +// Define default behavior of audio role when interrupting lower priority sources (in configuration) +#define AHL_INTERRUPTBEHAVIOR_CONTINUE "continue" // Continue to play when interrupted (e.g. media may be ducked) +#define AHL_INTERRUPTBEHAVIOR_CANCEL "cancel" // Abort playback when interrupted (e.g. non-important HMI feedback that does not make sense later) +#define AHL_INTERRUPTBEHAVIOR_PAUSE "pause" // Pause source when interrupted, to be resumed afterwards (e.g. non-temporal guidance) + +///// Naming convention ///// + +// Standardized name for common audio roles (not enforced in any way, just helps compatibility) +#define AHL_ROLE_WARNING "warning" // Safety-relevant or critical alerts/alarms +#define AHL_ROLE_GUIDANCE "guidance" // Important user information where user action is expected (e.g. navigation instruction) +#define AHL_ROLE_NOTIFICATION "notification" // HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...) +#define AHL_ROLE_COMMUNICATION "communication" // Voice communications (e.g. handsfree, speech recognition) +#define AHL_ROLE_ENTERTAINMENT "entertainment" // Multimedia content (e.g. tuner, media player, etc.) +#define AHL_ROLE_SYSTEM "system" // System level content or development +#define AHL_ROLE_STARTUP "startup" // Early (startup) sound +#define AHL_ROLE_SHUTDOWN "shutdown" // Late (shutdown) sound +#define AHL_ROLE_NONE "none" // Non-assigned / legacy applications + +// Standardized list of properties (not enforced in any way, just helps compatibility) +#define AHL_PROPERTY_BALANCE "balance" +#define AHL_PROPERTY_FADE "fade" +#define AHL_PROPERTY_EQ_LOW "eq_bass" +#define AHL_PROPERTY_EQ_MID "eq_mid" +#define AHL_PROPERTY_EQ_HIGH "eq_treble" + +// Standardized list of events (not enforced in any way, just helps compatibility) +#define AHL_EVENTS_PLAYSOUND "play_sound" +#define AHL_EVENTS_ECHOCANCEL_ENABLE "echocancel_enable" +#define AHL_EVENTS_ECHOCANCEL_DISABLE "echocancel_disable" + +#endif // AHL_INTERFACE_INCLUDE diff --git a/ahl-utilities/ahl-interface.h b/ahl-utilities/ahl-interface.h deleted file mode 100644 index 0488e96..0000000 --- a/ahl-utilities/ahl-interface.h +++ /dev/null @@ -1,99 +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. - */ - -#ifndef AHL_INTERFACE_INCLUDE -#define AHL_INTERFACE_INCLUDE - -///// API ///// - -// Endpoint types -#define AHL_ENDPOINTTYPE_SOURCE "source" // source devices -#define AHL_ENDPOINTTYPE_SINK "sink" // sink devices - -// Stream state -#define AHL_STREAM_STATE_IDLE "idle" // Stream is inactive -#define AHL_STREAM_STATE_RUNNING "running" // Stream is active and running -#define AHL_STREAM_STATE_PAUSED "paused" // Stream is active but paused - -// Stream mute state -#define AHL_STREAM_UNMUTED "off" // Stream is not muted -#define AHL_STREAM_MUTED "on" // Stream is muted - -// Property/Volume/Action events -#define AHL_ENDPOINT_PROPERTY_EVENT "ahl_endpoint_property_event" -#define AHL_ENDPOINT_VOLUME_EVENT "ahl_endpoint_volume_event" -#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event" -#define AHL_POST_ACTION_EVENT "ahl_post_action" -#define AHL_STREAM_STATE_EVENT "ahl_stream_state_event" -#define AHL_ENDPOINT_INIT_EVENT "ahl_endpoint_init_event" - - -// Stream state event types -#define AHL_STREAM_EVENT_START "start" // Stream is inactive -#define AHL_STREAM_EVENT_STOP "stop" // Stream is running -#define AHL_STREAM_EVENT_PAUSE "pause" // Audio stream paused -#define AHL_STREAM_EVENT_RESUME "resume" // Audio stream resumed -#define AHL_STREAM_EVENT_MUTE "mute" // Audio stream muted -#define AHL_STREAM_EVENT_UNMUTE "unmute" // Audio stream unmuted - -///// Interpret returned or configuration information ///// - -// Known audio domain string definitions (for configuration file format and device URI interpretation) -#define AHL_DOMAIN_ALSA "alsa" -#define AHL_DOMAIN_PULSE "pulse" -#define AHL_DOMAIN_GSTREAMER "gstreamer" -#define AHL_DOMAIN_EXTERNAL "external" - -// ALSA Device URI type -#define AHL_DEVICEURITYPE_ALSA_HW "hw" // Alsa hardware device URI -#define AHL_DEVICEURITYPE_ALSA_DMIX "dmix" // Alsa Dmix device URI (only for playback devices) -#define AHL_DEVICEURITYPE_ALSA_DSNOOP "dsnoop" // Alsa DSnoop device URI (only for capture devices) -#define AHL_DEVICEURITYPE_ALSA_SOFTVOL "softvol" // Alsa softvol device URI -#define AHL_DEVICEURITYPE_ALSA_PLUG "plug" // Alsa plug device URI -#define AHL_DEVICEURITYPE_ALSA_OTHER "other" // Alsa domain URI device of unspecified type -#define AHL_DEVICEURITYPE_NOT_ALSA "nonalsa" - -// Define default behavior of audio role when interrupting lower priority sources (in configuration) -#define AHL_INTERRUPTBEHAVIOR_CONTINUE "continue" // Continue to play when interrupted (e.g. media may be ducked) -#define AHL_INTERRUPTBEHAVIOR_CANCEL "cancel" // Abort playback when interrupted (e.g. non-important HMI feedback that does not make sense later) -#define AHL_INTERRUPTBEHAVIOR_PAUSE "pause" // Pause source when interrupted, to be resumed afterwards (e.g. non-temporal guidance) - -///// Naming convention ///// - -// Standardized name for common audio roles (not enforced in any way, just helps compatibility) -#define AHL_ROLE_WARNING "warning" // Safety-relevant or critical alerts/alarms -#define AHL_ROLE_GUIDANCE "guidance" // Important user information where user action is expected (e.g. navigation instruction) -#define AHL_ROLE_NOTIFICATION "notification" // HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...) -#define AHL_ROLE_COMMUNICATION "communication" // Voice communications (e.g. handsfree, speech recognition) -#define AHL_ROLE_ENTERTAINMENT "entertainment" // Multimedia content (e.g. tuner, media player, etc.) -#define AHL_ROLE_SYSTEM "system" // System level content or development -#define AHL_ROLE_STARTUP "startup" // Early (startup) sound -#define AHL_ROLE_SHUTDOWN "shutdown" // Late (shutdown) sound -#define AHL_ROLE_NONE "none" // Non-assigned / legacy applications - -// Standardized list of properties (not enforced in any way, just helps compatibility) -#define AHL_PROPERTY_BALANCE "balance" -#define AHL_PROPERTY_FADE "fade" -#define AHL_PROPERTY_EQ_LOW "eq_bass" -#define AHL_PROPERTY_EQ_MID "eq_mid" -#define AHL_PROPERTY_EQ_HIGH "eq_treble" - -// Standardized list of events (not enforced in any way, just helps compatibility) -#define AHL_EVENTS_PLAYSOUND "play_sound" -#define AHL_EVENTS_ECHOCANCEL_ENABLE "echocancel_enable" -#define AHL_EVENTS_ECHOCANCEL_DISABLE "echocancel_disable" - -#endif // AHL_INTERFACE_INCLUDE diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index ba56110..ff824cf 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -54,6 +54,7 @@ set(CONTROL_SUPPORT_LUA 1 CACHE BOOL "Active or not LUA Support") # PKG_CONFIG required packages # ----------------------------- set (PKG_REQUIRED_LIST + glib-2.0 alsa>=1.1.2 libsystemd>=222 libmicrohttpd>=0.9.55 @@ -86,6 +87,7 @@ set(COMPILE_OPTIONS -DMAX_LINEAR_DB_SCALE=24 # until 24db volume normalisation use a simple linear scale -DTLV_BYTE_SIZE=256 # Alsa use 4096 as default but 256 should fit most sndcards -DCONTROL_MAXPATH_LEN=255 +-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}" CACHE STRING "Compilation flags") #set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.") #set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.") @@ -100,7 +102,7 @@ if(IS_DIRECTORY $ENV{HOME}/opt/afb-monitoring) set(MONITORING_ALIAS "--alias=/monitoring:$ENV{HOME}/opt/afb-monitoring") endif() -set(CLOSING_MESSAGE "Debug: afb-daemon --name=afb-aaaa --port=1234 --ws-server=unix:/var/tmp/ahl-4a --cntxtimeout=1 ${MONITORING_ALIAS} --ldpaths=package/lib:../../alsa-4a/build/package/lib:../../hal-sample-4a/build/package/lib --workdir=. --roothttp=../htdocs --token= --verbose ") +set(CLOSING_MESSAGE "Debug: afb-daemon --name=afb-audiok4a --port=1234 --ws-server=unix:/var/tmp/ahl-4a --cntxtimeout=1 ${MONITORING_ALIAS} --binding=package/lib/afb-audiohighlevel.so --ldpaths=../../alsa-4a/build/package/lib:../../hal-sample-4a/build/package/lib --workdir=. --roothttp=../htdocs --token= --verbose ") # Optional location for config.xml.in diff --git a/conf.d/project/.asoundrc b/conf.d/project/.asoundrc deleted file mode 100644 index cba88e5..0000000 --- a/conf.d/project/.asoundrc +++ /dev/null @@ -1,164 +0,0 @@ - - -##### AGL Conf ##### -pcm.SoftMixer { - type dmix - ipc_key 1024 - ipc_key_add_uid false - ipc_perm 0666 # mixing for all users - - # Define target effective sound card (cannot be a plugin) - slave { - pcm "hw:0" # Main sound card - # periods 8 - period_size 1024 - buffer_size 4096 - } - - # DMIX can only map two channels - bindings { - 0 0 - 1 1 - } -} - -pcm.SoftMixer_DriverHR { - type dmix - ipc_key 1024 - ipc_key_add_uid false - ipc_perm 0666 # mixing for all users - - # Define target effective sound card (cannot be a plugin) - slave { - pcm "hw:1" # Alternate sound card / dummy - # periods 8 - period_size 1024 - buffer_size 4096 - } - - # DMIX can only map two channels - bindings { - 0 0 - 1 1 - } -} - -pcm.SoftMixer_RSE { - type dmix - ipc_key 1024 - ipc_key_add_uid false - ipc_perm 0666 # mixing for all users - - # Define target effective sound card (cannot be a plugin) - slave { - pcm "hw:2" # Alternate sound card / dummy - # periods 8 - period_size 1024 - buffer_size 4096 - } - - # DMIX can only map two channels - bindings { - 0 0 - 1 1 - } -} - -pcm.Entertainment_Main { - type softvol - slave.pcm "SoftMixer" - control{ - name "Entertainment_Vol" - card 0 - } -} - -pcm.Guidance_Main { - type softvol - slave.pcm "SoftMixer" - control{ - name "Guidance_Vol" - card 0 - } -} - -pcm.Communications_Main { - type softvol - slave.pcm "SoftMixer" - control{ - name "Communications_Vol" - card 0 - } -} - -pcm.Notification_Main { - type softvol - slave.pcm "SoftMixer" - control{ - name "Notification_Vol" - card 0 - } -} - -pcm.Warning_Main { - type softvol - slave.pcm "SoftMixer" - control{ - name "Warning_Vol" - card 0 - } -} - -pcm.Entertainment_DriverHR { - type softvol - slave.pcm "SoftMixer_DriverHR" - control{ - name "Entertainment_Vol" - card 1 - } -} - -pcm.Guidance_DriverHR { - type softvol - slave.pcm "SoftMixer_DriverHR" - control{ - name "Guidance_Vol" - card 1 - } -} - -pcm.Communications_DriverHR { - type softvol - slave.pcm "SoftMixer_DriverHR" - control{ - name "Communications_Vol" - card 1 - } -} - -pcm.Notification_DriverHR { - type softvol - slave.pcm "SoftMixer_DriverHR" - control{ - name "Notification_Vol" - card 1 - } -} - -pcm.Warning_DriverHR { - type softvol - slave.pcm "SoftMixer_DriverHR" - control{ - name "Warning_Vol" - card 1 - } -} - -pcm.Entertainment_RSE { - type softvol - slave.pcm "SoftMixer_RSE" - control{ - name "Entertainment_Vol" - card 2 - } -} diff --git a/conf.d/project/.asoundrc-audiok b/conf.d/project/.asoundrc-audiok new file mode 100644 index 0000000..cba88e5 --- /dev/null +++ b/conf.d/project/.asoundrc-audiok @@ -0,0 +1,164 @@ + + +##### AGL Conf ##### +pcm.SoftMixer { + type dmix + ipc_key 1024 + ipc_key_add_uid false + ipc_perm 0666 # mixing for all users + + # Define target effective sound card (cannot be a plugin) + slave { + pcm "hw:0" # Main sound card + # periods 8 + period_size 1024 + buffer_size 4096 + } + + # DMIX can only map two channels + bindings { + 0 0 + 1 1 + } +} + +pcm.SoftMixer_DriverHR { + type dmix + ipc_key 1024 + ipc_key_add_uid false + ipc_perm 0666 # mixing for all users + + # Define target effective sound card (cannot be a plugin) + slave { + pcm "hw:1" # Alternate sound card / dummy + # periods 8 + period_size 1024 + buffer_size 4096 + } + + # DMIX can only map two channels + bindings { + 0 0 + 1 1 + } +} + +pcm.SoftMixer_RSE { + type dmix + ipc_key 1024 + ipc_key_add_uid false + ipc_perm 0666 # mixing for all users + + # Define target effective sound card (cannot be a plugin) + slave { + pcm "hw:2" # Alternate sound card / dummy + # periods 8 + period_size 1024 + buffer_size 4096 + } + + # DMIX can only map two channels + bindings { + 0 0 + 1 1 + } +} + +pcm.Entertainment_Main { + type softvol + slave.pcm "SoftMixer" + control{ + name "Entertainment_Vol" + card 0 + } +} + +pcm.Guidance_Main { + type softvol + slave.pcm "SoftMixer" + control{ + name "Guidance_Vol" + card 0 + } +} + +pcm.Communications_Main { + type softvol + slave.pcm "SoftMixer" + control{ + name "Communications_Vol" + card 0 + } +} + +pcm.Notification_Main { + type softvol + slave.pcm "SoftMixer" + control{ + name "Notification_Vol" + card 0 + } +} + +pcm.Warning_Main { + type softvol + slave.pcm "SoftMixer" + control{ + name "Warning_Vol" + card 0 + } +} + +pcm.Entertainment_DriverHR { + type softvol + slave.pcm "SoftMixer_DriverHR" + control{ + name "Entertainment_Vol" + card 1 + } +} + +pcm.Guidance_DriverHR { + type softvol + slave.pcm "SoftMixer_DriverHR" + control{ + name "Guidance_Vol" + card 1 + } +} + +pcm.Communications_DriverHR { + type softvol + slave.pcm "SoftMixer_DriverHR" + control{ + name "Communications_Vol" + card 1 + } +} + +pcm.Notification_DriverHR { + type softvol + slave.pcm "SoftMixer_DriverHR" + control{ + name "Notification_Vol" + card 1 + } +} + +pcm.Warning_DriverHR { + type softvol + slave.pcm "SoftMixer_DriverHR" + control{ + name "Warning_Vol" + card 1 + } +} + +pcm.Entertainment_RSE { + type softvol + slave.pcm "SoftMixer_RSE" + control{ + name "Entertainment_Vol" + card 2 + } +} diff --git a/conf.d/project/.asounrc-fulup b/conf.d/project/.asounrc-fulup new file mode 100644 index 0000000..c98d5a8 --- /dev/null +++ b/conf.d/project/.asounrc-fulup @@ -0,0 +1,198 @@ +# +# Author: Fulup Ar Foll +# Object: PCM hook type +# +# Test : Note: Jabra_USB=hw:v1340 +# Check SoundCard ==> speaker-test -Dhw:v1340 -c2 -twav +# Check MixerPCM ==> speaker-test -DSpeakers -c2 -twav +# Check SoftVol ==> speaker-test -DMusicPCM -c2 -twav +# Check Plugin ==> speaker-test -DMultimedia -c2 -twav +# Check Plugin ==> speaker-test -DNavigation -c2 -twav +# +# MultiMedia aplay -DDMyNavPCM /usr/share/sounds/alsa/test.wav +# +# Bug/Feature: when softvol control is initialised from plugin and not +# from AGL binding. At 1st run ctl has invalid TLV and cannot be +# use. Bypass Solution: +# * start audio-binder before playing sound (binding create control before softvol plugin) +# * run a dummy aplay -DMyNavPCM "" to get a clean control +# +# References: https://www.spinics.net/lists/alsa-devel/msg54235.html +# -------------------------------------------------------------------- + +# ------------------------------------------------------ +# Mixer PCM allow to play multiple stream simultaneously +# ------------------------------------------------------ +pcm.Speakers { + type dmix + slave {pcm "hw:v1340"} #Jabra Solmate 1 + ipc_key 1001 # ipc_key should be unique to each dmix +} + +# ----------------------------------------------------- +# Register ControllerHookPlugin (ToiBeFix fullpath) +# ----------------------------------------------------- +pcm_hook_type.CtlHookPlugin { + install "AlsaInstallHook" + lib "/home/fulup/Workspace/Audio-4a/alsa-4a/build/alsa-hook/policy_alsa_hook.so" +} + + +# ------------------------------------------------------- +# Define one Audio Virtual Channel per Audio Roles +# ------------------------------------------------------- +pcm.MusicPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "Speakers" + + # name should match with HAL definition + control.name "Playback Multimedia" +} + +pcm.NaviPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "Speakers" + + # name should match with HAL definition + control.name "Playback Navigation" +} + +pcm.UrgentPCM { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "Speakers" + + # name should match with HAL definition + control.name "Playback Emergency" +} + +# ---------------------------------------------------- +# Define one hooked PCM channel per Audio Roles +# ---------------------------------------------------- +pcm.Multimedia { + type hooks + slave {pcm "MusicPCM"} + hooks.0 { + comment "Defined used hook sharelib and provide arguments/config to install func" + type "CtlHookPlugin" + hook_args { + + # print few log messages (default false) + verbose true + + # uri to audio-4a policy engine + uri="unix:/var/tmp/ahl-4a" + + # timeout in ms (default 500) + timeout 5000 + + # force API synchronous mode + synchronous true + + # api subcall to request a role + request { + stream_open "{'audio_role':'Entertainment', 'endpoint_type': 'sink'}" + set_stream_state "{'state': 'running'}" + } + + # api subcall to request a role + release { + stream_close "{}" + } + + # map AGL event on Unix signal. Search in event for json key=value + events { + sig-02 {search music, value quit} + sig-31 {search event, value start} + sig-32 {search event, value start} + } + } + } +} + +pcm.Navigation { + type hooks + slave {pcm "NaviPCM"} + hooks.0 { + comment "Defined used hook sharelib and provide arguments/config to install func" + type "CtlHookPlugin" + hook_args { + + # print few log messages (default false) + verbose true + + # uri to audio-4a policy engine + uri="unix:/var/tmp/ahl-4a" + + # timeout in ms (default 500) + timeout 5000 + + # force API synchronous mode + synchronous true + + # api subcall to request a role + request { + stream_open "{'audio_role':'Guidance', 'endpoint_type': 'sink'}" + set_stream_state "{'state': 'running'}" + } + + # api subcall to request a role + release { + release-role "{'uid':'alsa-hook-client'}" + } + + # map AGL event on Unix signal. Search in event for json key=value + events { + sig-02 {search navi, value quit} + sig-31 {search event, value start} + sig-32 {search event, value start} + } + } + } +} + +pcm.Emergency { + type hooks + slave {pcm "UrgentPCM"} + hooks.0 { + comment "Defined used hook sharelib and provide arguments/config to install func" + type "CtlHookPlugin" + hook_args { + + # print few log messages (default false) + verbose true + + # uri to audio-4a policy engine + uri="unix:/var/tmp/ahl-4a" + + # timeout in ms (default 500) + timeout 5000 + + # force API synchronous mode + synchronous true + + # api subcall to request a role + request { + stream_open "{'audio_role':'Emergency', 'endpoint_type': 'sink'}" + set_stream_state "{'state': 'running'}" + } + + # api subcall to request a role + release { + release-role "{'uid':'alsa-hook-client'}" + } + + # map AGL event on Unix signal. Search in event for json key=value + events { + sig-02 {search navi, value quit} + sig-31 {search event, value start} + sig-32 {search event, value start} + } + } + } +} diff --git a/conf.d/project/README.md b/conf.d/project/README.md new file mode 100644 index 0000000..00e3c2f --- /dev/null +++ b/conf.d/project/README.md @@ -0,0 +1,15 @@ + +1) $HOME/.asoundrc or /etc/asound.conf should match you hardware audio configuration. +2) ahl-xxxxxx-config.json should match your .asoundrc config + +Note: config file is search within with following rules: + - default search path is $PROJECT_ROOT/conf.d/project:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME} + - if environment variable "AAAA_CONFIG_PATH" is defined that it is used as search path + - config file should match "ahl-BINDERNAME-config.json" where BINDERNAME is provided through "--name=BINDERNAME" in afb-daemon commande line. + +Note: you may debug Audio-4A from your development tree with: + + afb-daemon --name=afb-audio4a --port=1234 --ws-server=unix:/var/tmp/ahl-4a --cntxtimeout=1 \ + --alias=/monitoring:/home/fulup/opt/afb-monitoring --binding=package/lib/afb-audiohighlevel.so \ + --ldpaths=../../alsa-4a/build/package/lib:../../hal-sample-4a/build/package/lib --workdir=. \ + --roothttp=../htdocs --token= --verbose --verbose \ No newline at end of file diff --git a/conf.d/project/agl-ahl-config.json b/conf.d/project/agl-ahl-config.json deleted file mode 100644 index f49c0be..0000000 --- a/conf.d/project/agl-ahl-config.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "version": "0.2.0", - "policy_module": "AudioPolicy_v1", - "description": "High-level binding configuration file", - "note": "Devices and routings are always listed in order of priority (for device selection rules)", - "hal_list": ["ensoniq","usbaudio"], - "audio_roles": [ - { - "name": "Warning", - "id": 0, - "description": "Safety-relevant or critical alerts/alarms", - "priority": 100, - "output": [ - "alsa.plug:Warning_Main", - "alsa.plug:Warning_DriverHR" - ], - "actions": [ - "emergency_brake", - "collision_warning", - "blind_spot_warning" - ], - "interupt_behavior": "pause" - }, - { - "name": "Guidance", - "id": 1, - "description": "Important user information where user action is expected (e.g. navigation instruction)", - "priority": 25, - "output": [ - "alsa.plug:Guidance_Main", - "alsa.plug:Guidance_DriverHR" - ], - "actions": [ - "lane_guidance_left", - "lane_guidance_right", - "destination_reached" - ], - "interupt_behavior": "continue" - }, - { - "name": "Notification", - "id": 2, - "description": "HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...)", - "priority": 0, - "output": [ - "alsa.plug:Notification_Main", - "alsa.plug:Notification_DriverHR" - ], - "actions": [ - "home", - "context_switch", - "accept", - "cancel", - "selection_change" - ], - "interupt_behavior": "cancel" - }, - { - "name": "Communication", - "id": 3, - "description": "Voice communications (e.g. handsfree, speech recognition)", - "priority": 50, - "output": [ - "alsa.plug:Communications_Main", - "alsa.plug:Communications_DriverHR", - ], - "input": [ - "alsa.hw:0", - ], - "actions": [ - "bt_device_connected", - "bt_device_disconnected", - "sms_received" - ], - "interupt_behavior": "continue" - }, - { - "name": "Entertainment", - "id": 4, - "description": "Multimedia content (e.g. tuner, media player, etc.)", - "priority": 0, - "output": [ - "alsa.plug:Entertainment_Main", - "alsa.plug:Entertainment_DriverHR", - ], - "interupt_behavior": "pause" - }, - { - "name": "System", - "id": 5, - "description": "System level content or development", - "priority": 100, - "output": [ - "alsa.hw:0" - ], - "input": [ - "alsa.hw:0" - ], - "interupt_behavior": "continue" - }, - { - "name": "Startup", - "id": 6, - "description": "Early (startup) sound", - "priority": 100, - "output": [ - "alsa.hw:0" - ], - "actions": [ - "welcome_sound" - ], - "interupt_behavior": "pause" - }, - { - "name": "Shutdown", - "id": 7, - "description": "Late (shutdown) sound", - "priority": 100, - "output": [ - "alsa.hw:0" - ], - "actions": [ - "goodbye_sound" - ], - "interupt_behavior": "cancel" - } - ] -} diff --git a/conf.d/project/ahl-audiok4a-config.json b/conf.d/project/ahl-audiok4a-config.json new file mode 100644 index 0000000..f49c0be --- /dev/null +++ b/conf.d/project/ahl-audiok4a-config.json @@ -0,0 +1,128 @@ +{ + "version": "0.2.0", + "policy_module": "AudioPolicy_v1", + "description": "High-level binding configuration file", + "note": "Devices and routings are always listed in order of priority (for device selection rules)", + "hal_list": ["ensoniq","usbaudio"], + "audio_roles": [ + { + "name": "Warning", + "id": 0, + "description": "Safety-relevant or critical alerts/alarms", + "priority": 100, + "output": [ + "alsa.plug:Warning_Main", + "alsa.plug:Warning_DriverHR" + ], + "actions": [ + "emergency_brake", + "collision_warning", + "blind_spot_warning" + ], + "interupt_behavior": "pause" + }, + { + "name": "Guidance", + "id": 1, + "description": "Important user information where user action is expected (e.g. navigation instruction)", + "priority": 25, + "output": [ + "alsa.plug:Guidance_Main", + "alsa.plug:Guidance_DriverHR" + ], + "actions": [ + "lane_guidance_left", + "lane_guidance_right", + "destination_reached" + ], + "interupt_behavior": "continue" + }, + { + "name": "Notification", + "id": 2, + "description": "HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...)", + "priority": 0, + "output": [ + "alsa.plug:Notification_Main", + "alsa.plug:Notification_DriverHR" + ], + "actions": [ + "home", + "context_switch", + "accept", + "cancel", + "selection_change" + ], + "interupt_behavior": "cancel" + }, + { + "name": "Communication", + "id": 3, + "description": "Voice communications (e.g. handsfree, speech recognition)", + "priority": 50, + "output": [ + "alsa.plug:Communications_Main", + "alsa.plug:Communications_DriverHR", + ], + "input": [ + "alsa.hw:0", + ], + "actions": [ + "bt_device_connected", + "bt_device_disconnected", + "sms_received" + ], + "interupt_behavior": "continue" + }, + { + "name": "Entertainment", + "id": 4, + "description": "Multimedia content (e.g. tuner, media player, etc.)", + "priority": 0, + "output": [ + "alsa.plug:Entertainment_Main", + "alsa.plug:Entertainment_DriverHR", + ], + "interupt_behavior": "pause" + }, + { + "name": "System", + "id": 5, + "description": "System level content or development", + "priority": 100, + "output": [ + "alsa.hw:0" + ], + "input": [ + "alsa.hw:0" + ], + "interupt_behavior": "continue" + }, + { + "name": "Startup", + "id": 6, + "description": "Early (startup) sound", + "priority": 100, + "output": [ + "alsa.hw:0" + ], + "actions": [ + "welcome_sound" + ], + "interupt_behavior": "pause" + }, + { + "name": "Shutdown", + "id": 7, + "description": "Late (shutdown) sound", + "priority": 100, + "output": [ + "alsa.hw:0" + ], + "actions": [ + "goodbye_sound" + ], + "interupt_behavior": "cancel" + } + ] +} diff --git a/conf.d/project/ahl-fulup4a-config.json b/conf.d/project/ahl-fulup4a-config.json new file mode 100644 index 0000000..1a851a5 --- /dev/null +++ b/conf.d/project/ahl-fulup4a-config.json @@ -0,0 +1,39 @@ +{ + "version": "0.2.0", + "policy_module": "AudioPolicy_v1", + "description": "High-level binding configuration file", + "note": "Devices and routings are always listed in order of priority (for device selection rules)", + "hal_list": ["jabra-usb"], + "audio_roles": [ + { + "name": "Guidance", + "id": 1, + "description": "Important user information where user action is expected (e.g. navigation instruction)", + "priority": 25, + "output": [ + "alsa.plug:NaviPCM" + ], + "interupt_behavior": "continue" + }, + { + "name": "Emergency", + "id": 2, + "description": "HMI or else notifications (e.g. touchscreen events, speech recognition on/off,...)", + "priority": 100, + "output": [ + "alsa.plug:UrgentPCM" + ], + "interupt_behavior": "pause" + }, + { + "name": "Entertainment", + "id": 3, + "description": "Multimedia content (e.g. tuner, media player, etc.)", + "priority": 0, + "output": [ + "alsa.plug:MusicPCM" + ], + "interupt_behavior": "pause" + } + ] +} diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 8ebd7d3..93a17f5 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -12,7 +12,6 @@ ahl-deviceenum.c - ahl-interface.h ahl-policy-utils.c ahl-policy-utils.h @@ -87,8 +86,6 @@ - - diff --git a/nbproject/project.xml b/nbproject/project.xml index 72c2a3b..3e0cffd 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -6,7 +6,7 @@ afb-audiohighlevel c cpp,cxx - h + h,hpp UTF-8 -- cgit 1.2.3-korg