From 735e7a39cc509f74f85c48b6a3db50e08c377752 Mon Sep 17 00:00:00 2001 From: Jonathan Aillet Date: Fri, 19 Apr 2019 10:24:11 +0200 Subject: Reorganize repository directories Reorganize repository directories to clarify code use. BUG-AGL: SPEC-2329 Change-Id: Ia9be0c1818cb2e331e75b51a87fcb2820407c1d8 Signed-off-by: Jonathan Aillet --- 4a-hal-utilities/4a-hal-utilities-alsa-data.c | 51 -- 4a-hal-utilities/4a-hal-utilities-alsa-data.h | 74 -- 4a-hal-utilities/4a-hal-utilities-data.c | 344 --------- 4a-hal-utilities/4a-hal-utilities-data.h | 116 --- .../4a-hal-utilities-hal-streams-handler.c | 355 --------- .../4a-hal-utilities-hal-streams-handler.h | 51 -- 4a-hal-utilities/4a-hal-utilities-verbs-loader.c | 50 -- 4a-hal-utilities/4a-hal-utilities-verbs-loader.h | 28 - 4a-hal-utilities/CMakeLists.txt | 33 - 4a-hal/4a-hal-manager/4a-hal-manager-cb.c | 273 ------- 4a-hal/4a-hal-manager/4a-hal-manager-cb.h | 36 - 4a-hal/4a-hal-manager/4a-hal-manager.c | 168 ----- 4a-hal/4a-hal-manager/4a-hal-manager.h | 29 - .../4a-internals-hal-alsacore-link.c | 633 ----------------- .../4a-internals-hal-alsacore-link.h | 53 -- .../4a-internals-hal/4a-internals-hal-api-loader.c | 243 ------- .../4a-internals-hal/4a-internals-hal-api-loader.h | 31 - 4a-hal/4a-internals-hal/4a-internals-hal-cb.c | 790 --------------------- 4a-hal/4a-internals-hal/4a-internals-hal-cb.h | 45 -- .../4a-internals-hal/4a-internals-hal-mixer-link.c | 389 ---------- .../4a-internals-hal/4a-internals-hal-mixer-link.h | 70 -- .../4a-internals-hal-value-handler.c | 354 --------- .../4a-internals-hal-value-handler.h | 53 -- 4a-hal/CMakeLists.txt | 51 -- lib/4a-hal-utilities/4a-hal-utilities-alsa-data.c | 51 ++ lib/4a-hal-utilities/4a-hal-utilities-alsa-data.h | 74 ++ lib/4a-hal-utilities/4a-hal-utilities-data.c | 344 +++++++++ lib/4a-hal-utilities/4a-hal-utilities-data.h | 116 +++ .../4a-hal-utilities-hal-streams-handler.c | 355 +++++++++ .../4a-hal-utilities-hal-streams-handler.h | 51 ++ .../4a-hal-utilities-verbs-loader.c | 50 ++ .../4a-hal-utilities-verbs-loader.h | 28 + lib/4a-hal-utilities/CMakeLists.txt | 33 + lib/CMakeLists.txt | 22 + plugins/lib/bluealsa/CMakeLists.txt | 2 +- src/4a-hal-manager/4a-hal-manager-cb.c | 273 +++++++ src/4a-hal-manager/4a-hal-manager-cb.h | 36 + src/4a-hal-manager/4a-hal-manager.c | 168 +++++ src/4a-hal-manager/4a-hal-manager.h | 29 + .../4a-internals-hal-alsacore-link.c | 633 +++++++++++++++++ .../4a-internals-hal-alsacore-link.h | 53 ++ src/4a-internals-hal/4a-internals-hal-api-loader.c | 243 +++++++ src/4a-internals-hal/4a-internals-hal-api-loader.h | 31 + src/4a-internals-hal/4a-internals-hal-cb.c | 790 +++++++++++++++++++++ src/4a-internals-hal/4a-internals-hal-cb.h | 45 ++ src/4a-internals-hal/4a-internals-hal-mixer-link.c | 389 ++++++++++ src/4a-internals-hal/4a-internals-hal-mixer-link.h | 70 ++ .../4a-internals-hal-value-handler.c | 354 +++++++++ .../4a-internals-hal-value-handler.h | 53 ++ src/CMakeLists.txt | 51 ++ 50 files changed, 4343 insertions(+), 4321 deletions(-) delete mode 100644 4a-hal-utilities/4a-hal-utilities-alsa-data.c delete mode 100644 4a-hal-utilities/4a-hal-utilities-alsa-data.h delete mode 100644 4a-hal-utilities/4a-hal-utilities-data.c delete mode 100644 4a-hal-utilities/4a-hal-utilities-data.h delete mode 100644 4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c delete mode 100644 4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h delete mode 100644 4a-hal-utilities/4a-hal-utilities-verbs-loader.c delete mode 100644 4a-hal-utilities/4a-hal-utilities-verbs-loader.h delete mode 100644 4a-hal-utilities/CMakeLists.txt delete mode 100644 4a-hal/4a-hal-manager/4a-hal-manager-cb.c delete mode 100644 4a-hal/4a-hal-manager/4a-hal-manager-cb.h delete mode 100644 4a-hal/4a-hal-manager/4a-hal-manager.c delete mode 100644 4a-hal/4a-hal-manager/4a-hal-manager.h delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.c delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.h delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-api-loader.h delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-cb.c delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-cb.h delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.h delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c delete mode 100644 4a-hal/4a-internals-hal/4a-internals-hal-value-handler.h delete mode 100644 4a-hal/CMakeLists.txt create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-alsa-data.c create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-alsa-data.h create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-data.c create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-data.h create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.c create mode 100644 lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.h create mode 100644 lib/4a-hal-utilities/CMakeLists.txt create mode 100644 lib/CMakeLists.txt create mode 100644 src/4a-hal-manager/4a-hal-manager-cb.c create mode 100644 src/4a-hal-manager/4a-hal-manager-cb.h create mode 100644 src/4a-hal-manager/4a-hal-manager.c create mode 100644 src/4a-hal-manager/4a-hal-manager.h create mode 100644 src/4a-internals-hal/4a-internals-hal-alsacore-link.c create mode 100644 src/4a-internals-hal/4a-internals-hal-alsacore-link.h create mode 100644 src/4a-internals-hal/4a-internals-hal-api-loader.c create mode 100644 src/4a-internals-hal/4a-internals-hal-api-loader.h create mode 100644 src/4a-internals-hal/4a-internals-hal-cb.c create mode 100644 src/4a-internals-hal/4a-internals-hal-cb.h create mode 100644 src/4a-internals-hal/4a-internals-hal-mixer-link.c create mode 100644 src/4a-internals-hal/4a-internals-hal-mixer-link.h create mode 100644 src/4a-internals-hal/4a-internals-hal-value-handler.c create mode 100644 src/4a-internals-hal/4a-internals-hal-value-handler.h create mode 100644 src/CMakeLists.txt diff --git a/4a-hal-utilities/4a-hal-utilities-alsa-data.c b/4a-hal-utilities/4a-hal-utilities-alsa-data.c deleted file mode 100644 index 6409253..0000000 --- a/4a-hal-utilities/4a-hal-utilities-alsa-data.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2019 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 "4a-hal-utilities-alsa-data.h" - -/******************************************************************************* - * Free contents of 'InternalHalAlsaMapT' data structure * - ******************************************************************************/ - -uint8_t HalUtlFreeAlsaCtlsMap(struct InternalHalAlsaMapT *alsaCtlsMap) -{ - int idx; - - if(! alsaCtlsMap) - return -1; - - if(alsaCtlsMap->ctlsCount > 0 && ! alsaCtlsMap->ctls) - return -2; - - for(idx = 0; idx < alsaCtlsMap->ctlsCount; idx++) { - free(alsaCtlsMap->ctls[idx].action); - free(alsaCtlsMap->ctls[idx].ctl.alsaCtlProperties.enums); - free(alsaCtlsMap->ctls[idx].ctl.alsaCtlProperties.dbscale); - } - - free(alsaCtlsMap->ctls); - - free(alsaCtlsMap); - - return 0; -} \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-alsa-data.h b/4a-hal-utilities/4a-hal-utilities-alsa-data.h deleted file mode 100644 index fe70210..0000000 --- a/4a-hal-utilities/4a-hal-utilities-alsa-data.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -* Copyright (C) 2019 "IoT.bzh" -* Author Jonathan Aillet -* -* 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 _HAL_UTILITIES_ALSA_DATA_INCLUDE_ -#define _HAL_UTILITIES_ALSA_DATA_INCLUDE_ - -#include - -#include - -#include - -#include - -#include - -struct InternalHalAlsaDBScale { - int min; - int max; - int step; - int mute; -}; - -struct InternalHalAlsaCtlProperties { - snd_ctl_elem_type_t type; - int count; - int minval; - int maxval; - int step; - // TBD JAI : use them - const char **enums; - struct InternalHalAlsaDBScale *dbscale; -}; - -struct InternalHalAlsaCtl { - char *name; - int numid; - int value; - struct InternalHalAlsaCtlProperties alsaCtlProperties; - struct InternalHalAlsaCtlProperties *alsaCtlCreation; -}; - -struct InternalHalAlsaMap { - const char *uid; - char *info; - afb_event_t alsaControlEvent; - struct InternalHalAlsaCtl ctl; - json_object *actionJ; - CtlActionT *action; -}; - -struct InternalHalAlsaMapT { - struct InternalHalAlsaMap *ctls; - unsigned int ctlsCount; -}; - -// Free contents of 'CtlHalAlsaMapT' data structure -uint8_t HalUtlFreeAlsaCtlsMap(struct InternalHalAlsaMapT *alsaCtlsMap); - -#endif /* _HAL_UTILITIES_ALSA_DATA_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-data.c b/4a-hal-utilities/4a-hal-utilities-data.c deleted file mode 100644 index 314190f..0000000 --- a/4a-hal-utilities/4a-hal-utilities-data.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include "4a-hal-utilities-data.h" -#include "4a-hal-utilities-alsa-data.h" - -/******************************************************************************* - * Internal Hal - Streams data handling functions * - ******************************************************************************/ - -struct InternalHalMixerData *HalUtlAddMixerDataToMixerDataList(struct InternalHalMixerData **mixerDataList) -{ - struct InternalHalMixerData *currentMixerData; - - if(! mixerDataList) - return NULL; - - currentMixerData = *mixerDataList; - if(! currentMixerData) { - currentMixerData = (struct InternalHalMixerData *) calloc(1, sizeof(struct InternalHalMixerData)); - if(! currentMixerData) - return NULL; - - *mixerDataList = currentMixerData; - } - else { - while(currentMixerData->next) - currentMixerData = currentMixerData->next; - - currentMixerData->next = calloc(1, sizeof(struct InternalHalMixerData)); - if(! currentMixerData->next) - return NULL; - - currentMixerData = currentMixerData->next; - } - - return currentMixerData; -} - -int8_t HalUtlRemoveSelectedMixerData(struct InternalHalMixerData **mixerDataList, struct InternalHalMixerData *mixerDataToRemove) -{ - struct InternalHalMixerData *currentMixerData, *matchingMixerData; - - if(! mixerDataList || ! *mixerDataList || ! mixerDataToRemove) - return -1; - - currentMixerData = *mixerDataList; - if(currentMixerData == mixerDataToRemove) { - *mixerDataList = currentMixerData->next; - matchingMixerData = currentMixerData; - } - else { - while(currentMixerData && currentMixerData->next != mixerDataToRemove) - currentMixerData = currentMixerData->next; - - if(currentMixerData) { - matchingMixerData = currentMixerData->next; - currentMixerData->next = currentMixerData->next->next; - } - else { - return -2; - } - } - - free(matchingMixerData->verb); - free(matchingMixerData->verbToCall); - free(matchingMixerData->streamCardId); - - free(matchingMixerData); - - return 0; -} - -int64_t HalUtlRemoveAllMixerData(struct InternalHalMixerData **mixerDataList) -{ - int8_t ret; - int64_t mixerDataRemoved = 0; - - if(! mixerDataList) - return -1; - - while(*mixerDataList) { - ret = HalUtlRemoveSelectedMixerData(mixerDataList, *mixerDataList); - if(ret) - return (int64_t) ret; - - mixerDataRemoved++; - } - - return mixerDataRemoved; -} - -int64_t HalUtlGetNumberOfMixerDataInList(struct InternalHalMixerData **mixerDataList) -{ - int64_t numberOfMixerData = 0; - struct InternalHalMixerData *currentMixerData; - - if(! mixerDataList) - return -1; - - currentMixerData = *mixerDataList; - while(currentMixerData) { - currentMixerData = currentMixerData->next; - numberOfMixerData++; - } - - return numberOfMixerData; -} - -struct InternalHalMixerData *HalUtlSearchMixerDataByProperties(struct InternalHalMixerData **mixerDataList, char *verb, char *verbToCall, char *streamCardId) -{ - struct InternalHalMixerData *currentMixerData; - - if(! mixerDataList || ! verb) - return NULL; - - currentMixerData = *mixerDataList; - - while(currentMixerData) { - if((! strcmp(verb, currentMixerData->verb)) && - (! strcmp(verbToCall, currentMixerData->verbToCall)) && - (! strcmp(streamCardId, currentMixerData->streamCardId))) - return currentMixerData; - - currentMixerData = currentMixerData->next; - } - - return NULL; -} - -/******************************************************************************* - * Hal data handling functions * - ******************************************************************************/ - -struct HalData *HalUtlAddHalToHalList(struct HalData **halDataList) -{ - struct HalData *currentHalData; - - if(! halDataList) - return NULL; - - currentHalData = *halDataList; - if(! currentHalData) { - currentHalData = (struct HalData *) calloc(1, sizeof(struct HalData)); - if(! currentHalData) - return NULL; - - *halDataList = currentHalData; - } - else { - while(currentHalData->next) - currentHalData = currentHalData->next; - - currentHalData->next = calloc(1, sizeof(struct HalData)); - if(! currentHalData->next) - return NULL; - - currentHalData = currentHalData->next; - } - - return currentHalData; -} - -int8_t HalUtlRemoveSelectedHalFromList(struct HalData **halDataList, struct HalData *halToRemove) -{ - struct HalData *currentHalData, *matchingHal; - - if(! halDataList || ! *halDataList || ! halToRemove) - return -1; - - currentHalData = *halDataList; - if(currentHalData == halToRemove) { - *halDataList = currentHalData->next; - matchingHal = currentHalData; - } - else { - while(currentHalData && currentHalData->next != halToRemove) - currentHalData = currentHalData->next; - - if(currentHalData) { - matchingHal = currentHalData->next; - currentHalData->next = currentHalData->next->next; - } - else { - return -2; - } - } - - free(matchingHal->apiName); - free(matchingHal->sndCardPath); - free(matchingHal->info); - free(matchingHal->author); - free(matchingHal->version); - free(matchingHal->date); - - if(matchingHal->internal) { - HalUtlRemoveAllMixerData(&matchingHal->internalHalData->streamsData); - HalUtlRemoveAllMixerData(&matchingHal->internalHalData->playbacksData); - HalUtlRemoveAllMixerData(&matchingHal->internalHalData->capturesData); - - HalUtlFreeAlsaCtlsMap(matchingHal->internalHalData->alsaMapT); - - free(matchingHal->internalHalData); - } - - free(matchingHal); - - return 0; -} - -int64_t HalUtlRemoveAllHalFromList(struct HalData **halDataList) -{ - int8_t ret; - int64_t halRemoved = 0; - - if(! halDataList) - return -1; - - while(*halDataList) { - ret = HalUtlRemoveSelectedHalFromList(halDataList, *halDataList); - if(ret) - return (int64_t) ret; - - halRemoved++; - } - - return halRemoved; -} - -int64_t HalUtlGetNumberOfHalInList(struct HalData **halDataList) -{ - int64_t numberOfHal = 0; - struct HalData *currentHalData; - - if(! halDataList) - return -1; - - currentHalData = *halDataList; - - while(currentHalData) { - currentHalData = currentHalData->next; - numberOfHal++; - } - - return numberOfHal; -} - -struct HalData *HalUtlSearchHalDataByApiName(struct HalData **halDataList, char *apiName) -{ - struct HalData *currentHalData; - - if(! halDataList || ! *halDataList || ! apiName) - return NULL; - - currentHalData = *halDataList; - - while(currentHalData) { - if(! strcmp(apiName, currentHalData->apiName)) - return currentHalData; - - currentHalData = currentHalData->next; - } - - return NULL; -} - -struct HalData *HalUtlSearchReadyHalDataByCardId(struct HalData **halDataList, int cardId) -{ - struct HalData *currentHalData; - - if(! halDataList || ! *halDataList) - return NULL; - - currentHalData = *halDataList; - - while(currentHalData) { - if(currentHalData->status == HAL_STATUS_READY && currentHalData->sndCardId == cardId) - return currentHalData; - - currentHalData = currentHalData->next; - } - - return NULL; -} - -/******************************************************************************* - * Hal Manager data handling functions * - ******************************************************************************/ - -uint8_t HalUtlInitializeHalMgrData(afb_api_t apiHandle, struct HalMgrData *halMgrData, char *apiName, char *info) -{ - if(! apiHandle || ! halMgrData || ! apiName || ! info) - return -1; - - // Allocate and fill apiName and info strings - halMgrData->apiName = strdup(apiName); - if(! halMgrData->apiName) - return -2; - - halMgrData->info = strdup(info); - if(! halMgrData->info) - return -3; - - halMgrData->apiHandle = apiHandle; - - return 0; -} - -void HalUtlRemoveHalMgrData(struct HalMgrData *halMgrData) -{ - if(! halMgrData) - return; - - if(halMgrData->halDataList) - HalUtlRemoveAllHalFromList(&halMgrData->halDataList); - - free(halMgrData->apiName); - free(halMgrData->info); - - free(halMgrData); -} \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-data.h b/4a-hal-utilities/4a-hal-utilities-data.h deleted file mode 100644 index f3de1a6..0000000 --- a/4a-hal-utilities/4a-hal-utilities-data.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _HAL_UTILITIES_DATA_INCLUDE_ -#define _HAL_UTILITIES_DATA_INCLUDE_ - -#include - -#include - -#include - -#include - -#include "4a-hal-utilities-alsa-data.h" - -#define HAL_STREAM_UPDATES_EVENT_NAME "stream-updates" - -// Enum for hal status -enum HalStatus { - HAL_STATUS_UNAVAILABLE=0, - HAL_STATUS_AVAILABLE=1, - HAL_STATUS_READY=2 -}; - -// Structure to store stream data -struct InternalHalMixerData { - char *verb; - char *verbToCall; - char *streamCardId; - afb_event_t event; - - struct InternalHalMixerData *next; -}; - -// Structure to store specific internal hal data -struct InternalHalData { - char *mixerApiName; - char *prefix; - json_object *halMixerJ; - - struct InternalHalMixerData *streamsData; - afb_event_t streamUpdates; - - struct InternalHalMixerData *playbacksData; - struct InternalHalMixerData *capturesData; - - struct InternalHalAlsaMapT *alsaMapT; - - afb_api_t apiHandle; - CtlConfigT *ctrlConfig; -}; - -// Structure to store specific hal (internal or external) data -struct HalData { - char *apiName; - enum HalStatus status; - char *sndCardPath; - int sndCardId; - char *info; - unsigned int internal; - - char *author; - char *version; - char *date; - // Can be beefed up if needed - - struct InternalHalData *internalHalData; // Can be NULL if external api - - struct HalData *next; -}; - -// Structure to store hal manager data -struct HalMgrData { - char *apiName; - char *info; - - afb_api_t apiHandle; - - struct HalData *halDataList; -}; - -// Internal Hal - Streams data handling functions -struct InternalHalMixerData *HalUtlAddMixerDataToMixerDataList(struct InternalHalMixerData **mixerDataList); -int8_t HalUtlRemoveSelectedMixerData(struct InternalHalMixerData **mixerDataList, struct InternalHalMixerData *mixerDataToRemove); -int64_t HalUtlRemoveAllMixerData(struct InternalHalMixerData **mixerDataList); -int64_t HalUtlGetNumberOfMixerDataInList(struct InternalHalMixerData **mixerDataList); -struct InternalHalMixerData *HalUtlSearchMixerDataByProperties(struct InternalHalMixerData **mixerDataList, char *verb, char *verbToCall, char *streamCardId); - -// Hal data handling functions -struct HalData *HalUtlAddHalToHalList(struct HalData **halDataList); -int8_t HalUtlRemoveSelectedHalFromList(struct HalData **halDataList, struct HalData *halToRemove); -int64_t HalUtlRemoveAllHalFromList(struct HalData **halDataList); -int64_t HalUtlGetNumberOfHalInList(struct HalData **halDataList); -struct HalData *HalUtlSearchHalDataByApiName(struct HalData **halDataList, char *apiName); -struct HalData *HalUtlSearchReadyHalDataByCardId(struct HalData **halDataList, int cardId); - -// Hal Manager data handling functions -uint8_t HalUtlInitializeHalMgrData(afb_api_t apiHandle, struct HalMgrData *halMgrData, char *apiName, char *info); -void HalUtlRemoveHalMgrData(struct HalMgrData *halMgrData); - -#endif /* _HAL_UTILITIES_DATA_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c b/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c deleted file mode 100644 index ed06b27..0000000 --- a/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2019 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include "4a-hal-utilities-data.h" -#include "4a-hal-utilities-hal-streams-handler.h" - -/******************************************************************************* - * Actions to be call when a stream verb is called * - ******************************************************************************/ - -void HalUtlActionOnMixer(afb_req_t request, enum ActionOnMixerType actionType) -{ - int idx, count; - - char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; - - afb_api_t apiHandle; - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - struct InternalHalMixerData *currentMixerData = NULL; - - json_object *requestJson, *responseJ = NULL, *toReturnJ = NULL; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get current hal controller api handle"); - return; - } - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - afb_req_fail(request, "hal_controller_config", "Can't get current hal controller config"); - return; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - afb_req_fail(request, "hal_controller_data", "Can't get current hal controller data"); - return; - } - - if(! (requestJson = afb_req_json(request))) { - afb_req_fail(request, "request_json", "Can't get request json"); - return; - } - - if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) - json_object_object_add(requestJson, "verbose", json_object_new_boolean(1)); - - apiToCall = currentHalData->internalHalData->mixerApiName; - if(! apiToCall) { - afb_req_fail(request, "mixer_api", "Can't get mixer api"); - return; - } - - if(currentHalData->status != HAL_STATUS_READY) { - afb_req_fail(request, "hal_not_ready", "Seems that hal is not ready"); - return; - } - - currentMixerData = (struct InternalHalMixerData *) afb_req_get_vcbdata(request); - if(! currentMixerData) { - afb_req_fail(request, "hal_call_data", "Can't get current call data"); - return; - } - - switch(actionType) { - case ACTION_ON_MIXER_STREAM: - count = 1; - break; - - case ACTION_ON_MIXER_PLAYBACK: - case ACTION_ON_MIXER_CAPTURE: - case ACTION_ON_MIXER_ALL_STREAM: - count = (int) HalUtlGetNumberOfMixerDataInList(¤tMixerData); - toReturnJ = json_object_new_object(); - break; - - default: - afb_req_fail(request, "mixer_action_type", "Action type is unknown"); - return; - } - - for(idx = 0; idx < count; idx++) { - if(afb_api_call_sync(apiHandle, - apiToCall, - currentMixerData->verbToCall, - json_object_get(requestJson), - &responseJ, - &returnedError, - &returnedInfo)) { - if(responseJ) - json_object_put(responseJ); - if(toReturnJ) - json_object_put(toReturnJ); - afb_req_fail_f(request, - "mixer_call", - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s' (call to mixer %i out of %i)", - currentMixerData->verbToCall, - apiToCall, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned", - idx, - count); - free(returnedError); - free(returnedInfo); - return; - } - - if(! responseJ) { - if(toReturnJ) - json_object_put(toReturnJ); - afb_req_fail_f(request, - "mixer_call", - "Seems that %s call to api %s succeed but no response was returned (call to mixer %i out of %i)", - currentMixerData->verbToCall, - apiToCall, - idx, - count); - free(returnedError); - free(returnedInfo); - return; - } - - // TBD JAI : When mixer events will be available, use them instead of generating events at calls - if((actionType == ACTION_ON_MIXER_STREAM || - actionType == ACTION_ON_MIXER_ALL_STREAM) && - ((! currentMixerData->event) || - (afb_event_push(currentMixerData->event, json_object_get(responseJ)) < 0))) { - AFB_API_ERROR(apiHandle, "Could not generate an event for stream %s", currentMixerData->verb); - } - - switch(actionType) { - case ACTION_ON_MIXER_STREAM: - toReturnJ = responseJ; - break; - - case ACTION_ON_MIXER_PLAYBACK: - case ACTION_ON_MIXER_CAPTURE: - json_object_object_add(toReturnJ, currentMixerData->verbToCall, responseJ); - currentMixerData = currentMixerData->next; - break; - - case ACTION_ON_MIXER_ALL_STREAM: - json_object_object_add(toReturnJ, currentMixerData->verb, responseJ); - currentMixerData = currentMixerData->next; - break; - - default: - break; - } - } - - switch(actionType) { - case ACTION_ON_MIXER_STREAM: - afb_req_success_f(request, - toReturnJ, - "Action %s correctly transferred to %s without any error raised", - currentMixerData->verbToCall, - apiToCall); - break; - - case ACTION_ON_MIXER_PLAYBACK: - afb_req_success(request, - toReturnJ, - "Actions correctly transferred to all playbacks without any error raised"); - break; - - case ACTION_ON_MIXER_CAPTURE: - afb_req_success(request, - toReturnJ, - "Actions correctly transferred to all captures without any error raised"); - break; - - case ACTION_ON_MIXER_ALL_STREAM: - afb_req_success(request, - toReturnJ, - "Actions correctly transferred to all streams without any error raised"); - break; - - default: - break; - } -} - -void HalUtlActionOnStream(afb_req_t request) -{ - HalUtlActionOnMixer(request, ACTION_ON_MIXER_STREAM); -} - -void HalUtlActionOnPlayback(afb_req_t request) -{ - HalUtlActionOnMixer(request, ACTION_ON_MIXER_PLAYBACK); -} - -void HalUtlActionOnCapture(afb_req_t request) -{ - HalUtlActionOnMixer(request, ACTION_ON_MIXER_CAPTURE); -} - -void HalUtlActionOnAllStream(afb_req_t request) -{ - HalUtlActionOnMixer(request, ACTION_ON_MIXER_ALL_STREAM); -} - -/******************************************************************************* - * Add stream data and verb function * - ******************************************************************************/ - -struct InternalHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(afb_api_t apiHandle, - char *verb, - char *verbToCall, - char *streamCardId) -{ - json_object *streamAddedEventJ; - - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - struct InternalHalMixerData *createdStreamData; - - if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) - return NULL; - - ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); - if(! ctrlConfig) - return NULL; - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData || - ! currentHalData->internalHalData) - return NULL; - - createdStreamData = HalUtlAddMixerDataToMixerDataList(¤tHalData->internalHalData->streamsData); - if(! createdStreamData) - return NULL; - - createdStreamData->verb = strdup(verb); - createdStreamData->verbToCall = strdup(verbToCall); - createdStreamData->streamCardId = strdup(streamCardId); - - if((! createdStreamData->verb) || - (! createdStreamData->verbToCall) || - (! createdStreamData->streamCardId)) { - HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); - return NULL; - } - - if(! (createdStreamData->event = afb_api_make_event(apiHandle, createdStreamData->verb))) { - HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); - return NULL; - } - - if(afb_api_add_verb(apiHandle, - createdStreamData->verb, - "Stream action transferred to mixer", - HalUtlActionOnStream, - (void *) createdStreamData, - NULL, - 0, - 0)) { - AFB_API_ERROR(apiHandle,"Error while creating verb for stream : '%s'", createdStreamData->verb); - HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); - return NULL; - } - - wrap_json_pack(&streamAddedEventJ, - "{s:s, s:s, s:s}", - "action", "added", - "name", createdStreamData->verb, - "cardId", createdStreamData->streamCardId); - - afb_event_push(currentHalData->internalHalData->streamUpdates, streamAddedEventJ); - - return createdStreamData; -} - -int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, - char *verb, - char *verbToCall, - char *streamCardId) -{ - int8_t returnedErr = 0; - - json_object *streamRemovedEventJ; - - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - struct InternalHalMixerData *toRemoveStreamData; - - if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) - return -1; - - ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); - if(! ctrlConfig) - return -2; - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData || - ! currentHalData->internalHalData) - return -3; - - toRemoveStreamData = HalUtlSearchMixerDataByProperties(¤tHalData->internalHalData->streamsData, - verb, - verbToCall, - streamCardId); - if(! toRemoveStreamData) - return -4; - - wrap_json_pack(&streamRemovedEventJ, - "{s:s, s:s, s:s}", - "action", "removed", - "name", toRemoveStreamData->verb, - "cardId", toRemoveStreamData->streamCardId); - - if(afb_api_del_verb(apiHandle, verb, NULL)) { - AFB_API_ERROR(apiHandle,"Error while deleting verb for stream : '%s'", verb); - json_object_put(streamRemovedEventJ); - return -5; - } - - returnedErr = HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, toRemoveStreamData); - if(returnedErr) { - AFB_API_ERROR(apiHandle,"Error %i while removing data for stream : '%s'", returnedErr, verb); - json_object_put(streamRemovedEventJ); - return -6; - } - - afb_event_push(currentHalData->internalHalData->streamUpdates, streamRemovedEventJ); - - return 0; -} \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h b/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h deleted file mode 100644 index 028dd1f..0000000 --- a/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -* Copyright (C) 2019 "IoT.bzh" -* Author Jonathan Aillet -* -* 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 _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ -#define _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ - -#include - -#include - -#include - -// Enum for the type of action on mixer -enum ActionOnMixerType { - ACTION_ON_MIXER_STREAM = 1, - ACTION_ON_MIXER_PLAYBACK = 2, - ACTION_ON_MIXER_CAPTURE = 3, - ACTION_ON_MIXER_ALL_STREAM = 4 -}; - -// Actions to be call when a stream verb is called -void HalUtlActionOnStream(afb_req_t request); -void HalUtlActionOnPlayback(afb_req_t request); -void HalUtlActionOnCapture(afb_req_t request); -void HalUtlActionOnAllStream(afb_req_t request); - -// Add/Remove stream data and verb functions -struct InternalHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(afb_api_t apiHandle, - char *verb, - char *verbToCall, - char *streamCardId); -int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, - char *verb, - char *verbToCall, - char *streamCardId); - -#endif /* _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-verbs-loader.c b/4a-hal-utilities/4a-hal-utilities-verbs-loader.c deleted file mode 100644 index 16c28c4..0000000 --- a/4a-hal-utilities/4a-hal-utilities-verbs-loader.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 "4a-hal-utilities-verbs-loader.h" - -/******************************************************************************* - * Dynamic API common functions * - ******************************************************************************/ - -int HalUtlLoadVerbs(afb_api_t apiHandle, afb_verb_t *verbs) -{ - int idx, errCount = 0; - - if(! apiHandle || ! verbs) - return -1; - - for (idx = 0; verbs[idx].verb; idx++) { - errCount+= afb_api_add_verb(apiHandle, - verbs[idx].verb, - NULL, - verbs[idx].callback, - (void *) &verbs[idx], - verbs[idx].auth, - 0, - 0); - } - - return errCount; -} \ No newline at end of file diff --git a/4a-hal-utilities/4a-hal-utilities-verbs-loader.h b/4a-hal-utilities/4a-hal-utilities-verbs-loader.h deleted file mode 100644 index 9084595..0000000 --- a/4a-hal-utilities/4a-hal-utilities-verbs-loader.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ -#define _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ - -#include - -#include - -// Verb that allows to add verb to a dynamic api -int HalUtlLoadVerbs(afb_api_t apiHandle, afb_verb_t *verbs); - -#endif /* _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal-utilities/CMakeLists.txt b/4a-hal-utilities/CMakeLists.txt deleted file mode 100644 index d90dd11..0000000 --- a/4a-hal-utilities/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017, 2018, 2019 IoT.bzh -# -# author: Fulup Ar Foll -# contrib: Jonathan Aillet -# -# 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(4a-hal-utilities) - - # Define project Targets - ADD_LIBRARY(${TARGET_NAME} STATIC - 4a-hal-utilities-alsa-data.c - 4a-hal-utilities-data.c - 4a-hal-utilities-hal-streams-handler.c - 4a-hal-utilities-verbs-loader.c) - - # Define target includes for this target client - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ) diff --git a/4a-hal/4a-hal-manager/4a-hal-manager-cb.c b/4a-hal/4a-hal-manager/4a-hal-manager-cb.c deleted file mode 100644 index 32fbb25..0000000 --- a/4a-hal/4a-hal-manager/4a-hal-manager-cb.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include "4a-hal-utilities-data.h" - -#include "4a-hal-manager-cb.h" - -/******************************************************************************* - * HAL Manager event handler function * - ******************************************************************************/ - -// TBD JAI : to implement -void HalMgrDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ) -{ - AFB_API_WARNING(apiHandle, "Not implemented yet"); - // Use "4a-hal-manager-events.h" to handle events -} - -/******************************************************************************* - * HAL Manager verbs functions * - ******************************************************************************/ - -void HalMgrPing(afb_req_t request) -{ - static int count = 0; - - count++; - - AFB_REQ_NOTICE(request, "ping count = %d", count); - afb_req_success(request, json_object_new_int(count), NULL); - - return; -} - -void HalMgrLoaded(afb_req_t request) -{ - int requestJsonErr = 0, allHal = 0, verbose = 0; - - char cardIdString[32]; - - afb_api_t apiHandle; - struct HalMgrData *halMgrData; - struct HalData *currentHalData; - - json_object *requestJson, *requestAnswer, *apiObject; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); - return; - } - - halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); - if(! halMgrData) { - afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); - return; - } - - currentHalData = halMgrData->halDataList; - - if(! currentHalData) { - afb_req_success(request, NULL, "No Hal Api loaded"); - return; - } - - requestAnswer = json_object_new_array(); - if(! requestAnswer) { - afb_req_fail(request, "json_answer", "Can't generate json answer"); - return; - } - - if(! (requestJson = afb_req_json(request))) - AFB_REQ_NOTICE(request, "Can't get request json"); - else - requestJsonErr = wrap_json_unpack(requestJson, "{s?:b s?:b}", "all", &allHal, "verbose", &verbose); - - while(currentHalData) { - if(allHal || currentHalData->status == HAL_STATUS_READY) { - // Case if request key is 'verbose' and value is bigger than 0 - if(! requestJsonErr && verbose) { - if(currentHalData->sndCardId >= 0) - snprintf(cardIdString, sizeof(cardIdString), "hw:%i", currentHalData->sndCardId); - else - snprintf(cardIdString, sizeof(cardIdString), "not-found"); - - wrap_json_pack(&apiObject, - "{s:s s:i s:s s:i s:s s:s s:s s:s s:s}", - "api", currentHalData->apiName, - "status", (int) currentHalData->status, - "sndcard", currentHalData->sndCardPath, - "internal", (int) currentHalData->internal, - "info", currentHalData->info ? currentHalData->info : "", - "author", currentHalData->author ? currentHalData->author : "", - "version", currentHalData->version ? currentHalData->version : "", - "date", currentHalData->date ? currentHalData->date : "", - "snd-dev-id", cardIdString); - json_object_array_add(requestAnswer, apiObject); - } - // Case if request is empty or not handled - else { - json_object_array_add(requestAnswer, json_object_new_string(currentHalData->apiName)); - } - } - - currentHalData = currentHalData->next; - } - - afb_req_success(request, requestAnswer, "Requested data"); -} - -void HalMgrLoad(afb_req_t request) -{ - int cardId = -1; - - char *apiName, *sndCardPath, *info = NULL, *author = NULL, *version = NULL, *date = NULL; - - afb_api_t apiHandle; - struct HalMgrData *halMgrData; - struct HalData *addedHal; - - json_object *requestJson, *apiReceivedMetadata; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); - return; - } - - halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); - if(! halMgrData) { - afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); - return; - } - - if(! (requestJson = afb_req_json(request))) { - afb_req_fail(request, "request_json", "Can't get request json"); - return; - } - - if(! json_object_object_get_ex(requestJson, "metadata", &apiReceivedMetadata)) { - afb_req_fail(request, "api_metadata", "Can't get json metadata section to register external hal"); - return; - } - - if(wrap_json_unpack(apiReceivedMetadata, - "{s:s s:s s?:s s?:s s?:s s?:s s?:i}", - "api", &apiName, - "uid", &sndCardPath, - "info", &info, - "author", &author, - "version", &version, - "date", &date, - "snd-dev-id", &cardId)) { - afb_req_fail(request, "api_metadata", "Can't metadata of api to register"); - return; - } - - addedHal = HalUtlAddHalToHalList(&halMgrData->halDataList); - - addedHal->internal = 0; - // TBD JAI : initialize external to unavailable once event from external hal will be handled - addedHal->status = HAL_STATUS_READY; - - addedHal->apiName = strdup(apiName); - addedHal->sndCardPath = strdup(sndCardPath); - - if(info) - addedHal->info = strdup(info); - - if(author) - addedHal->author = strdup(author); - - if(version) - addedHal->version = strdup(version); - - if(date) - addedHal->date = strdup(date); - - addedHal->sndCardId = cardId; - - // TBD JAI: add subscription to this api status events, if subscription fails, remove hal from list - - afb_req_success(request, NULL, "Api successfully registered"); -} - -void HalMgrUnload(afb_req_t request) -{ - char *apiName; - - afb_api_t apiHandle; - struct HalMgrData *halMgrData; - struct HalData *halToRemove; - - json_object *requestJson; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); - return; - } - - halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); - if(! halMgrData) { - afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); - return; - } - - if(! (requestJson = afb_req_json(request))) { - afb_req_fail(request, "request_json", "Can't get request json"); - return; - } - - if(wrap_json_unpack(requestJson, "{s:s}", "api", &apiName)) { - afb_req_fail(request, "requested_api", "Can't get api to remove"); - return; - } - - halToRemove = HalUtlSearchHalDataByApiName(&halMgrData->halDataList, apiName); - if(! halToRemove) { - afb_req_fail(request, "requested_api", "Can't find api to remove"); - return; - } - - if(halToRemove->internal) { - afb_req_fail(request, "requested_api", "Can't remove an internal hal"); - return; - } - - if(HalUtlRemoveSelectedHalFromList(&halMgrData->halDataList, halToRemove)) { - afb_req_fail(request, "unregister_error", "Didn't succeed to remove specified api"); - return; - } - - // TBD JAI: remove subscription to this api status events - - afb_req_success(request, NULL, "Api successfully unregistered"); -} - -// TBD JAI : to implement -void HalMgrSubscribeEvent(afb_req_t request) -{ - AFB_REQ_WARNING(request, "Not implemented yet"); - - afb_req_success(request, json_object_new_boolean(0), NULL); -} - -// TBD JAI : to implement -void HalMgrUnsubscribeEvent(afb_req_t request) -{ - AFB_REQ_WARNING(request, "Not implemented yet"); - - afb_req_success(request, json_object_new_boolean(0), NULL); -} diff --git a/4a-hal/4a-hal-manager/4a-hal-manager-cb.h b/4a-hal/4a-hal-manager/4a-hal-manager-cb.h deleted file mode 100644 index e0e144f..0000000 --- a/4a-hal/4a-hal-manager/4a-hal-manager-cb.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _HALMGR_CB_INCLUDE_ -#define _HALMGR_CB_INCLUDE_ - -#include - -#include - -// Event handler -void HalMgrDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ); - -// Exported verbs callbacks -void HalMgrPing(afb_req_t request); -void HalMgrLoaded(afb_req_t request); -void HalMgrLoad(afb_req_t request); -void HalMgrUnload(afb_req_t request); -void HalMgrSubscribeEvent(afb_req_t request); -void HalMgrUnsubscribeEvent(afb_req_t request); - -#endif /* _HALMGR_CB_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-hal-manager/4a-hal-manager.c b/4a-hal/4a-hal-manager/4a-hal-manager.c deleted file mode 100644 index 4d2fbf1..0000000 --- a/4a-hal/4a-hal-manager/4a-hal-manager.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 "4a-hal-utilities-data.h" -#include "4a-hal-utilities-verbs-loader.h" - -#include "../4a-internals-hal/4a-internals-hal-api-loader.h" - -#include "4a-hal-manager.h" -#include "4a-hal-manager-cb.h" - -// Default api to print log when apihandle not available -afb_api_t AFB_default; - -// Local (static) Hal manager data structure -static struct HalMgrData localHalMgrGlobalData; - -/******************************************************************************* - * HAL Manager verbs table * - ******************************************************************************/ - -// Hal manager exported verbs -afb_verb_t HalManagerApiStaticVerbs[] = -{ - /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ - { .verb = "ping", .callback = HalMgrPing, .info = "Ping test"}, - { .verb = "loaded", .callback = HalMgrLoaded, .info = "Show loaded HAL"}, - { .verb = "load", .callback = HalMgrLoad, .info = "Load an external HAL to HAL Manager"}, - { .verb = "unload", .callback = HalMgrUnload, .info = "Unload an external HAL to HAL Manager"}, - { .verb = "subscribe", .callback = HalMgrSubscribeEvent, .info = "Subscribe to an event"}, - { .verb = "unsuscribe", .callback = HalMgrUnsubscribeEvent, .info = "Unsubscribe to an event"}, - { .verb = NULL } // Marker for end of the array -}; - -/******************************************************************************* - * HAL Manager get 'HalData' linked list * - from HAL list function * - ******************************************************************************/ - -struct HalData **HalMngGetHalDataList(void) -{ - return &localHalMgrGlobalData.halDataList; -} - -/******************************************************************************* - * Dynamic API functions for hal manager * - ******************************************************************************/ - -static int HalMgrInitApi(afb_api_t apiHandle) -{ - struct HalData *currentHalData; - struct HalMgrData *halMgrData; - - if(! apiHandle) - return -1; - - // Hugely hack to make all V2 AFB_DEBUG to work in fileutils - AFB_default = apiHandle; - - // Retrieve section config from api handle - halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); - if(! halMgrData) - return -2; - - if(HalUtlInitializeHalMgrData(apiHandle, halMgrData, HAL_MANAGER_API_NAME, HAL_MANAGER_API_INFO)) - return -3; - - currentHalData = halMgrData->halDataList; - - while(currentHalData) { - if(! currentHalData->apiName) - return -4; - else if(afb_api_require_api(apiHandle, currentHalData->apiName, 1)) - return -5; - - currentHalData = currentHalData->next; - } - - return 0; -} - -static int HalMgrLoadApi(void *cbdata, afb_api_t apiHandle) -{ - struct HalMgrData *halMgrData; - - if(! cbdata || ! apiHandle) - return -1; - - halMgrData = (struct HalMgrData *) cbdata; - - // Save closure as api's data context - afb_api_set_userdata(apiHandle, halMgrData); - - // Add static controls verbs - if(HalUtlLoadVerbs(apiHandle, HalManagerApiStaticVerbs)) { - AFB_API_ERROR(apiHandle, "Load section : fail to register static verbs"); - return 1; - } - - // Declare an event manager for Hal Manager - afb_api_on_event(apiHandle, HalMgrDispatchApiEvent); - - // Init Api function (does not receive user closure ???) - afb_api_on_init(apiHandle, HalMgrInitApi); - - afb_api_seal(apiHandle); - - return 0; -} - -int HalMgrCreateApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) -{ - if(! apiHandle || ! halMgrData) - return -1; - - // Create one API - return afb_api_new_api(apiHandle, HAL_MANAGER_API_NAME, HAL_MANAGER_API_INFO, 1, HalMgrLoadApi, halMgrData) ? 0 : -1; -} - -/******************************************************************************* - * Startup function * - ******************************************************************************/ - -int afbBindingEntry(afb_api_t apiHandle) -{ - int status = 0, rc; - - if(! apiHandle) - return -1; - - // Hugely hack to make all V2 AFB_DEBUG to work in fileutils - AFB_default = apiHandle; - - AFB_API_NOTICE(apiHandle, "Binding start"); - - // Load Hal-Manager using Api v3 - rc = HalMgrCreateApi(apiHandle, &localHalMgrGlobalData); - if(rc < 0) - status--; - - // Load internals Hal using Api v3 - rc = InternalHalCreateAllApi(apiHandle, &localHalMgrGlobalData); - if(rc < 0) - status -= rc; - - return status; -} \ No newline at end of file diff --git a/4a-hal/4a-hal-manager/4a-hal-manager.h b/4a-hal/4a-hal-manager/4a-hal-manager.h deleted file mode 100644 index 4a53bdd..0000000 --- a/4a-hal/4a-hal-manager/4a-hal-manager.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _HALMGR_BINDING_INCLUDE_ -#define _HALMGR_BINDING_INCLUDE_ - -#include - -#define HAL_MANAGER_API_NAME "4a-hal-manager" -#define HAL_MANAGER_API_INFO "Manager for 4A HAL APIs" - -// HAL Manager get 'HalData' linked list -struct HalData **HalMngGetHalDataList(void); - -#endif /* _HALMGR_BINDING_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.c b/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.c deleted file mode 100644 index d092ddf..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.c +++ /dev/null @@ -1,633 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include - -#include - -#include "4a-hal-utilities-alsa-data.h" -#include "4a-hal-utilities-data.h" - -#include "4a-internals-hal-alsacore-link.h" -#include "4a-internals-hal-value-handler.h" - -/******************************************************************************* - * Map to alsa control types * - ******************************************************************************/ - -static const char *const snd_ctl_elem_type_names[] = { - [SND_CTL_ELEM_TYPE_NONE]= "NONE", - [SND_CTL_ELEM_TYPE_BOOLEAN]= "BOOLEAN", - [SND_CTL_ELEM_TYPE_INTEGER]="INTEGER", - [SND_CTL_ELEM_TYPE_ENUMERATED]="ENUMERATED", - [SND_CTL_ELEM_TYPE_BYTES]="BYTES", - [SND_CTL_ELEM_TYPE_IEC958]="IEC958", - [SND_CTL_ELEM_TYPE_INTEGER64]="INTEGER64", -}; - -/******************************************************************************* - * Alsa control types map from string function * - ******************************************************************************/ - -snd_ctl_elem_type_t InternalHalMapsAlsaTypeToEnum(const char *label) -{ - int idx; - static int length = sizeof(snd_ctl_elem_type_names) / sizeof(char *); - - for(idx = 0; idx < length; idx++) { - if(! strcasecmp(label, snd_ctl_elem_type_names[idx])) - return (snd_ctl_elem_type_t) idx; - } - - return SND_CTL_ELEM_TYPE_NONE; -} - -/******************************************************************************* - * Internals HAL - Alsacore calls funtions * - ******************************************************************************/ - -int InternalHalGetCardIdByCardPath(afb_api_t apiHandle, char *devPath) -{ - int errorToReturn, cardId; - - char *returnedError = NULL, *returnedInfo = NULL; - - json_object *toSendJ, *responseJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Api handle not available"); - return -1; - } - - if(! devPath) { - AFB_API_ERROR(apiHandle, "Dev path is not available"); - return -2; - } - - wrap_json_pack(&toSendJ, "{s:s}", "cardPath", devPath); - - if(afb_api_call_sync(apiHandle, - ALSACORE_API, - ALSACORE_GETINFO_VERB, - toSendJ, - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - ALSACORE_GETINFO_VERB, - ALSACORE_API, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - errorToReturn = -3; - } - else if(! responseJ) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but no response was returned", - ALSACORE_GETINFO_VERB, - ALSACORE_API); - errorToReturn = -4; - } - else if(! json_object_is_type(responseJ, json_type_object)) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but the returned response is invalid", - ALSACORE_GETINFO_VERB, - ALSACORE_API); - errorToReturn = -5; - } - else if(wrap_json_unpack(responseJ, "{s:i}", "cardNb", &cardId)) { - AFB_API_WARNING(apiHandle, "Response card id is not present/valid"); - errorToReturn = -6; - } - else { - return cardId; - } - - if(responseJ) - json_object_put(responseJ); - - free(returnedError); - free(returnedInfo); - - return errorToReturn; -} - -int InternalHalSubscribeToAlsaCardEvent(afb_api_t apiHandle, char *cardId) -{ - int err = 0; - - char *returnedError = NULL, *returnedInfo = NULL; - - json_object *subscribeQueryJ, *responseJ = NULL; - - wrap_json_pack(&subscribeQueryJ, "{s:s}", "devid", cardId); - if(afb_api_call_sync(apiHandle, - ALSACORE_API, - ALSACORE_SUBSCRIBE_VERB, - subscribeQueryJ, - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - ALSACORE_SUBSCRIBE_VERB, - ALSACORE_API, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - err = -1; - } - - if(responseJ) - json_object_put(responseJ); - - free(returnedError); - free(returnedInfo); - - return err; -} - -int InternalHalGetAlsaCtlInfo(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl, json_object **returnedDataJ) -{ - int err = 0; - - char *returnedError = NULL, *returnedInfo = NULL; - - json_object *queryJ, *responseJ = NULL; - - *returnedDataJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Api handle not available"); - return -1; - } - - if(! cardId) { - AFB_API_ERROR(apiHandle, "Card id is not available"); - return -2; - } - - if(! currentAlsaCtl) { - AFB_API_ERROR(apiHandle, "Alsa control data structure is not available"); - return -3; - } - - if(currentAlsaCtl->name && currentAlsaCtl->numid > 0) { - AFB_API_DEBUG(apiHandle, - "Both a control name (%s) and a control uid (%i) are specified, control uid will be used", - currentAlsaCtl->name, - currentAlsaCtl->numid); - } - - if(currentAlsaCtl->numid > 0) { - wrap_json_pack(&queryJ, "{s:s s:i s:i}", "devid", cardId, "ctl", currentAlsaCtl->numid, "mode", 3); - } - else if(currentAlsaCtl->name) { - wrap_json_pack(&queryJ, "{s:s s:s s:i}", "devid", cardId, "ctl", currentAlsaCtl->name, "mode", 3); - } - else { - AFB_API_ERROR(apiHandle, "Need at least a control name or a control id"); - return -4; - } - - if(afb_api_call_sync(apiHandle, - ALSACORE_API, - ALSACORE_CTLGET_VERB, - queryJ, - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - ALSACORE_CTLGET_VERB, - ALSACORE_API, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - free(returnedError); - free(returnedInfo); - return -5; - } - else if(! responseJ) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but no response was returned", - ALSACORE_CTLGET_VERB, - ALSACORE_API); - return -6; - } - else if(currentAlsaCtl->name && wrap_json_unpack(responseJ, "{s:i}", "id", ¤tAlsaCtl->numid)) { - AFB_API_ERROR(apiHandle, "Can't find alsa control 'id' from control 'name': '%s' on device '%s'", currentAlsaCtl->name, cardId); - json_object_put(responseJ); - return -7; - } - - *returnedDataJ = responseJ; - - return err; -} - -int InternalHalUpdateAlsaCtlProperties(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl) -{ - int err = 0; - - json_object *returnedDataJ; - - err = InternalHalGetAlsaCtlInfo(apiHandle, cardId, currentAlsaCtl, &returnedDataJ); - if(err) { - return err; - } - // TBD JAI : get dblinear/dbminmax/... values - else if(wrap_json_unpack(returnedDataJ, - "{s:{s?:i s?:i s?:i s?:i s?:i}}", - "ctl", - "type", (int *) ¤tAlsaCtl->alsaCtlProperties.type, - "count", ¤tAlsaCtl->alsaCtlProperties.count, - "min", ¤tAlsaCtl->alsaCtlProperties.minval, - "max", ¤tAlsaCtl->alsaCtlProperties.maxval, - "step", ¤tAlsaCtl->alsaCtlProperties.step)) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to get control %i properties on device '%s' : '%s'", - currentAlsaCtl->numid, - cardId, - json_object_get_string(returnedDataJ)); - - err = -8; - } - - if(returnedDataJ) - json_object_put(returnedDataJ); - - return err; -} - -int InternalHalGetAlsaCtlValues(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl, json_object **returnedValuesJ) -{ - int err = 0; - - json_object *returnedDataJ = NULL, *returnedValuesArrayJ; - - *returnedValuesJ = NULL; - - err = InternalHalGetAlsaCtlInfo(apiHandle, cardId, currentAlsaCtl, &returnedDataJ); - if(err) { - return err; - } - else if(wrap_json_unpack(returnedDataJ, "{s:o}", "val", &returnedValuesArrayJ)) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to get control %i values on device '%s' : '%s'", - currentAlsaCtl->numid, - cardId, - json_object_get_string(returnedValuesArrayJ)); - - err = -8; - } - else if(! json_object_is_type(returnedValuesArrayJ, json_type_array)) { - AFB_API_ERROR(apiHandle, - "Json returned by control %i values on device '%s' are not an array ('%s')", - currentAlsaCtl->numid, - cardId, - json_object_get_string(returnedValuesArrayJ)); - - err = -9; - } - - if(! err) - *returnedValuesJ = json_object_get(returnedValuesArrayJ); - - if(returnedDataJ) - json_object_put(returnedDataJ); - - return err; -} - -int InternalHalSetAlsaCtlValue(afb_api_t apiHandle, char *cardId, int ctlId, json_object *valuesJ) -{ - int err = 0; - - char *returnedError = NULL, *returnedInfo = NULL; - - json_object *queryJ, *responseJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Api handle not available"); - return -1; - } - - if(! cardId) { - AFB_API_ERROR(apiHandle, "Card id is not available"); - return -2; - } - - if(ctlId <= 0) { - AFB_API_ERROR(apiHandle, "Alsa control id is not valid"); - return -3; - } - - if(! valuesJ) { - AFB_API_ERROR(apiHandle, "Values to set json is not available"); - return -4; - } - - wrap_json_pack(&queryJ, "{s:s s:{s:i s:o}}", "devid", cardId, "ctl", "id", ctlId, "val", json_object_get(valuesJ)); - - if(afb_api_call_sync(apiHandle, - ALSACORE_API, - ALSACORE_CTLSET_VERB, - queryJ, - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - ALSACORE_CTLSET_VERB, - ALSACORE_API, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - err = -5; - } - - if(responseJ) - json_object_put(responseJ); - - free(returnedError); - free(returnedInfo); - - return err; -} - -int InternalHalCreateAlsaCtl(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *alsaCtlToCreate) -{ - int err = 0; - - char *returnedError = NULL, *returnedInfo = NULL; - - json_object *queryJ, *responseJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Api handle not available"); - return -1; - } - - if(! cardId) { - AFB_API_ERROR(apiHandle, "Card id is not available"); - return -2; - } - - if(! alsaCtlToCreate) { - AFB_API_ERROR(apiHandle, "Alsa control data structure is not available"); - return -3; - } - - if(! alsaCtlToCreate->alsaCtlCreation) { - AFB_API_ERROR(apiHandle, "Alsa control data for creation structure is not available"); - return -4; - } - - wrap_json_pack(&queryJ, "{s:s s:{s:i s:s s?:i s?:i s?:i s:i s:i}}", - "devid", cardId, - "ctl", - "ctl", -1, - "name", alsaCtlToCreate->name, - "min", alsaCtlToCreate->alsaCtlCreation->minval, - "max", alsaCtlToCreate->alsaCtlCreation->maxval, - "step", alsaCtlToCreate->alsaCtlCreation->step, - "type", (int) alsaCtlToCreate->alsaCtlCreation->type, - "count", alsaCtlToCreate->alsaCtlCreation->count); - - if(afb_api_call_sync(apiHandle, - ALSACORE_API, - ALSACORE_ADDCTL_VERB, - queryJ, - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - ALSACORE_ADDCTL_VERB, - ALSACORE_API, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - err = -5; - } - else if(! responseJ) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but no response was returned", - ALSACORE_ADDCTL_VERB, - ALSACORE_API); - err = -6; - } - else if(wrap_json_unpack(responseJ, "{s:i}", "id", &alsaCtlToCreate->numid)) { - AFB_API_ERROR(apiHandle, - "Can't get create id from %s of %s api", - ALSACORE_ADDCTL_VERB, - ALSACORE_API); - err = -7; - } - else if(wrap_json_unpack(responseJ, "{s:o}", "ctl", NULL)) { - AFB_API_WARNING(apiHandle, "Control %s was already present but has been updated", alsaCtlToCreate->name); - } - - if(responseJ) - json_object_put(responseJ); - - free(returnedError); - free(returnedInfo); - - return err; -} - -/******************************************************************************* - * Internals HAL - Alsacore controls request callback * - ******************************************************************************/ - -void InternalHalActionOnAlsaCtl(afb_req_t request) -{ - char cardIdString[6]; - - afb_api_t apiHandle; - - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - struct InternalHalAlsaMap *currentAlsaCtl; - - json_object *requestJson, - *valueJ, - *convertedJ, - *answerJ, - *previousControlValuesJ, - *normalizedPreviousControlValuesJ, - *appliedControlValuesJ, - *normalizedAppliedControlValuesJ; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get current hal controller api handle"); - return; - } - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - afb_req_fail(request, "hal_controller_config", "Can't get current hal controller config"); - return; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - afb_req_fail(request, "hal_controller_data", "Can't get current hal controller data"); - return; - } - - if(currentHalData->status == HAL_STATUS_UNAVAILABLE) { - afb_req_fail(request, "hal_unavailable", "Seems that hal is not available"); - return; - } - - currentAlsaCtl = (struct InternalHalAlsaMap *) afb_req_get_vcbdata(request); - if(! currentAlsaCtl) { - afb_req_fail(request, "alsa_control_data", "Can't get current alsa control data"); - return; - } - - if(currentAlsaCtl->ctl.numid <= 0) { - afb_req_fail(request, "alsa_control_id", "Alsa control id is not valid"); - return; - } - - snprintf(cardIdString, 6, "hw:%i", currentHalData->sndCardId); - - if(InternalHalGetAlsaCtlValues(apiHandle, cardIdString, ¤tAlsaCtl->ctl, &previousControlValuesJ)) { - afb_req_fail_f(request, "previous_values", "Error when trying to get unchanged alsa control values"); - return; - } - else if(InternalHalConvertJsonValues(apiHandle, - ¤tAlsaCtl->ctl.alsaCtlProperties, - previousControlValuesJ, - &normalizedPreviousControlValuesJ, - CONVERSION_ALSACORE_TO_NORMALIZED)) { - afb_req_fail_f(request, - "request_json", - "Error when trying to normalize unchanged alsa control values json '%s'", - json_object_get_string(previousControlValuesJ)); - json_object_put(previousControlValuesJ); - return; - } - - if(! (requestJson = afb_req_json(request))) { - wrap_json_pack(&answerJ, - "{s:o}", - "current", normalizedPreviousControlValuesJ); - afb_req_success(request, answerJ, "Current controls values"); - json_object_put(previousControlValuesJ); - return; - } - - if(! json_object_is_type(requestJson, json_type_object)) { - afb_req_fail_f(request, "request_json", "Request json is not valid '%s'", json_object_get_string(requestJson)); - json_object_put(previousControlValuesJ); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - - if(wrap_json_unpack(requestJson, "{s:o}", "value", &valueJ)) { - afb_req_fail_f(request, - "request_json", "Error when trying to get request value object inside request '%s'", - json_object_get_string(requestJson)); - json_object_put(previousControlValuesJ); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - - if((! json_object_is_type(valueJ, json_type_string)) && - InternalHalConvertJsonValues(apiHandle, - ¤tAlsaCtl->ctl.alsaCtlProperties, - valueJ, - &convertedJ, - CONVERSION_NORMALIZED_TO_ALSACORE)) { - afb_req_fail_f(request, - "request_json", - "Error when trying to convert request values '%s'", - json_object_get_string(valueJ)); - json_object_put(previousControlValuesJ); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - else if(json_object_is_type(valueJ, json_type_string) && - InternalHalChangePreviousValuesUsingJson(apiHandle, - ¤tAlsaCtl->ctl.alsaCtlProperties, - valueJ, - previousControlValuesJ, - &convertedJ)) { - afb_req_fail_f(request, - "previous_values", - "Error when trying to generate changed alsa control values (values : '%s', previous :'%s')", - json_object_get_string(valueJ), - json_object_get_string(previousControlValuesJ)); - json_object_put(previousControlValuesJ); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - - json_object_put(previousControlValuesJ); - - if(InternalHalSetAlsaCtlValue(apiHandle, cardIdString, currentAlsaCtl->ctl.numid, convertedJ)) { - afb_req_fail_f(request, - "alsa_control_call_error", - "Error while trying to set value on alsa control %i, device '%s', converted message '%s'", - currentAlsaCtl->ctl.numid, - cardIdString, - json_object_get_string(convertedJ)); - json_object_put(convertedJ); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - - json_object_put(convertedJ); - - if(InternalHalGetAlsaCtlValues(apiHandle, cardIdString, ¤tAlsaCtl->ctl, &appliedControlValuesJ)) { - afb_req_fail_f(request, "applied_values", "Error when trying to get applied alsa control values"); - json_object_put(normalizedPreviousControlValuesJ); - return; - } - else if(InternalHalConvertJsonValues(apiHandle, - ¤tAlsaCtl->ctl.alsaCtlProperties, - appliedControlValuesJ, - &normalizedAppliedControlValuesJ, - CONVERSION_ALSACORE_TO_NORMALIZED)) { - afb_req_fail_f(request, - "request_json", - "Error when trying to normalize applied values json '%s'", - json_object_get_string(appliedControlValuesJ)); - json_object_put(normalizedPreviousControlValuesJ); - json_object_put(appliedControlValuesJ); - return; - } - - json_object_put(appliedControlValuesJ); - - wrap_json_pack(&answerJ, - "{s:o, s:o}", - "previous", normalizedPreviousControlValuesJ, - "current", normalizedAppliedControlValuesJ); - - afb_req_success(request, answerJ, "Values correctly applied on alsa control"); -} \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.h b/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.h deleted file mode 100644 index 065e017..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-alsacore-link.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -* Copyright (C) 2018 "IoT.bzh" -* Author Jonathan Aillet -* -* 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 _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ -#define _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ - -#include - -#include - -#include - -#include - -#include - -#include "4a-hal-utilities-alsa-data.h" - -#define ALSACORE_API "alsacore" -#define ALSACORE_SUBSCRIBE_VERB "subscribe" -#define ALSACORE_GETINFO_VERB "infoget" -#define ALSACORE_CTLGET_VERB "ctlget" -#define ALSACORE_CTLSET_VERB "ctlset" -#define ALSACORE_ADDCTL_VERB "addcustomctl" - -// Alsa control types map from string function -snd_ctl_elem_type_t InternalHalMapsAlsaTypeToEnum(const char *label); - -// Internals HAL alsacore calls funtions -int InternalHalGetCardIdByCardPath(afb_api_t apiHandle, char *devPath); -int InternalHalSubscribeToAlsaCardEvent(afb_api_t apiHandle, char *cardId); -int InternalHalUpdateAlsaCtlProperties(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl); -int InternalHalSetAlsaCtlValue(afb_api_t apiHandle, char *cardId, int ctlId, json_object *valuesJ); -int InternalHalCreateAlsaCtl(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *alsaCtlToCreate); - -// Internals HAL alsacore controls request callback -void InternalHalActionOnAlsaCtl(afb_req_t request); - -#endif /* _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c b/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c deleted file mode 100644 index 94891b8..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include - -#include - -#include "4a-hal-utilities-verbs-loader.h" -#include "4a-internals-hal-api-loader.h" -#include "4a-internals-hal-alsacore-link.h" -#include "4a-internals-hal-cb.h" -#include "4a-internals-hal-mixer-link.h" - -// Default api to print log when apihandle not available -afb_api_t AFB_default; - -/******************************************************************************* - * Json parsing functions using controller * - ******************************************************************************/ - -// Config Section definition -static CtlSectionT ctrlSectionsDefault[] = -{ - { .key = "resources", .loadCB = PluginConfig }, - { .key = "halmixer", .loadCB = InternalHalHalMixerConfig }, - { .key = "onload", .loadCB = OnloadConfig }, - { .key = "controls", .loadCB = ControlConfig }, - { .key = "events", .loadCB = EventConfig }, - { .key = "halmap", .loadCB = InternalHalHalMapConfig }, - { .key = NULL } -}; - -/******************************************************************************* - * Dynamic HAL verbs' functions * - ******************************************************************************/ - -// Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT -static afb_verb_t InternalHalApiStaticVerbs[] = -{ - /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ - { .verb = "info", .callback = InternalHalInfo, .info = "List available streams/playbacks/captures/controls for this api" }, - { .verb = "subscribe", .callback = InternalHalSubscribe, .info = "Subscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, - { .verb = "unsubscribe", .callback = InternalHalUnsubscribe, .info = "Unsubscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, - { .verb = NULL } // Marker for end of the array -}; - -/******************************************************************************* - * Dynamic API functions for internals hal * - ******************************************************************************/ - -static int InternalHalInitOneApi(afb_api_t apiHandle) -{ - CtlConfigT *ctrlConfig; - struct HalData *currentHalData; - - if(! apiHandle) - return -1; - - // Hugely hack to make all V2 AFB_DEBUG to work in fileutils - AFB_default = apiHandle; - - // Retrieve section config from api handle - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) - return -2; - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) - return -3; - - // Fill HalDatadata structure - currentHalData->internal = 1; - - currentHalData->sndCardPath = (char *) ctrlConfig->uid; - currentHalData->info = (char *) ctrlConfig->info; - - currentHalData->author = (char *) ctrlConfig->author; - currentHalData->version = (char *) ctrlConfig->version; - currentHalData->date = (char *) ctrlConfig->date; - - currentHalData->internalHalData->apiHandle = apiHandle; - currentHalData->internalHalData->ctrlConfig = ctrlConfig; - - currentHalData->sndCardId = InternalHalGetCardIdByCardPath(apiHandle, currentHalData->sndCardPath); - - currentHalData->internalHalData->streamUpdates = afb_api_make_event(apiHandle, HAL_STREAM_UPDATES_EVENT_NAME); - if(! currentHalData->internalHalData->streamUpdates) - return -4; - - if(currentHalData->sndCardId < 0) - currentHalData->status = HAL_STATUS_UNAVAILABLE; - else - currentHalData->status = HAL_STATUS_AVAILABLE; - - // TBD JAI: handle refresh of hal status for dynamic card (/dev/by-id) - - return CtlConfigExec(apiHandle, ctrlConfig); -} - -static int InternalHalLoadOneApi(void *cbdata, afb_api_t apiHandle) -{ - int err; - CtlConfigT *ctrlConfig; - CtlSectionT *ctrlCurrentSections; - - if(! cbdata || ! apiHandle) - return -1; - - ctrlConfig = (CtlConfigT*) cbdata; - - // Save closure as api's data context - afb_api_set_userdata(apiHandle, ctrlConfig); - - // Add static controls verbs - if(HalUtlLoadVerbs(apiHandle, InternalHalApiStaticVerbs)) { - AFB_API_ERROR(apiHandle, "Load Section : fail to register static V2 verbs"); - return 1; - } - - ctrlCurrentSections = malloc(sizeof(ctrlSectionsDefault)); - memcpy(ctrlCurrentSections, ctrlSectionsDefault, sizeof(ctrlSectionsDefault)); - - // Load section for corresponding Api - if((err = CtlLoadSections(apiHandle, ctrlConfig, ctrlCurrentSections))) - return err; - - // Declare an event manager for this Api - afb_api_on_event(apiHandle, InternalHalDispatchApiEvent); - - // Init Api function (does not receive user closure ???) - afb_api_on_init(apiHandle, InternalHalInitOneApi); - - return 0; -} - -int InternalHalCreateApi(afb_api_t apiHandle, char *path, struct HalMgrData *halMgrData) -{ - CtlConfigT *ctrlConfig; - struct HalData *currentHalData; - - if(! apiHandle || ! path || ! halMgrData) - return -1; - - // Create one Api per file - ctrlConfig = CtlLoadMetaData(apiHandle, path); - if(! ctrlConfig) { - AFB_API_ERROR(apiHandle, "No valid control config file in:\n-- %s", path); - return -2; - } - - if(! ctrlConfig->api) { - AFB_API_ERROR(apiHandle, "API Missing from metadata in:\n-- %s", path); - return -3; - } - - // Allocation of current hal controller data - currentHalData = HalUtlAddHalToHalList(&halMgrData->halDataList); - if(! currentHalData) - return -4; - - currentHalData->apiName = (char *) ctrlConfig->api; - - // Stores hal data in controller config - setExternalData(ctrlConfig, (void *) currentHalData); - - // Allocation of the structure that will be used to store internal hal data - currentHalData->internalHalData = calloc(1, sizeof(struct InternalHalData)); - - // Create one API - if(! afb_api_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, InternalHalLoadOneApi, ctrlConfig)) - return -5; - - return 0; -} - -int InternalHalCreateAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) -{ - int index, status = 0; - char *dirList, *fileName, *fullPath; - char filePath[CONTROL_MAXPATH_LEN]; - - filePath[CONTROL_MAXPATH_LEN - 1] = '\0'; - - json_object *configJ, *entryJ; - - if(! apiHandle || ! halMgrData) - return -1; - - // Hugely hack to make all V2 AFB_DEBUG to work in fileutils - AFB_default = apiHandle; - - AFB_API_NOTICE(apiHandle, "Begining to create all APIs"); - - dirList = getenv("CONTROL_CONFIG_PATH"); - if(! dirList) - dirList = CONTROL_CONFIG_PATH; - - configJ = CtlConfigScan(dirList, "hal"); - if(! configJ) { - AFB_API_WARNING(apiHandle, "No hal-(binder-middle-name)*.json config file(s) found in %s, 4a-hal-manager will only works with external hal", dirList); - return 0; - } - - // We load 1st file others are just warnings - for(index = 0; index < (int) json_object_array_length(configJ); index++) { - entryJ = json_object_array_get_idx(configJ, index); - - if(wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullPath, "filename", &fileName)) { - AFB_API_ERROR(apiHandle, "HOOPs invalid JSON entry = %s", json_object_get_string(entryJ)); - return -2; - } - - strncpy(filePath, fullPath, sizeof(filePath) - 1); - strncat(filePath, "/", sizeof(filePath) - 1); - strncat(filePath, fileName, sizeof(filePath) - 1); - - if(InternalHalCreateApi(apiHandle, filePath, halMgrData) < 0) - status--; - } - - return status; -} \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.h b/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.h deleted file mode 100644 index fa878e2..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _INTERNALS_HAL_API_LOADER_INCLUDE_ -#define _INTERNALS_HAL_API_LOADER_INCLUDE_ - -#include - -#include - -#include "4a-hal-utilities-data.h" - -// Verbs that can be use to create api -int InternalHalCreateApi(afb_api_t apiHandle, char *path, struct HalMgrData *halMgrData); -int InternalHalCreateAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData); - -#endif /* _INTERNALS_HAL_API_LOADER_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-cb.c b/4a-hal/4a-internals-hal/4a-internals-hal-cb.c deleted file mode 100644 index 0102d8d..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-cb.c +++ /dev/null @@ -1,790 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include "4a-hal-utilities-data.h" - -#include "4a-internals-hal-cb.h" -#include "4a-internals-hal-alsacore-link.h" -#include "4a-internals-hal-mixer-link.h" -#include "4a-internals-hal-value-handler.h" - -/******************************************************************************* - * Internals HAL Event handler function * - ******************************************************************************/ - -void InternalHalDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ) -{ - int numid, idx = 0, cardidx; - - CtlConfigT *ctrlConfig; - CtlSourceT source; - - struct HalData *currentHalData; - struct InternalHalAlsaMapT *currentHalAlsaCtlsT; - - json_object *valuesJ, *normalizedValuesJ; - - AFB_API_DEBUG(apiHandle, "Evtname=%s [msg=%s]", evtLabel, json_object_get_string(eventJ)); - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - AFB_API_ERROR(apiHandle, "Can't get current internal hal controller config"); - return; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - AFB_API_WARNING(apiHandle, "Can't get current internal hal controller data"); - return; - } - - // Extract sound card index from event - while(evtLabel[idx] != '\0' && evtLabel[idx] != ':') - idx++; - - if(evtLabel[idx] != '\0' && - sscanf(&evtLabel[idx + 1], "%d", &cardidx) == 1 && - currentHalData->sndCardId == cardidx) { - if(wrap_json_unpack(eventJ, "{s:i s:o !}", "id", &numid, "val", &valuesJ)) { - AFB_API_ERROR(apiHandle, "Invalid Alsa Event label=%s value=%s", evtLabel, json_object_get_string(eventJ)); - return; - } - - currentHalAlsaCtlsT = currentHalData->internalHalData->alsaMapT; - - // Search for corresponding numid in halCtls, if found, launch callback (if available) - for(idx = 0; idx < currentHalAlsaCtlsT->ctlsCount; idx++) { - if(currentHalAlsaCtlsT->ctls[idx].ctl.numid == numid) { - if(currentHalAlsaCtlsT->ctls[idx].action) { - source.uid = currentHalAlsaCtlsT->ctls[idx].action->uid; - source.api = currentHalAlsaCtlsT->ctls[idx].action->api; - source.request = NULL; - - (void) ActionExecOne(&source, currentHalAlsaCtlsT->ctls[idx].action, valuesJ); - } - else { - AFB_API_NOTICE(apiHandle, - "The alsa control id '%i' is corresponding to a known control but without any action registered", - numid); - } - - if((! currentHalAlsaCtlsT->ctls[idx].alsaControlEvent) || - InternalHalConvertJsonValues(apiHandle, - ¤tHalAlsaCtlsT->ctls[idx].ctl.alsaCtlProperties, - valuesJ, - &normalizedValuesJ, - CONVERSION_ALSACORE_TO_NORMALIZED) || - (afb_event_push(currentHalAlsaCtlsT->ctls[idx].alsaControlEvent, normalizedValuesJ) < 0)) { - AFB_API_ERROR(apiHandle, - "Couldn't generate an event for known halmap %s (alsa control id %i)", - currentHalAlsaCtlsT->ctls[idx].uid, - currentHalAlsaCtlsT->ctls[idx].ctl.numid); - } - - return; - } - } - - AFB_API_WARNING(apiHandle, - "Alsacore event with an unrecognized numid: %i, evtname=%s [msg=%s]", - numid, - evtLabel, - json_object_get_string(eventJ)); - - return; - } - - AFB_API_INFO(apiHandle, - "Not an alsacore event '%s' [msg=%s]", - evtLabel, - json_object_get_string(eventJ)); - - CtrlDispatchApiEvent(apiHandle, evtLabel, eventJ); -} - -/******************************************************************************* - * Internals HAL - 'halmixer' section parsing/handling functions * - ******************************************************************************/ - -int InternalHalHalMixerConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *MixerJ) -{ - int err = 0; - - CtlConfigT *ctrlConfig; - struct HalData *currentHalData; - - if(! apiHandle || ! section) - return -1; - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) - return -2; - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) - return -3; - - if(MixerJ) { - if(json_object_is_type(MixerJ, json_type_object)) - currentHalData->internalHalData->halMixerJ = MixerJ; - else - return -4; - - if(wrap_json_unpack(MixerJ, "{s:s}", "mixerapi", ¤tHalData->internalHalData->mixerApiName)) - return -5; - - wrap_json_unpack(MixerJ, "{s?:s}", "prefix", ¤tHalData->internalHalData->prefix); - } - else if(currentHalData->status == HAL_STATUS_AVAILABLE) { - err = InternalHalAttachToMixer(apiHandle); - if(err) { - AFB_API_ERROR(apiHandle, "Error %i while attaching to mixer", err); - return -6; - } - } - - return 0; -} - -/******************************************************************************* - * Internals HAL - 'halmap' section parsing/handling functions * - ******************************************************************************/ - -int InternalHalProcessOneHalMapObject(afb_api_t apiHandle, struct InternalHalAlsaMap *alsaMap, json_object *AlsaMapJ) -{ - char *action = NULL, *typename = NULL; - - json_object *alsaJ = NULL, *createAlsaCtlJ = NULL; - - AFB_API_DEBUG(apiHandle, "AlsaMapJ=%s", json_object_get_string(AlsaMapJ)); - - if(wrap_json_unpack(AlsaMapJ, "{s:s s?:s s:o s?:s !}", - "uid", &alsaMap->uid, - "info", &alsaMap->info, - "alsa", &alsaJ, - "action", &action)) { - AFB_API_ERROR(apiHandle, "Parsing error, map should only contains [label]|[uid]|[tag]|[info]|[alsa]|[action] in:\n-- %s", json_object_get_string(AlsaMapJ)); - return -1; - } - - if(wrap_json_unpack(alsaJ, "{s?:s s?:i s?:i s?:o !}", - "name", &alsaMap->ctl.name, - "numid", &alsaMap->ctl.numid, - "value", &alsaMap->ctl.value, - "create", &createAlsaCtlJ)) { - AFB_API_ERROR(apiHandle, "Parsing error, alsa json should only contains [name]|[numid]||[value]|[create] in:\n-- %s", json_object_get_string(alsaJ)); - return -2; - } - - if(createAlsaCtlJ) { - alsaMap->ctl.alsaCtlCreation = &alsaMap->ctl.alsaCtlProperties; - - if(wrap_json_unpack(createAlsaCtlJ, - "{s:s s:i s:i s:i s:i !}", - "type", &typename, - "count", &alsaMap->ctl.alsaCtlCreation->count, - "minval", &alsaMap->ctl.alsaCtlCreation->minval, - "maxval", &alsaMap->ctl.alsaCtlCreation->maxval, - "step", &alsaMap->ctl.alsaCtlCreation->step)) { - AFB_API_ERROR(apiHandle, "Parsing error, alsa creation json should only contains [type]|[count]|[minval]|[maxval]|[step] in:\n-- %s", json_object_get_string(alsaJ)); - return -3; - } - - if(typename) { - alsaMap->ctl.alsaCtlCreation->type = InternalHalMapsAlsaTypeToEnum(typename); - if(alsaMap->ctl.alsaCtlCreation->type == SND_CTL_ELEM_TYPE_NONE) { - AFB_API_ERROR(apiHandle, "Couldn't get alsa type from string %s in:\n-- %s", typename, json_object_get_string(alsaJ)); - return -4; - } - } - - if(! alsaMap->ctl.name) - alsaMap->ctl.name = (char *) alsaMap->uid; - } - else if(alsaMap->ctl.name && alsaMap->ctl.numid > 0) { - AFB_API_ERROR(apiHandle, - "Can't have both a control name (%s) and a control uid (%i) in alsa object:\n-- %s", - alsaMap->ctl.name, - alsaMap->ctl.numid, - json_object_get_string(alsaJ)); - return -5; - } - else if(! alsaMap->ctl.name && alsaMap->ctl.numid <= 0) { - AFB_API_ERROR(apiHandle, - "Need at least a control name or a control uid in alsa object:\n-- %s", - json_object_get_string(alsaJ)); - return -6; - } - - if(action) - alsaMap->actionJ = AlsaMapJ; - - return 0; -} - -int InternalHalHandleOneHalMapObject(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaMap *alsaMap) -{ - int err; - - json_object *valueJ, *convertedValueJ = NULL; - - if(! (alsaMap->alsaControlEvent = afb_api_make_event(apiHandle, alsaMap->uid))) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to create event for current alsa control to load action using alsa object:\n-- %s", - json_object_get_string(alsaMap->actionJ)); - return -1; - } - - if(alsaMap->ctl.alsaCtlCreation) { - if(InternalHalCreateAlsaCtl(apiHandle, cardId, &alsaMap->ctl)) { - AFB_API_ERROR(apiHandle, "An error happened when trying to create a new alsa control"); - return -2; - } - } - else if(InternalHalUpdateAlsaCtlProperties(apiHandle, cardId, &alsaMap->ctl)) { - AFB_API_ERROR(apiHandle, "An error happened when trying to get existing alsa control info"); - return -3; - } - - if(alsaMap->ctl.value) { - // TBD JAI : handle alsa controls type - valueJ = json_object_new_int(alsaMap->ctl.value); - err = 0; - - if(InternalHalConvertJsonValues(apiHandle, &alsaMap->ctl.alsaCtlProperties, valueJ, &convertedValueJ, CONVERSION_NORMALIZED_TO_ALSACORE)) { - AFB_API_ERROR(apiHandle, "Error when trying to convert initiate value json '%s'", json_object_get_string(valueJ)); - err = -4; - } - else if(InternalHalSetAlsaCtlValue(apiHandle, cardId, alsaMap->ctl.numid, convertedValueJ)) { - AFB_API_ERROR(apiHandle, - "Error while trying to set initial value on alsa control %i, device '%s', value '%s'", - alsaMap->ctl.numid, - cardId, - json_object_get_string(valueJ)); - err = -5; - } - - json_object_put(valueJ); - - if(convertedValueJ) - json_object_put(convertedValueJ); - - if(err) - return err; - } - - if(alsaMap->actionJ) { - alsaMap->action = calloc(1, sizeof(CtlActionT)); - if(ActionLoadOne(apiHandle, alsaMap->action, alsaMap->actionJ, 0)) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to load action using alsa object:\n-- %s", - json_object_get_string(alsaMap->actionJ)); - return -6; - } - } - - if(afb_api_add_verb(apiHandle, alsaMap->uid, alsaMap->info, InternalHalActionOnAlsaCtl, (void *) alsaMap, NULL, 0, 0)) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to create verb for current alsa control to load action using alsa object:\n-- %s", - json_object_get_string(alsaMap->actionJ)); - return -7; - } - - return 0; -} - -int InternalHalProcessAllHalMap(afb_api_t apiHandle, json_object *AlsaMapJ, struct InternalHalAlsaMapT *currentInternalHalAlsaMapT) -{ - int idx, err = 0; - - struct InternalHalAlsaMap *ctlMaps; - - json_type alsaMapType; - - alsaMapType = json_object_get_type(AlsaMapJ); - switch(alsaMapType) { - case json_type_array: - currentInternalHalAlsaMapT->ctlsCount = (unsigned int) json_object_array_length(AlsaMapJ); - break; - - case json_type_object: - currentInternalHalAlsaMapT->ctlsCount = 1; - break; - - default: - currentInternalHalAlsaMapT->ctlsCount = 0; - currentInternalHalAlsaMapT->ctls = NULL; - AFB_API_WARNING(apiHandle, "Couldn't get content of 'halmap' section in : '%s'", json_object_get_string(AlsaMapJ)); - return -1; - } - - ctlMaps = calloc(currentInternalHalAlsaMapT->ctlsCount, sizeof(struct InternalHalAlsaMap)); - - for(idx = 0; idx < currentInternalHalAlsaMapT->ctlsCount; idx++) - err += InternalHalProcessOneHalMapObject(apiHandle, &ctlMaps[idx], alsaMapType == json_type_array ? json_object_array_get_idx(AlsaMapJ, idx) : AlsaMapJ); - - currentInternalHalAlsaMapT->ctls = ctlMaps; - - return err; -} - -int InternalHalHandleAllHalMap(afb_api_t apiHandle, int sndCardId, struct InternalHalAlsaMapT *currentInternalHalAlsaMapT) -{ - int idx, err = 0; - - char cardIdString[6]; - - snprintf(cardIdString, 6, "hw:%i", sndCardId); - - InternalHalSubscribeToAlsaCardEvent(apiHandle, cardIdString); - - for(idx = 0; idx < currentInternalHalAlsaMapT->ctlsCount; idx++) - err += InternalHalHandleOneHalMapObject(apiHandle, cardIdString, ¤tInternalHalAlsaMapT->ctls[idx]); - - return err; -} - -int InternalHalHalMapConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *AlsaMapJ) -{ - CtlConfigT *ctrlConfig; - struct HalData *currentHalData; - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) - return -1; - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) - return -2; - - if(AlsaMapJ) { - currentHalData->internalHalData->alsaMapT = calloc(1, sizeof(struct InternalHalAlsaMapT)); - - if(InternalHalProcessAllHalMap(apiHandle, AlsaMapJ, currentHalData->internalHalData->alsaMapT)) { - AFB_API_ERROR(apiHandle, "Failed to process 'halmap' section"); - return -3; - } - } - else if(currentHalData->status == HAL_STATUS_UNAVAILABLE) { - AFB_API_WARNING(apiHandle, "Hal is unavailable, 'halmap' section data can't be handle"); - return 1; - } - else if(currentHalData->sndCardId < 0) { - AFB_API_ERROR(apiHandle, "Hal alsa card id is not valid, 'halmap' section data can't be handle"); - return -6; - } - else if(! currentHalData->internalHalData->alsaMapT) { - AFB_API_WARNING(apiHandle, "'halmap' section data is empty"); - return 2; - } - else if(! (currentHalData->internalHalData->alsaMapT->ctlsCount > 0)) { - AFB_API_WARNING(apiHandle, "No alsa controls defined in 'halmap' section"); - return 3; - } - else if(InternalHalHandleAllHalMap(apiHandle, currentHalData->sndCardId, currentHalData->internalHalData->alsaMapT)) { - AFB_API_ERROR(apiHandle, "Failed to handle 'halmap' section"); - return -9; - } - - return 0; -} - -/******************************************************************************* - * Internals HAL verbs functions * - ******************************************************************************/ - -json_object *InternalHalGetJsonArrayForMixerDataTable(afb_api_t apiHandle, - struct InternalHalMixerData **mixerDataList, - enum MixerDataType dataType) -{ - json_object *mixerDataArrayJ, *currentMixerDataJ; - - struct InternalHalMixerData *currentMixerData; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Api handle is not valid"); - return NULL; - } - - mixerDataArrayJ = json_object_new_array(); - if(! mixerDataArrayJ) { - AFB_API_ERROR(apiHandle, "Can't generate json mixer data array"); - return NULL; - } - - currentMixerData = *mixerDataList; - - while(currentMixerData) { - switch(dataType) { - case MIXER_DATA_STREAMS: - wrap_json_pack(¤tMixerDataJ, - "{s:s s:s}", - "name", currentMixerData->verb, - "cardId", currentMixerData->streamCardId); - break; - - case MIXER_DATA_PLAYBACKS: - case MIXER_DATA_CAPTURES : - wrap_json_pack(¤tMixerDataJ, - "{s:s s:s}", - "name", currentMixerData->verb, - "mixer-name", currentMixerData->verbToCall, - "uid", currentMixerData->streamCardId ? currentMixerData->streamCardId : "none"); - break; - - default: - json_object_put(mixerDataArrayJ); - return NULL; - } - json_object_array_add(mixerDataArrayJ, currentMixerDataJ); - - currentMixerData = currentMixerData->next; - } - - return mixerDataArrayJ; -} - -json_object *InternalHalGetJsonArrayForControls(afb_api_t apiHandle, struct InternalHalAlsaMapT *currentAlsaMapDataT) -{ - unsigned int idx; - - json_object *alsaMapDataArray, *currentAlsaMapData; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); - return NULL; - } - - if(! currentAlsaMapDataT) { - AFB_API_ERROR(apiHandle, "Can't get Alsa map data table to handle"); - return NULL; - } - - if(! (alsaMapDataArray = json_object_new_array())) { - AFB_API_ERROR(apiHandle, "Can't generate json mixer data array"); - return NULL; - } - - for(idx = 0; idx < currentAlsaMapDataT->ctlsCount; idx++) { - wrap_json_pack(¤tAlsaMapData, - "{s:s s:s}", - "name", currentAlsaMapDataT->ctls[idx].uid, - "info", currentAlsaMapDataT->ctls[idx].info ? currentAlsaMapDataT->ctls[idx].info : "none"); - - json_object_array_add(alsaMapDataArray, currentAlsaMapData); - } - - return alsaMapDataArray; -} - -void InternalHalInfo(afb_req_t request) -{ - char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; - - afb_api_t apiHandle; - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - - json_object *requestJson, *toReturnJ = NULL, *requestAnswer, *streamsArray, *playbacksArray, *capturesArray, *controlsArray; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); - return; - } - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - afb_req_fail(request, "hal_controller_config", "Can't get current internal hal controller config"); - return; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - afb_req_fail(request, "hal_controller_data", "Can't get current internal hal controller data"); - return; - } - - if(! (requestJson = afb_req_json(request))) { - AFB_REQ_NOTICE(request, "Can't get request json"); - } - else if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) { - apiToCall = currentHalData->internalHalData->mixerApiName; - if(! apiToCall) { - afb_req_fail(request, "mixer_api", "Can't get mixer api"); - return; - } - - if(InternalHalGetInfoFromMixer(apiHandle, apiToCall, requestJson, &toReturnJ, &returnedError, &returnedInfo)) { - afb_req_fail_f(request, - "mixer_info", - "Call to mixer info verb didn't succeed with status '%s' and info '%s'", - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - return; - } - - afb_req_success(request, toReturnJ, "Mixer requested data"); - return; - } - - streamsArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, - ¤tHalData->internalHalData->streamsData, - MIXER_DATA_STREAMS); - if(! streamsArray) { - afb_req_fail(request, "streams_data", "Didn't succeed to generate streams data array"); - return; - } - - playbacksArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, - ¤tHalData->internalHalData->playbacksData, - MIXER_DATA_PLAYBACKS); - if(! playbacksArray) { - afb_req_fail(request, "playbacks_data", "Didn't succeed to generate playbacks data array"); - return; - } - - capturesArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, - ¤tHalData->internalHalData->capturesData, - MIXER_DATA_CAPTURES); - if(! capturesArray) { - afb_req_fail(request, "captures_data", "Didn't succeed to generate captures data array"); - return; - } - - controlsArray = InternalHalGetJsonArrayForControls(apiHandle, - currentHalData->internalHalData->alsaMapT); - if(! controlsArray) { - afb_req_fail(request, "controls_data", "Didn't succeed to generate controls data array"); - return; - } - - wrap_json_pack(&requestAnswer, - "{s:o s:o s:o s:o}", - "streams", streamsArray, - "playbacks", playbacksArray, - "captures", capturesArray, - "controls", controlsArray); - - afb_req_success(request, requestAnswer, "Requested data"); -} - -void InternalHalSubscribeUnsubscribe(afb_req_t request, enum SubscribeUnsubscribeType subscribeUnsubscribeType) -{ - int arrayIdx, searchIdx, count, subscriptionFound, subscriptionDoneNb = 0; - - char *currentSubscriptionString; - - afb_api_t apiHandle; - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData; - struct InternalHalMixerData *currentStreamData; - struct InternalHalAlsaMapT *InternalHalAlsaMapT; - - json_object *requestJson, *requestedSubscriptionsJ, *requestedSubscriptionJ = NULL; - json_type requestJsonType; - - if(! (apiHandle = afb_req_get_api(request))) { - afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); - return; - } - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - afb_req_fail(request, "hal_controller_config", "Can't get current internal hal controller config"); - return; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - afb_req_fail(request, "hal_controller_data", "Can't get current internal hal controller data"); - return; - } - - if(! currentHalData->internalHalData) { - afb_req_fail(request, "hal_controller_data", "Current internal hal data is not valid"); - return; - } - - InternalHalAlsaMapT = currentHalData->internalHalData->alsaMapT; - - if(! (requestJson = afb_req_json(request))) { - afb_req_fail(request, "request_json", "Can't get request json"); - return; - } - - if(wrap_json_unpack(requestJson, "{s:o}", "events", &requestedSubscriptionsJ)) { - afb_req_fail(request, "request_json", "Request json invalid"); - return; - } - - requestJsonType = json_object_get_type(requestedSubscriptionsJ); - switch(requestJsonType) { - case json_type_string: - count = 1; - requestedSubscriptionJ = requestedSubscriptionsJ; - break; - - case json_type_array: - count = (int) json_object_array_length(requestedSubscriptionsJ); - break; - - default: - afb_req_fail(request, "request_json", "Request json invalid"); - return; - } - - for(arrayIdx = 0; arrayIdx < count; arrayIdx++) { - if(requestJsonType == json_type_array) { - requestedSubscriptionJ = json_object_array_get_idx(requestedSubscriptionsJ, arrayIdx); - if(! json_object_is_type(requestedSubscriptionJ, json_type_string)) { - afb_req_fail_f(request, "request_json", "Request json number %i in array invalid", arrayIdx); - return; - } - } - - subscriptionFound = 0; - currentSubscriptionString = (char *) json_object_get_string(requestedSubscriptionJ); - - if(! strcasecmp(currentSubscriptionString, HAL_STREAM_UPDATES_EVENT_NAME)) { - if(currentHalData->internalHalData->streamUpdates && - subscribeUnsubscribeType == SUBSCRIPTION && - afb_req_subscribe(request, currentHalData->internalHalData->streamUpdates)) { - afb_req_fail_f(request, - "request_stream_list_updates_event", - "Error while trying to subscribe to stream list updates event"); - return; - } - else if(currentHalData->internalHalData->streamUpdates && - subscribeUnsubscribeType == UNSUBSCRIPTION && - afb_req_unsubscribe(request, currentHalData->internalHalData->streamUpdates)) { - afb_req_fail_f(request, - "request_stream_list_updates_event", - "Error while trying to unsubscribe to stream list updates event"); - return; - } - - subscriptionFound = 1; - subscriptionDoneNb++; - } - - currentStreamData = currentHalData->internalHalData->streamsData; - while(currentStreamData && - (! subscriptionFound)) { - if(! strcasecmp(currentSubscriptionString, currentStreamData->verb)) { - if(currentStreamData->event && - subscribeUnsubscribeType == SUBSCRIPTION && - afb_req_subscribe(request, currentStreamData->event)) { - afb_req_fail_f(request, - "request_stream_event", - "Error while trying to subscribe to %s stream events", - currentStreamData->verb); - return; - } - else if(currentStreamData->event && - subscribeUnsubscribeType == UNSUBSCRIPTION && - afb_req_unsubscribe(request, currentStreamData->event)) { - afb_req_fail_f(request, - "request_stream_event", - "Error while trying to unsubscribe to %s stream events", - currentStreamData->verb); - return; - } - - subscriptionFound = 1; - subscriptionDoneNb++; - - break; - } - - currentStreamData = currentStreamData->next; - } - - searchIdx = 0; - while((searchIdx < (InternalHalAlsaMapT ? InternalHalAlsaMapT->ctlsCount : 0)) && - (! subscriptionFound)) { - if(! strcasecmp(currentSubscriptionString, InternalHalAlsaMapT->ctls[searchIdx].uid)) { - if(InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent && - subscribeUnsubscribeType == SUBSCRIPTION && - afb_req_subscribe(request, InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent)) { - afb_req_fail_f(request, - "request_control_event", - "Error while trying to subscribe to %s halmap controls events", - InternalHalAlsaMapT->ctls[searchIdx].uid); - return; - } - else if(InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent && - subscribeUnsubscribeType == UNSUBSCRIPTION && - afb_req_unsubscribe(request, InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent)) { - afb_req_fail_f(request, - "request_stream_event", - "Error while trying to unsubscribe to %s halmap controls events", - InternalHalAlsaMapT->ctls[searchIdx].uid); - return; - } - - subscriptionFound = 1; - subscriptionDoneNb++; - - break; - } - - searchIdx++; - } - } - - if(subscriptionDoneNb == 0) - afb_req_fail_f(request, - "events_not_found", - "%s failed, event(s) were not found", - subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription"); - if(subscriptionDoneNb == count) - afb_req_success_f(request, - json_object_new_int(subscriptionDoneNb), - "%s succeed for all the %i events requested", - subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", - subscriptionDoneNb); - else if(subscriptionDoneNb < count) - afb_req_success_f(request, - json_object_new_int(subscriptionDoneNb), - "%s succeed but only to %i events requested out of %i", - subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", - subscriptionDoneNb, - count); - else - afb_req_success_f(request, - json_object_new_int(subscriptionDoneNb), - "%s succeed but to more events than requested (%i out of %i)", - subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", - subscriptionDoneNb, - count); -} - -void InternalHalSubscribe(afb_req_t request) -{ - InternalHalSubscribeUnsubscribe(request, SUBSCRIPTION); -} - -void InternalHalUnsubscribe(afb_req_t request) -{ - InternalHalSubscribeUnsubscribe(request, UNSUBSCRIPTION); -} diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-cb.h b/4a-hal/4a-internals-hal/4a-internals-hal-cb.h deleted file mode 100644 index ff35656..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-cb.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _INTERNALS_HAL_CB_INCLUDE_ -#define _INTERNALS_HAL_CB_INCLUDE_ - -#include - -#include - -#include - -// Enum for the type of subscription/subscription -enum SubscribeUnsubscribeType { - SUBSCRIPTION = 1, - UNSUBSCRIPTION = 2 -}; - -// Internals HAL event handler function -void InternalHalDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ); - -// Internals HAL sections parsing functions -int InternalHalHalMixerConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *MixerJ); -int InternalHalHalMapConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *AlsaMapJ); - -// Internals HAL verbs functions -void InternalHalInfo(afb_req_t request); -void InternalHalSubscribe(afb_req_t request); -void InternalHalUnsubscribe(afb_req_t request); - -#endif /* _HALMGR_CB_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c b/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c deleted file mode 100644 index 95e9099..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include "4a-hal-utilities-data.h" - -#include "4a-hal-utilities-hal-streams-handler.h" -#include "4a-hal-utilities-verbs-loader.h" - -#include "../4a-hal-manager/4a-hal-manager.h" - -#include "4a-internals-hal-mixer-link.h" -#include "4a-internals-hal-cb.h" - -/******************************************************************************* - * Internals HAL handle mixer calls functions * - ******************************************************************************/ - -int InternalHalHandleMixerData(afb_api_t apiHandle, - struct InternalHalMixerData **mixerDataList, - json_object *currentDataJ, - enum MixerDataType dataType) -{ - int idx, mixerDataNb, verbStart, size; - int err = (int) MIXER_NO_ERROR; - - char *currentDataVerbName, *currentStreamCardId; - - json_type currentDataType; - json_object *currentJ; - - struct InternalHalMixerData *currentMixerData; - - currentDataType = json_object_get_type(currentDataJ); - switch(currentDataType) { - case json_type_object: - mixerDataNb = 1; - break; - case json_type_array: - mixerDataNb = (unsigned int) json_object_array_length(currentDataJ); - break; - default: - mixerDataNb = 0; - AFB_API_ERROR(apiHandle, "No data returned"); - return (int) MIXER_ERROR_DATA_EMPTY; - } - - for(idx = 0; idx < mixerDataNb; idx++) { - if(currentDataType == json_type_array) - currentJ = json_object_array_get_idx(currentDataJ, (int) idx); - else - currentJ = currentDataJ; - - if(wrap_json_unpack(currentJ, "{s:s}", "verb", ¤tDataVerbName)) { - AFB_API_ERROR(apiHandle, "Can't find verb in current data object"); - err += (int) MIXER_ERROR_DATA_NAME_UNAVAILABLE; - } - else if(dataType == MIXER_DATA_STREAMS && wrap_json_unpack(currentJ, "{s:s}", "alsa", ¤tStreamCardId)) { - AFB_API_ERROR(apiHandle, "Can't find card id in current data object"); - err += (int) MIXER_ERROR_DATA_CARDID_UNAVAILABLE; - } - else { - switch(dataType) { - case MIXER_DATA_STREAMS: - size = (int) strlen(currentDataVerbName); - for(verbStart = 0; verbStart < size; verbStart++) { - if(currentDataVerbName[verbStart] == '#') { - verbStart++; - break; - } - } - - if(verbStart == size) - verbStart = 0; - - if(! HalUtlAddStreamDataAndCreateStreamVerb(apiHandle, - ¤tDataVerbName[verbStart], - currentDataVerbName, - currentStreamCardId)) { - AFB_API_ERROR(apiHandle, - "Error while adding stream '%s'", - currentDataVerbName); - err += (int) MIXER_ERROR_STREAM_NOT_ADDED; - } - - break; - - case MIXER_DATA_PLAYBACKS: - case MIXER_DATA_CAPTURES: - currentMixerData = HalUtlAddMixerDataToMixerDataList(mixerDataList); - - currentMixerData->verb = strdup((dataType == MIXER_DATA_PLAYBACKS) ? HAL_PLAYBACK_ID : HAL_CAPTURE_ID); - currentMixerData->verbToCall = strdup(currentDataVerbName); - - if((! currentMixerData->verb) || - (! currentMixerData->verbToCall)) { - HalUtlRemoveSelectedMixerData(mixerDataList, currentMixerData); - err += (int) MIXER_ERROR_STREAM_ALLOCATION_FAILED; - } - break; - - default: - break; - } - } - } - - if(dataType == MIXER_DATA_PLAYBACKS) { - if(afb_api_add_verb(apiHandle, - HAL_PLAYBACK_ID, - "Playback action transferred to mixer", - HalUtlActionOnPlayback, - (void *) *mixerDataList, - NULL, - 0, - 0)) { - AFB_API_ERROR(apiHandle, "Error while creating verb for playbacks : '%s'", HAL_PLAYBACK_ID); - err += (int) MIXER_ERROR_PLAYBACK_VERB_NOT_CREATED; - } - } - - if(dataType == MIXER_DATA_CAPTURES) { - if(afb_api_add_verb(apiHandle, - HAL_CAPTURE_ID, - "Capture action transferred to mixer", - HalUtlActionOnCapture, - (void *) *mixerDataList, - NULL, - 0, - 0)) { - AFB_API_ERROR(apiHandle, "Error while creating verb for captures : '%s'", HAL_CAPTURE_ID); - err += (int) MIXER_ERROR_CAPTURE_VERB_NOT_CREATED; - } - } - - return err; -} - -int InternalHalHandleMixerAttachResponse(afb_api_t apiHandle, struct InternalHalData *currentHalSpecificData, json_object *mixerResponseJ) -{ - int err = (int) MIXER_NO_ERROR; - - json_object *mixerStreamsJ = NULL, *mixerPlaybacksJ = NULL, *mixerCapturesJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); - return (int) MIXER_ERROR_API_UNAVAILABLE; - } - - if(wrap_json_unpack(mixerResponseJ, "{s?:o s?:o s?:o}", "streams", &mixerStreamsJ, "playbacks", &mixerPlaybacksJ, "captures", &mixerCapturesJ)) { - AFB_API_ERROR(apiHandle, "Can't get streams|playbacks|captures object in '%s'", json_object_get_string(mixerResponseJ)); - return (int) MIXER_ERROR_DATA_UNAVAILABLE; - } - - if(mixerStreamsJ) { - err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->streamsData, mixerStreamsJ, MIXER_DATA_STREAMS); - if(err) - AFB_API_ERROR(apiHandle, "Error during handling response mixer streams data '%s'", json_object_get_string(mixerStreamsJ)); - } - - if(mixerPlaybacksJ) { - err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->playbacksData, mixerPlaybacksJ, MIXER_DATA_PLAYBACKS); - if(err) - AFB_API_ERROR(apiHandle, "Error during handling response mixer playbacks data '%s'", json_object_get_string(mixerPlaybacksJ)); - } - - if(mixerCapturesJ) { - err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->capturesData, mixerCapturesJ, MIXER_DATA_CAPTURES); - if(err) - AFB_API_ERROR(apiHandle, "Error during handling response mixer captures data '%s'", json_object_get_string(mixerCapturesJ)); - } - - if(! currentHalSpecificData->streamsData) { - AFB_API_WARNING(apiHandle, "No stream detected in mixer response, %s verb won't be created", HAL_ALL_STREAMS_VERB); - } - else if(afb_api_add_verb(apiHandle, - HAL_ALL_STREAMS_VERB, - "Send a stream action on all streams", - HalUtlActionOnAllStream, - (void *) currentHalSpecificData->streamsData, - NULL, - 0, - 0)) { - AFB_API_ERROR(apiHandle, "Error while creating verb for all streams : '%s'", HAL_ALL_STREAMS_VERB); - return (int) MIXER_ERROR_ALL_STREAMS_VERB_NOT_CREATED; - } - - return err; -} - -int InternalHalAttachToMixer(afb_api_t apiHandle) -{ - int err = 0, mixerError; - - char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; - - CtlConfigT *ctrlConfig; - - struct HalData *currentHalData, *concurentHalData = NULL; - - json_object *responseJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); - return -1; - } - - if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { - AFB_API_ERROR(apiHandle, "Can't get current hal controller config"); - return -2; - } - - currentHalData = (struct HalData *) getExternalData(ctrlConfig); - if(! currentHalData) { - AFB_API_ERROR(apiHandle, "Can't get current hal controller data"); - return -3; - } - - switch(currentHalData->status) { - case HAL_STATUS_UNAVAILABLE: - AFB_API_ERROR(apiHandle, "Seems that the hal corresponding card was not found by alsacore at startup"); - return -4; - - case HAL_STATUS_READY: - AFB_API_NOTICE(apiHandle, "Seems that the hal mixer is already initialized"); - return 1; - - case HAL_STATUS_AVAILABLE: - break; - } - - concurentHalData = HalUtlSearchReadyHalDataByCardId(HalMngGetHalDataList(), currentHalData->sndCardId); - if(concurentHalData) { - AFB_API_ERROR(apiHandle, - "Trying to attach mixer for hal '%s' but the alsa device %i is already in use with mixer by hal '%s'", - currentHalData->apiName, - currentHalData->sndCardId, - concurentHalData->apiName); - return -5; - } - - apiToCall = currentHalData->internalHalData->mixerApiName; - if(! apiToCall) { - AFB_API_ERROR(apiHandle, "Can't get mixer api"); - return -6; - } - - if(afb_api_call_sync(apiHandle, - apiToCall, - MIXER_ATTACH_VERB, - json_object_get(currentHalData->internalHalData->halMixerJ), - &responseJ, - &returnedError, - &returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - MIXER_ATTACH_VERB, - apiToCall, - returnedError ? returnedError : "not returned", - returnedInfo ? returnedInfo : "not returned"); - err = -7; - } - else if(! responseJ) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but no response was returned", - MIXER_ATTACH_VERB, - apiToCall); - err = -8; - } - else { - mixerError = InternalHalHandleMixerAttachResponse(apiHandle, currentHalData->internalHalData, responseJ); - if(mixerError != (int) MIXER_NO_ERROR) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but this warning was risen by response decoder : %i '%s'", - MIXER_ATTACH_VERB, - apiToCall, - mixerError, - json_object_get_string(responseJ)); - err = -9; - } - else { - AFB_API_NOTICE(apiHandle, - "Seems that %s call to api %s succeed with no warning raised : '%s'", - MIXER_ATTACH_VERB, - apiToCall, - json_object_get_string(responseJ)); - currentHalData->status = HAL_STATUS_READY; - } - } - - if(responseJ) - json_object_put(responseJ); - - free(returnedError); - free(returnedInfo); - - return err; -} - -int InternalHalGetInfoFromMixer(afb_api_t apiHandle, - char *apiToCall, - json_object *requestJson, - json_object **toReturnJ, - char **returnedError, - char **returnedInfo) -{ - json_object *responseJ = NULL; - - if(! apiHandle) { - AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); - return -1; - } - - if(! apiToCall) { - AFB_API_ERROR(apiHandle, "Can't get mixer api"); - return -2; - } - - if(! requestJson) { - AFB_API_ERROR(apiHandle, "Can't get request json"); - return -3; - } - - if(*returnedError || *returnedInfo) { - AFB_API_ERROR(apiHandle, "'returnedError' and 'returnedInfo' strings should be empty and set to 'NULL'"); - return -4; - } - - if(*toReturnJ) { - AFB_API_ERROR(apiHandle, "'toReturnJ' should be empty and set to 'NULL'"); - return -5; - } - - if(afb_api_call_sync(apiHandle, - apiToCall, - MIXER_INFO_VERB, - json_object_get(requestJson), - &responseJ, - returnedError, - returnedInfo)) { - AFB_API_ERROR(apiHandle, - "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", - apiToCall, - MIXER_INFO_VERB, - *returnedError ? *returnedError : "not returned", - *returnedInfo ? *returnedInfo : "not returned"); - return -6; - } - else if(! responseJ) { - AFB_API_ERROR(apiHandle, - "Seems that %s call to api %s succeed but no response was returned", - MIXER_INFO_VERB, - apiToCall); - json_object_put(responseJ); - return -7; - } - else { - AFB_API_NOTICE(apiHandle, - "Seems that %s call to api %s succeed with no warning raised : '%s'", - MIXER_INFO_VERB, - apiToCall, - json_object_get_string(responseJ)); - *toReturnJ = responseJ; - } - - return 0; -} \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.h b/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.h deleted file mode 100644 index 6c1f827..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ -#define _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ - -#include - -#include - -#include - -#include - -#include "4a-hal-utilities-data.h" - -#define MIXER_ATTACH_VERB "attach" -#define MIXER_INFO_VERB "info" - -#define HAL_PLAYBACK_ID "playback" -#define HAL_CAPTURE_ID "capture" - -#define HAL_ALL_STREAMS_VERB "all-streams" - -// Enum for the type of object sent back by the mixer -enum MixerDataType { - MIXER_DATA_STREAMS = 1, - MIXER_DATA_PLAYBACKS = 2, - MIXER_DATA_CAPTURES = 3 -}; - -// Enum for the type of error detected -enum MixerStatus { - MIXER_NO_ERROR=0, - MIXER_ERROR_API_UNAVAILABLE=-1, - MIXER_ERROR_DATA_UNAVAILABLE=-2, - MIXER_ERROR_DATA_EMPTY =-3, - MIXER_ERROR_PLAYBACK_VERB_NOT_CREATED =-4, - MIXER_ERROR_CAPTURE_VERB_NOT_CREATED =-5, - MIXER_ERROR_ALL_STREAMS_VERB_NOT_CREATED =-6, - MIXER_ERROR_DATA_NAME_UNAVAILABLE=-10, - MIXER_ERROR_DATA_CARDID_UNAVAILABLE=-100, - MIXER_ERROR_STREAM_NOT_ADDED =-1000, - MIXER_ERROR_STREAM_ALLOCATION_FAILED =-10000 -}; - -// Internals HAL handle mixer calls functions -int InternalHalAttachToMixer(afb_api_t apiHandle); -int InternalHalGetInfoFromMixer(afb_api_t apiHandle, - char *apiToCall, - json_object *requestJson, - json_object **toReturnJ, - char **returnedError, - char **returnedInfo); - -#endif /* _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c b/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c deleted file mode 100644 index 64083a9..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 - -#include - -#include - -#include "4a-internals-hal-value-handler.h" -#include "4a-internals-hal-alsacore-link.h" - -/******************************************************************************* - * Simple conversion value to/from percentage functions * - ******************************************************************************/ - -int InternalHalConvertValueToPercentage(double val, double min, double max) -{ - double range; - - range = max - min; - if(range <= 0) - return -INT_MAX; - - val -= min; - - return (int) round(val / range * 100); -} - -int InternalHalConvertPercentageToValue(int percentage, int min, int max) -{ - int range; - - range = max - min; - if(range <= 0) - return -INT_MAX; - - return (int) round((double) percentage * (double) range * 0.01 + (double) min); -} - -/******************************************************************************* - * Convert json object from percentage to value * - ******************************************************************************/ - -int InternalHalConvertJsonValueForIntegerControl(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *toConvertJ, - json_object **ConvertedJ, - enum ConversionType requestedConversion) -{ - int initialValue, convertedValue; - - if(! json_object_is_type(toConvertJ, json_type_int)) { - AFB_API_ERROR(apiHandle, - "Can't convert json value, unrecognized json format (must be an integer) : '%s'", - json_object_get_string(toConvertJ)); - return -1; - } - - initialValue = json_object_get_int(toConvertJ); - - switch(requestedConversion) { - case CONVERSION_NORMALIZED_TO_ALSACORE: - if(initialValue < 0 || initialValue > 100) { - AFB_API_ERROR(apiHandle, - "Cannot convert '%i' value, value should be between 0 and 100 ('%s')", - initialValue, - json_object_get_string(toConvertJ)); - return -2; - } - - convertedValue = InternalHalConvertPercentageToValue(initialValue, - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - if(convertedValue == -INT_MAX) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to convert %i (using min %i et max %i)", - initialValue, - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - return -3; - } - - if(alsaCtlProperties->step) { - // Round value to the nearest step - convertedValue = (int) round((double) convertedValue / (double) alsaCtlProperties->step); - convertedValue *= alsaCtlProperties->step; - } - break; - - case CONVERSION_ALSACORE_TO_NORMALIZED: - convertedValue = InternalHalConvertValueToPercentage(initialValue, - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - if(convertedValue == -INT_MAX) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to convert %i (using min %i et max %i)", - initialValue, - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - return -4; - } - - break; - - default: - AFB_API_ERROR(apiHandle, - "Can't convert '%i' value, unrecognized conversion type : '%i'", - initialValue, - (int) requestedConversion); - *ConvertedJ = NULL; - return -5; - } - - *ConvertedJ = json_object_new_int(convertedValue); - - return 0; -} - -int InternalHalConvertJsonValueForBooleanControl(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *toConvertJ, - json_object **ConvertedJ, - enum ConversionType requestedConversion) -{ - int initialValue; - - switch(json_object_get_type(toConvertJ)) { - case json_type_int: - initialValue = json_object_get_int(toConvertJ); - break; - - case json_type_boolean: - initialValue = json_object_get_boolean(toConvertJ); - break; - - default: - AFB_API_ERROR(apiHandle, - "Can't convert json value, unrecognized format (must be an integer or a boolean) : '%s'", - json_object_get_string(toConvertJ)); - return -1; - } - - if(initialValue < 0 || initialValue > 1) { - AFB_API_ERROR(apiHandle, - "Cannot convert '%i' value, value should be 0 or 1 ('%s')", - initialValue, - json_object_get_string(toConvertJ)); - return -2; - } - - switch(requestedConversion) { - case CONVERSION_NORMALIZED_TO_ALSACORE: - *ConvertedJ = json_object_new_int(initialValue); - break; - - case CONVERSION_ALSACORE_TO_NORMALIZED: - *ConvertedJ = json_object_new_boolean(initialValue); - break; - - default: - AFB_API_ERROR(apiHandle, - "Can't convert '%i' value, unrecognized conversion type : '%i'", - initialValue, - (int) requestedConversion); - *ConvertedJ = NULL; - return -3; - } - - return 0; -} - -int InternalHalConvertJsonValues(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *toConvertJ, - json_object **ConvertedJ, - enum ConversionType requestedConversion) -{ - int conversionError = 0, idx, count; - - json_type toConvertType; - json_object *toConvertObjectJ, *convertedValueJ, *convertedArrayJ; - - *ConvertedJ = NULL; - - toConvertType = json_object_get_type(toConvertJ); - count = (toConvertType == json_type_array) ? (int) json_object_array_length(toConvertJ) : 1; - - convertedArrayJ = json_object_new_array(); - - for(idx = 0; idx < count; idx++) { - if(toConvertType == json_type_array) - toConvertObjectJ = json_object_array_get_idx(toConvertJ, idx); - else - toConvertObjectJ = toConvertJ; - - switch(alsaCtlProperties->type) { - case SND_CTL_ELEM_TYPE_INTEGER: - case SND_CTL_ELEM_TYPE_INTEGER64: - conversionError = InternalHalConvertJsonValueForIntegerControl(apiHandle, - alsaCtlProperties, - toConvertObjectJ, - &convertedValueJ, - requestedConversion); - if(conversionError) { - AFB_API_ERROR(apiHandle, - "Error %i happened in when trying to convert index %i for integer control ('%s')", - conversionError, - idx, - json_object_get_string(toConvertObjectJ)); - json_object_put(convertedArrayJ); - return -(idx + 1); - } - break; - - case SND_CTL_ELEM_TYPE_BOOLEAN: - conversionError = InternalHalConvertJsonValueForBooleanControl(apiHandle, - alsaCtlProperties, - toConvertObjectJ, - &convertedValueJ, - requestedConversion); - if(conversionError) { - AFB_API_ERROR(apiHandle, - "Error %i happened in when trying to convert index %i for boolean control ('%s')", - conversionError, - idx, - json_object_get_string(toConvertObjectJ)); - json_object_put(convertedArrayJ); - return -(idx + 1); - } - break; - - default: - AFB_API_ERROR(apiHandle, - "Conversion not handle for the alsa control type %i", - (int) alsaCtlProperties->type); - json_object_put(convertedArrayJ); - return -(idx + 1); - } - - json_object_array_put_idx(convertedArrayJ, idx, convertedValueJ); - } - - *ConvertedJ = convertedArrayJ; - - return 0; -} - -int InternalHalChangePreviousValuesUsingJson(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *requestedPercentageVariationJ, - json_object *previousControlValuesJ, - json_object **ChangedJ) -{ - int requestedPercentageVariation, requestedVariation, toChangeValue, changedValue, idx, count; - - char *requestedPercentageVariationString, *conversionEnd; - - json_object *toChangeObjectJ, *changedArrayJ; - - *ChangedJ = NULL; - - requestedPercentageVariationString = (char *) json_object_get_string(requestedPercentageVariationJ); - - requestedPercentageVariation = (int) strtol(requestedPercentageVariationString, &conversionEnd, 10); - if(conversionEnd == requestedPercentageVariationString) { - AFB_API_ERROR(apiHandle, - "Tried to increase/decrease an integer control \ - but string sent in json is not a increase/decrease string : '%s'", - json_object_get_string(requestedPercentageVariationJ)); - return -1; - } - - if(alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER && - alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER64) { - AFB_API_ERROR(apiHandle, - "Tried to increase/decrease values on a incompatible \ - control type (%i), control type must be an integer", - alsaCtlProperties->type); - return -2; - } - - if(requestedPercentageVariation < -100 || requestedPercentageVariation > 100) { - AFB_API_ERROR(apiHandle, - "Tried to increase/decrease values but specified change is \ - not a valid percentage, it should be between -100 and 100"); - return -3; - } - - requestedVariation = InternalHalConvertPercentageToValue((int) abs(requestedPercentageVariation), - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - if(requestedVariation == -INT_MAX) { - AFB_API_ERROR(apiHandle, - "Didn't succeed to convert %i (using min %i et max %i)", - requestedPercentageVariation, - alsaCtlProperties->minval, - alsaCtlProperties->maxval); - return -4; - } - - if(requestedPercentageVariation < 0) - requestedVariation = -requestedVariation; - - count = (int) json_object_array_length(previousControlValuesJ); - - changedArrayJ = json_object_new_array(); - - for(idx = 0; idx < count; idx++) { - toChangeObjectJ = json_object_array_get_idx(previousControlValuesJ, idx); - - if(! json_object_is_type(toChangeObjectJ, json_type_int)) { - AFB_API_ERROR(apiHandle, - "Current json object %s is not an integer", - json_object_get_string(toChangeObjectJ)); - return -(10 + idx); - } - - toChangeValue = json_object_get_int(toChangeObjectJ); - - if((toChangeValue + requestedVariation) < alsaCtlProperties->minval) - changedValue = alsaCtlProperties->minval; - else if((toChangeValue + requestedVariation) > alsaCtlProperties->maxval) - changedValue = alsaCtlProperties->maxval; - else - changedValue = toChangeValue + requestedVariation; - - json_object_array_put_idx(changedArrayJ, idx, json_object_new_int(changedValue)); - } - - *ChangedJ = changedArrayJ; - - return 0; -} \ No newline at end of file diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.h b/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.h deleted file mode 100644 index f0288ac..0000000 --- a/4a-hal/4a-internals-hal/4a-internals-hal-value-handler.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 "IoT.bzh" - * Author Jonathan Aillet - * - * 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 _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ -#define _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ - -#include - -#include - -#include - -#include "4a-internals-hal-alsacore-link.h" - -// Enum for the type of conversion requested -enum ConversionType { - CONVERSION_NORMALIZED_TO_ALSACORE = 1, - CONVERSION_ALSACORE_TO_NORMALIZED = 2 -}; - -// Simple conversion value to/from percentage functions -int InternalHalConvertValueToPercentage(double val, double min, double max); -int InternalHalConvertPercentageToValue(int percentage, int min, int max); - -// Convert json object from percentage to value -int InternalHalConvertJsonValues(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *toConvertJ, - json_object **ConvertedJ, - enum ConversionType requestedConversion); - -// Increase/Decrease previous values using percentage passed in Json -int InternalHalChangePreviousValuesUsingJson(afb_api_t apiHandle, - struct InternalHalAlsaCtlProperties *alsaCtlProperties, - json_object *requestedPercentageVariationJ, - json_object *previousControlValuesJ, - json_object **ChangedJ); - -#endif /* _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/CMakeLists.txt b/4a-hal/CMakeLists.txt deleted file mode 100644 index b863c5f..0000000 --- a/4a-hal/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017, 2018 IoT.bzh -# -# author: Fulup Ar Foll -# contrib: Romain Forlot -# conrtib: Jonathan Aillet -# -# 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(4a-hal) - - # Define project Targets - add_library(${TARGET_NAME} MODULE - 4a-hal-manager/4a-hal-manager.c - 4a-hal-manager/4a-hal-manager-cb.c - 4a-internals-hal/4a-internals-hal-alsacore-link.c - 4a-internals-hal/4a-internals-hal-api-loader.c - 4a-internals-hal/4a-internals-hal-cb.c - 4a-internals-hal/4a-internals-hal-mixer-link.c - 4a-internals-hal/4a-internals-hal-value-handler.c - ) - - # Binder exposes a unique public entry point - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "" - LABELS "BINDING" # Need to be in V3 - LINK_FLAGS ${BINDINGS_LINK_FLAG} - OUTPUT_NAME ${TARGET_NAME} - ) - - # Library dependencies (include updates automatically) - TARGET_LINK_LIBRARIES(${TARGET_NAME} - 4a-hal-utilities - ) - - # Define target includes for this target client - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - ) diff --git a/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.c b/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.c new file mode 100644 index 0000000..6409253 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 "4a-hal-utilities-alsa-data.h" + +/******************************************************************************* + * Free contents of 'InternalHalAlsaMapT' data structure * + ******************************************************************************/ + +uint8_t HalUtlFreeAlsaCtlsMap(struct InternalHalAlsaMapT *alsaCtlsMap) +{ + int idx; + + if(! alsaCtlsMap) + return -1; + + if(alsaCtlsMap->ctlsCount > 0 && ! alsaCtlsMap->ctls) + return -2; + + for(idx = 0; idx < alsaCtlsMap->ctlsCount; idx++) { + free(alsaCtlsMap->ctls[idx].action); + free(alsaCtlsMap->ctls[idx].ctl.alsaCtlProperties.enums); + free(alsaCtlsMap->ctls[idx].ctl.alsaCtlProperties.dbscale); + } + + free(alsaCtlsMap->ctls); + + free(alsaCtlsMap); + + return 0; +} \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.h b/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.h new file mode 100644 index 0000000..fe70210 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-alsa-data.h @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2019 "IoT.bzh" +* Author Jonathan Aillet +* +* 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 _HAL_UTILITIES_ALSA_DATA_INCLUDE_ +#define _HAL_UTILITIES_ALSA_DATA_INCLUDE_ + +#include + +#include + +#include + +#include + +#include + +struct InternalHalAlsaDBScale { + int min; + int max; + int step; + int mute; +}; + +struct InternalHalAlsaCtlProperties { + snd_ctl_elem_type_t type; + int count; + int minval; + int maxval; + int step; + // TBD JAI : use them + const char **enums; + struct InternalHalAlsaDBScale *dbscale; +}; + +struct InternalHalAlsaCtl { + char *name; + int numid; + int value; + struct InternalHalAlsaCtlProperties alsaCtlProperties; + struct InternalHalAlsaCtlProperties *alsaCtlCreation; +}; + +struct InternalHalAlsaMap { + const char *uid; + char *info; + afb_event_t alsaControlEvent; + struct InternalHalAlsaCtl ctl; + json_object *actionJ; + CtlActionT *action; +}; + +struct InternalHalAlsaMapT { + struct InternalHalAlsaMap *ctls; + unsigned int ctlsCount; +}; + +// Free contents of 'CtlHalAlsaMapT' data structure +uint8_t HalUtlFreeAlsaCtlsMap(struct InternalHalAlsaMapT *alsaCtlsMap); + +#endif /* _HAL_UTILITIES_ALSA_DATA_INCLUDE_ */ \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-data.c b/lib/4a-hal-utilities/4a-hal-utilities-data.c new file mode 100644 index 0000000..314190f --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-data.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include "4a-hal-utilities-data.h" +#include "4a-hal-utilities-alsa-data.h" + +/******************************************************************************* + * Internal Hal - Streams data handling functions * + ******************************************************************************/ + +struct InternalHalMixerData *HalUtlAddMixerDataToMixerDataList(struct InternalHalMixerData **mixerDataList) +{ + struct InternalHalMixerData *currentMixerData; + + if(! mixerDataList) + return NULL; + + currentMixerData = *mixerDataList; + if(! currentMixerData) { + currentMixerData = (struct InternalHalMixerData *) calloc(1, sizeof(struct InternalHalMixerData)); + if(! currentMixerData) + return NULL; + + *mixerDataList = currentMixerData; + } + else { + while(currentMixerData->next) + currentMixerData = currentMixerData->next; + + currentMixerData->next = calloc(1, sizeof(struct InternalHalMixerData)); + if(! currentMixerData->next) + return NULL; + + currentMixerData = currentMixerData->next; + } + + return currentMixerData; +} + +int8_t HalUtlRemoveSelectedMixerData(struct InternalHalMixerData **mixerDataList, struct InternalHalMixerData *mixerDataToRemove) +{ + struct InternalHalMixerData *currentMixerData, *matchingMixerData; + + if(! mixerDataList || ! *mixerDataList || ! mixerDataToRemove) + return -1; + + currentMixerData = *mixerDataList; + if(currentMixerData == mixerDataToRemove) { + *mixerDataList = currentMixerData->next; + matchingMixerData = currentMixerData; + } + else { + while(currentMixerData && currentMixerData->next != mixerDataToRemove) + currentMixerData = currentMixerData->next; + + if(currentMixerData) { + matchingMixerData = currentMixerData->next; + currentMixerData->next = currentMixerData->next->next; + } + else { + return -2; + } + } + + free(matchingMixerData->verb); + free(matchingMixerData->verbToCall); + free(matchingMixerData->streamCardId); + + free(matchingMixerData); + + return 0; +} + +int64_t HalUtlRemoveAllMixerData(struct InternalHalMixerData **mixerDataList) +{ + int8_t ret; + int64_t mixerDataRemoved = 0; + + if(! mixerDataList) + return -1; + + while(*mixerDataList) { + ret = HalUtlRemoveSelectedMixerData(mixerDataList, *mixerDataList); + if(ret) + return (int64_t) ret; + + mixerDataRemoved++; + } + + return mixerDataRemoved; +} + +int64_t HalUtlGetNumberOfMixerDataInList(struct InternalHalMixerData **mixerDataList) +{ + int64_t numberOfMixerData = 0; + struct InternalHalMixerData *currentMixerData; + + if(! mixerDataList) + return -1; + + currentMixerData = *mixerDataList; + while(currentMixerData) { + currentMixerData = currentMixerData->next; + numberOfMixerData++; + } + + return numberOfMixerData; +} + +struct InternalHalMixerData *HalUtlSearchMixerDataByProperties(struct InternalHalMixerData **mixerDataList, char *verb, char *verbToCall, char *streamCardId) +{ + struct InternalHalMixerData *currentMixerData; + + if(! mixerDataList || ! verb) + return NULL; + + currentMixerData = *mixerDataList; + + while(currentMixerData) { + if((! strcmp(verb, currentMixerData->verb)) && + (! strcmp(verbToCall, currentMixerData->verbToCall)) && + (! strcmp(streamCardId, currentMixerData->streamCardId))) + return currentMixerData; + + currentMixerData = currentMixerData->next; + } + + return NULL; +} + +/******************************************************************************* + * Hal data handling functions * + ******************************************************************************/ + +struct HalData *HalUtlAddHalToHalList(struct HalData **halDataList) +{ + struct HalData *currentHalData; + + if(! halDataList) + return NULL; + + currentHalData = *halDataList; + if(! currentHalData) { + currentHalData = (struct HalData *) calloc(1, sizeof(struct HalData)); + if(! currentHalData) + return NULL; + + *halDataList = currentHalData; + } + else { + while(currentHalData->next) + currentHalData = currentHalData->next; + + currentHalData->next = calloc(1, sizeof(struct HalData)); + if(! currentHalData->next) + return NULL; + + currentHalData = currentHalData->next; + } + + return currentHalData; +} + +int8_t HalUtlRemoveSelectedHalFromList(struct HalData **halDataList, struct HalData *halToRemove) +{ + struct HalData *currentHalData, *matchingHal; + + if(! halDataList || ! *halDataList || ! halToRemove) + return -1; + + currentHalData = *halDataList; + if(currentHalData == halToRemove) { + *halDataList = currentHalData->next; + matchingHal = currentHalData; + } + else { + while(currentHalData && currentHalData->next != halToRemove) + currentHalData = currentHalData->next; + + if(currentHalData) { + matchingHal = currentHalData->next; + currentHalData->next = currentHalData->next->next; + } + else { + return -2; + } + } + + free(matchingHal->apiName); + free(matchingHal->sndCardPath); + free(matchingHal->info); + free(matchingHal->author); + free(matchingHal->version); + free(matchingHal->date); + + if(matchingHal->internal) { + HalUtlRemoveAllMixerData(&matchingHal->internalHalData->streamsData); + HalUtlRemoveAllMixerData(&matchingHal->internalHalData->playbacksData); + HalUtlRemoveAllMixerData(&matchingHal->internalHalData->capturesData); + + HalUtlFreeAlsaCtlsMap(matchingHal->internalHalData->alsaMapT); + + free(matchingHal->internalHalData); + } + + free(matchingHal); + + return 0; +} + +int64_t HalUtlRemoveAllHalFromList(struct HalData **halDataList) +{ + int8_t ret; + int64_t halRemoved = 0; + + if(! halDataList) + return -1; + + while(*halDataList) { + ret = HalUtlRemoveSelectedHalFromList(halDataList, *halDataList); + if(ret) + return (int64_t) ret; + + halRemoved++; + } + + return halRemoved; +} + +int64_t HalUtlGetNumberOfHalInList(struct HalData **halDataList) +{ + int64_t numberOfHal = 0; + struct HalData *currentHalData; + + if(! halDataList) + return -1; + + currentHalData = *halDataList; + + while(currentHalData) { + currentHalData = currentHalData->next; + numberOfHal++; + } + + return numberOfHal; +} + +struct HalData *HalUtlSearchHalDataByApiName(struct HalData **halDataList, char *apiName) +{ + struct HalData *currentHalData; + + if(! halDataList || ! *halDataList || ! apiName) + return NULL; + + currentHalData = *halDataList; + + while(currentHalData) { + if(! strcmp(apiName, currentHalData->apiName)) + return currentHalData; + + currentHalData = currentHalData->next; + } + + return NULL; +} + +struct HalData *HalUtlSearchReadyHalDataByCardId(struct HalData **halDataList, int cardId) +{ + struct HalData *currentHalData; + + if(! halDataList || ! *halDataList) + return NULL; + + currentHalData = *halDataList; + + while(currentHalData) { + if(currentHalData->status == HAL_STATUS_READY && currentHalData->sndCardId == cardId) + return currentHalData; + + currentHalData = currentHalData->next; + } + + return NULL; +} + +/******************************************************************************* + * Hal Manager data handling functions * + ******************************************************************************/ + +uint8_t HalUtlInitializeHalMgrData(afb_api_t apiHandle, struct HalMgrData *halMgrData, char *apiName, char *info) +{ + if(! apiHandle || ! halMgrData || ! apiName || ! info) + return -1; + + // Allocate and fill apiName and info strings + halMgrData->apiName = strdup(apiName); + if(! halMgrData->apiName) + return -2; + + halMgrData->info = strdup(info); + if(! halMgrData->info) + return -3; + + halMgrData->apiHandle = apiHandle; + + return 0; +} + +void HalUtlRemoveHalMgrData(struct HalMgrData *halMgrData) +{ + if(! halMgrData) + return; + + if(halMgrData->halDataList) + HalUtlRemoveAllHalFromList(&halMgrData->halDataList); + + free(halMgrData->apiName); + free(halMgrData->info); + + free(halMgrData); +} \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-data.h b/lib/4a-hal-utilities/4a-hal-utilities-data.h new file mode 100644 index 0000000..f3de1a6 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-data.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _HAL_UTILITIES_DATA_INCLUDE_ +#define _HAL_UTILITIES_DATA_INCLUDE_ + +#include + +#include + +#include + +#include + +#include "4a-hal-utilities-alsa-data.h" + +#define HAL_STREAM_UPDATES_EVENT_NAME "stream-updates" + +// Enum for hal status +enum HalStatus { + HAL_STATUS_UNAVAILABLE=0, + HAL_STATUS_AVAILABLE=1, + HAL_STATUS_READY=2 +}; + +// Structure to store stream data +struct InternalHalMixerData { + char *verb; + char *verbToCall; + char *streamCardId; + afb_event_t event; + + struct InternalHalMixerData *next; +}; + +// Structure to store specific internal hal data +struct InternalHalData { + char *mixerApiName; + char *prefix; + json_object *halMixerJ; + + struct InternalHalMixerData *streamsData; + afb_event_t streamUpdates; + + struct InternalHalMixerData *playbacksData; + struct InternalHalMixerData *capturesData; + + struct InternalHalAlsaMapT *alsaMapT; + + afb_api_t apiHandle; + CtlConfigT *ctrlConfig; +}; + +// Structure to store specific hal (internal or external) data +struct HalData { + char *apiName; + enum HalStatus status; + char *sndCardPath; + int sndCardId; + char *info; + unsigned int internal; + + char *author; + char *version; + char *date; + // Can be beefed up if needed + + struct InternalHalData *internalHalData; // Can be NULL if external api + + struct HalData *next; +}; + +// Structure to store hal manager data +struct HalMgrData { + char *apiName; + char *info; + + afb_api_t apiHandle; + + struct HalData *halDataList; +}; + +// Internal Hal - Streams data handling functions +struct InternalHalMixerData *HalUtlAddMixerDataToMixerDataList(struct InternalHalMixerData **mixerDataList); +int8_t HalUtlRemoveSelectedMixerData(struct InternalHalMixerData **mixerDataList, struct InternalHalMixerData *mixerDataToRemove); +int64_t HalUtlRemoveAllMixerData(struct InternalHalMixerData **mixerDataList); +int64_t HalUtlGetNumberOfMixerDataInList(struct InternalHalMixerData **mixerDataList); +struct InternalHalMixerData *HalUtlSearchMixerDataByProperties(struct InternalHalMixerData **mixerDataList, char *verb, char *verbToCall, char *streamCardId); + +// Hal data handling functions +struct HalData *HalUtlAddHalToHalList(struct HalData **halDataList); +int8_t HalUtlRemoveSelectedHalFromList(struct HalData **halDataList, struct HalData *halToRemove); +int64_t HalUtlRemoveAllHalFromList(struct HalData **halDataList); +int64_t HalUtlGetNumberOfHalInList(struct HalData **halDataList); +struct HalData *HalUtlSearchHalDataByApiName(struct HalData **halDataList, char *apiName); +struct HalData *HalUtlSearchReadyHalDataByCardId(struct HalData **halDataList, int cardId); + +// Hal Manager data handling functions +uint8_t HalUtlInitializeHalMgrData(afb_api_t apiHandle, struct HalMgrData *halMgrData, char *apiName, char *info); +void HalUtlRemoveHalMgrData(struct HalMgrData *halMgrData); + +#endif /* _HAL_UTILITIES_DATA_INCLUDE_ */ \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c new file mode 100644 index 0000000..ed06b27 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2019 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include "4a-hal-utilities-data.h" +#include "4a-hal-utilities-hal-streams-handler.h" + +/******************************************************************************* + * Actions to be call when a stream verb is called * + ******************************************************************************/ + +void HalUtlActionOnMixer(afb_req_t request, enum ActionOnMixerType actionType) +{ + int idx, count; + + char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; + + afb_api_t apiHandle; + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + struct InternalHalMixerData *currentMixerData = NULL; + + json_object *requestJson, *responseJ = NULL, *toReturnJ = NULL; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get current hal controller api handle"); + return; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + afb_req_fail(request, "hal_controller_config", "Can't get current hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + afb_req_fail(request, "hal_controller_data", "Can't get current hal controller data"); + return; + } + + if(! (requestJson = afb_req_json(request))) { + afb_req_fail(request, "request_json", "Can't get request json"); + return; + } + + if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) + json_object_object_add(requestJson, "verbose", json_object_new_boolean(1)); + + apiToCall = currentHalData->internalHalData->mixerApiName; + if(! apiToCall) { + afb_req_fail(request, "mixer_api", "Can't get mixer api"); + return; + } + + if(currentHalData->status != HAL_STATUS_READY) { + afb_req_fail(request, "hal_not_ready", "Seems that hal is not ready"); + return; + } + + currentMixerData = (struct InternalHalMixerData *) afb_req_get_vcbdata(request); + if(! currentMixerData) { + afb_req_fail(request, "hal_call_data", "Can't get current call data"); + return; + } + + switch(actionType) { + case ACTION_ON_MIXER_STREAM: + count = 1; + break; + + case ACTION_ON_MIXER_PLAYBACK: + case ACTION_ON_MIXER_CAPTURE: + case ACTION_ON_MIXER_ALL_STREAM: + count = (int) HalUtlGetNumberOfMixerDataInList(¤tMixerData); + toReturnJ = json_object_new_object(); + break; + + default: + afb_req_fail(request, "mixer_action_type", "Action type is unknown"); + return; + } + + for(idx = 0; idx < count; idx++) { + if(afb_api_call_sync(apiHandle, + apiToCall, + currentMixerData->verbToCall, + json_object_get(requestJson), + &responseJ, + &returnedError, + &returnedInfo)) { + if(responseJ) + json_object_put(responseJ); + if(toReturnJ) + json_object_put(toReturnJ); + afb_req_fail_f(request, + "mixer_call", + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s' (call to mixer %i out of %i)", + currentMixerData->verbToCall, + apiToCall, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned", + idx, + count); + free(returnedError); + free(returnedInfo); + return; + } + + if(! responseJ) { + if(toReturnJ) + json_object_put(toReturnJ); + afb_req_fail_f(request, + "mixer_call", + "Seems that %s call to api %s succeed but no response was returned (call to mixer %i out of %i)", + currentMixerData->verbToCall, + apiToCall, + idx, + count); + free(returnedError); + free(returnedInfo); + return; + } + + // TBD JAI : When mixer events will be available, use them instead of generating events at calls + if((actionType == ACTION_ON_MIXER_STREAM || + actionType == ACTION_ON_MIXER_ALL_STREAM) && + ((! currentMixerData->event) || + (afb_event_push(currentMixerData->event, json_object_get(responseJ)) < 0))) { + AFB_API_ERROR(apiHandle, "Could not generate an event for stream %s", currentMixerData->verb); + } + + switch(actionType) { + case ACTION_ON_MIXER_STREAM: + toReturnJ = responseJ; + break; + + case ACTION_ON_MIXER_PLAYBACK: + case ACTION_ON_MIXER_CAPTURE: + json_object_object_add(toReturnJ, currentMixerData->verbToCall, responseJ); + currentMixerData = currentMixerData->next; + break; + + case ACTION_ON_MIXER_ALL_STREAM: + json_object_object_add(toReturnJ, currentMixerData->verb, responseJ); + currentMixerData = currentMixerData->next; + break; + + default: + break; + } + } + + switch(actionType) { + case ACTION_ON_MIXER_STREAM: + afb_req_success_f(request, + toReturnJ, + "Action %s correctly transferred to %s without any error raised", + currentMixerData->verbToCall, + apiToCall); + break; + + case ACTION_ON_MIXER_PLAYBACK: + afb_req_success(request, + toReturnJ, + "Actions correctly transferred to all playbacks without any error raised"); + break; + + case ACTION_ON_MIXER_CAPTURE: + afb_req_success(request, + toReturnJ, + "Actions correctly transferred to all captures without any error raised"); + break; + + case ACTION_ON_MIXER_ALL_STREAM: + afb_req_success(request, + toReturnJ, + "Actions correctly transferred to all streams without any error raised"); + break; + + default: + break; + } +} + +void HalUtlActionOnStream(afb_req_t request) +{ + HalUtlActionOnMixer(request, ACTION_ON_MIXER_STREAM); +} + +void HalUtlActionOnPlayback(afb_req_t request) +{ + HalUtlActionOnMixer(request, ACTION_ON_MIXER_PLAYBACK); +} + +void HalUtlActionOnCapture(afb_req_t request) +{ + HalUtlActionOnMixer(request, ACTION_ON_MIXER_CAPTURE); +} + +void HalUtlActionOnAllStream(afb_req_t request) +{ + HalUtlActionOnMixer(request, ACTION_ON_MIXER_ALL_STREAM); +} + +/******************************************************************************* + * Add stream data and verb function * + ******************************************************************************/ + +struct InternalHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(afb_api_t apiHandle, + char *verb, + char *verbToCall, + char *streamCardId) +{ + json_object *streamAddedEventJ; + + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + struct InternalHalMixerData *createdStreamData; + + if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) + return NULL; + + ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); + if(! ctrlConfig) + return NULL; + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData || + ! currentHalData->internalHalData) + return NULL; + + createdStreamData = HalUtlAddMixerDataToMixerDataList(¤tHalData->internalHalData->streamsData); + if(! createdStreamData) + return NULL; + + createdStreamData->verb = strdup(verb); + createdStreamData->verbToCall = strdup(verbToCall); + createdStreamData->streamCardId = strdup(streamCardId); + + if((! createdStreamData->verb) || + (! createdStreamData->verbToCall) || + (! createdStreamData->streamCardId)) { + HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); + return NULL; + } + + if(! (createdStreamData->event = afb_api_make_event(apiHandle, createdStreamData->verb))) { + HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); + return NULL; + } + + if(afb_api_add_verb(apiHandle, + createdStreamData->verb, + "Stream action transferred to mixer", + HalUtlActionOnStream, + (void *) createdStreamData, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle,"Error while creating verb for stream : '%s'", createdStreamData->verb); + HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); + return NULL; + } + + wrap_json_pack(&streamAddedEventJ, + "{s:s, s:s, s:s}", + "action", "added", + "name", createdStreamData->verb, + "cardId", createdStreamData->streamCardId); + + afb_event_push(currentHalData->internalHalData->streamUpdates, streamAddedEventJ); + + return createdStreamData; +} + +int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, + char *verb, + char *verbToCall, + char *streamCardId) +{ + int8_t returnedErr = 0; + + json_object *streamRemovedEventJ; + + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + struct InternalHalMixerData *toRemoveStreamData; + + if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) + return -1; + + ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); + if(! ctrlConfig) + return -2; + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData || + ! currentHalData->internalHalData) + return -3; + + toRemoveStreamData = HalUtlSearchMixerDataByProperties(¤tHalData->internalHalData->streamsData, + verb, + verbToCall, + streamCardId); + if(! toRemoveStreamData) + return -4; + + wrap_json_pack(&streamRemovedEventJ, + "{s:s, s:s, s:s}", + "action", "removed", + "name", toRemoveStreamData->verb, + "cardId", toRemoveStreamData->streamCardId); + + if(afb_api_del_verb(apiHandle, verb, NULL)) { + AFB_API_ERROR(apiHandle,"Error while deleting verb for stream : '%s'", verb); + json_object_put(streamRemovedEventJ); + return -5; + } + + returnedErr = HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, toRemoveStreamData); + if(returnedErr) { + AFB_API_ERROR(apiHandle,"Error %i while removing data for stream : '%s'", returnedErr, verb); + json_object_put(streamRemovedEventJ); + return -6; + } + + afb_event_push(currentHalData->internalHalData->streamUpdates, streamRemovedEventJ); + + return 0; +} \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h new file mode 100644 index 0000000..028dd1f --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2019 "IoT.bzh" +* Author Jonathan Aillet +* +* 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 _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ +#define _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ + +#include + +#include + +#include + +// Enum for the type of action on mixer +enum ActionOnMixerType { + ACTION_ON_MIXER_STREAM = 1, + ACTION_ON_MIXER_PLAYBACK = 2, + ACTION_ON_MIXER_CAPTURE = 3, + ACTION_ON_MIXER_ALL_STREAM = 4 +}; + +// Actions to be call when a stream verb is called +void HalUtlActionOnStream(afb_req_t request); +void HalUtlActionOnPlayback(afb_req_t request); +void HalUtlActionOnCapture(afb_req_t request); +void HalUtlActionOnAllStream(afb_req_t request); + +// Add/Remove stream data and verb functions +struct InternalHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(afb_api_t apiHandle, + char *verb, + char *verbToCall, + char *streamCardId); +int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, + char *verb, + char *verbToCall, + char *streamCardId); + +#endif /* _HAL_UTILITIES_HAL_STREAMS_CREATION_INCLUDE_ */ \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.c b/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.c new file mode 100644 index 0000000..16c28c4 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 "4a-hal-utilities-verbs-loader.h" + +/******************************************************************************* + * Dynamic API common functions * + ******************************************************************************/ + +int HalUtlLoadVerbs(afb_api_t apiHandle, afb_verb_t *verbs) +{ + int idx, errCount = 0; + + if(! apiHandle || ! verbs) + return -1; + + for (idx = 0; verbs[idx].verb; idx++) { + errCount+= afb_api_add_verb(apiHandle, + verbs[idx].verb, + NULL, + verbs[idx].callback, + (void *) &verbs[idx], + verbs[idx].auth, + 0, + 0); + } + + return errCount; +} \ No newline at end of file diff --git a/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.h b/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.h new file mode 100644 index 0000000..9084595 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-verbs-loader.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ +#define _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ + +#include + +#include + +// Verb that allows to add verb to a dynamic api +int HalUtlLoadVerbs(afb_api_t apiHandle, afb_verb_t *verbs); + +#endif /* _HAL_UTILITIES_VERBS_LOADER_INCLUDE_ */ \ No newline at end of file diff --git a/lib/4a-hal-utilities/CMakeLists.txt b/lib/4a-hal-utilities/CMakeLists.txt new file mode 100644 index 0000000..d90dd11 --- /dev/null +++ b/lib/4a-hal-utilities/CMakeLists.txt @@ -0,0 +1,33 @@ +########################################################################### +# Copyright 2015, 2016, 2017, 2018, 2019 IoT.bzh +# +# author: Fulup Ar Foll +# contrib: Jonathan Aillet +# +# 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(4a-hal-utilities) + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} STATIC + 4a-hal-utilities-alsa-data.c + 4a-hal-utilities-data.c + 4a-hal-utilities-hal-streams-handler.c + 4a-hal-utilities-verbs-loader.c) + + # Define target includes for this target client + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..3fd93ec --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,22 @@ +########################################################################### +# 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. +########################################################################### + + +# Include any directory not starting with _ +# ----------------------------------------------------- +PROJECT_SUBDIRS_ADD() diff --git a/plugins/lib/bluealsa/CMakeLists.txt b/plugins/lib/bluealsa/CMakeLists.txt index e7d3216..697923a 100644 --- a/plugins/lib/bluealsa/CMakeLists.txt +++ b/plugins/lib/bluealsa/CMakeLists.txt @@ -45,5 +45,5 @@ PROJECT_TARGET_ADD(hal-bluealsa) target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib" - PRIVATE "${CMAKE_SOURCE_DIR}/4a-hal/4a-hal-utilities" + PRIVATE "${CMAKE_SOURCE_DIR}/lib/4a-hal-utilities" ) diff --git a/src/4a-hal-manager/4a-hal-manager-cb.c b/src/4a-hal-manager/4a-hal-manager-cb.c new file mode 100644 index 0000000..32fbb25 --- /dev/null +++ b/src/4a-hal-manager/4a-hal-manager-cb.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include "4a-hal-utilities-data.h" + +#include "4a-hal-manager-cb.h" + +/******************************************************************************* + * HAL Manager event handler function * + ******************************************************************************/ + +// TBD JAI : to implement +void HalMgrDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ) +{ + AFB_API_WARNING(apiHandle, "Not implemented yet"); + // Use "4a-hal-manager-events.h" to handle events +} + +/******************************************************************************* + * HAL Manager verbs functions * + ******************************************************************************/ + +void HalMgrPing(afb_req_t request) +{ + static int count = 0; + + count++; + + AFB_REQ_NOTICE(request, "ping count = %d", count); + afb_req_success(request, json_object_new_int(count), NULL); + + return; +} + +void HalMgrLoaded(afb_req_t request) +{ + int requestJsonErr = 0, allHal = 0, verbose = 0; + + char cardIdString[32]; + + afb_api_t apiHandle; + struct HalMgrData *halMgrData; + struct HalData *currentHalData; + + json_object *requestJson, *requestAnswer, *apiObject; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); + return; + } + + halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); + if(! halMgrData) { + afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); + return; + } + + currentHalData = halMgrData->halDataList; + + if(! currentHalData) { + afb_req_success(request, NULL, "No Hal Api loaded"); + return; + } + + requestAnswer = json_object_new_array(); + if(! requestAnswer) { + afb_req_fail(request, "json_answer", "Can't generate json answer"); + return; + } + + if(! (requestJson = afb_req_json(request))) + AFB_REQ_NOTICE(request, "Can't get request json"); + else + requestJsonErr = wrap_json_unpack(requestJson, "{s?:b s?:b}", "all", &allHal, "verbose", &verbose); + + while(currentHalData) { + if(allHal || currentHalData->status == HAL_STATUS_READY) { + // Case if request key is 'verbose' and value is bigger than 0 + if(! requestJsonErr && verbose) { + if(currentHalData->sndCardId >= 0) + snprintf(cardIdString, sizeof(cardIdString), "hw:%i", currentHalData->sndCardId); + else + snprintf(cardIdString, sizeof(cardIdString), "not-found"); + + wrap_json_pack(&apiObject, + "{s:s s:i s:s s:i s:s s:s s:s s:s s:s}", + "api", currentHalData->apiName, + "status", (int) currentHalData->status, + "sndcard", currentHalData->sndCardPath, + "internal", (int) currentHalData->internal, + "info", currentHalData->info ? currentHalData->info : "", + "author", currentHalData->author ? currentHalData->author : "", + "version", currentHalData->version ? currentHalData->version : "", + "date", currentHalData->date ? currentHalData->date : "", + "snd-dev-id", cardIdString); + json_object_array_add(requestAnswer, apiObject); + } + // Case if request is empty or not handled + else { + json_object_array_add(requestAnswer, json_object_new_string(currentHalData->apiName)); + } + } + + currentHalData = currentHalData->next; + } + + afb_req_success(request, requestAnswer, "Requested data"); +} + +void HalMgrLoad(afb_req_t request) +{ + int cardId = -1; + + char *apiName, *sndCardPath, *info = NULL, *author = NULL, *version = NULL, *date = NULL; + + afb_api_t apiHandle; + struct HalMgrData *halMgrData; + struct HalData *addedHal; + + json_object *requestJson, *apiReceivedMetadata; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); + return; + } + + halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); + if(! halMgrData) { + afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); + return; + } + + if(! (requestJson = afb_req_json(request))) { + afb_req_fail(request, "request_json", "Can't get request json"); + return; + } + + if(! json_object_object_get_ex(requestJson, "metadata", &apiReceivedMetadata)) { + afb_req_fail(request, "api_metadata", "Can't get json metadata section to register external hal"); + return; + } + + if(wrap_json_unpack(apiReceivedMetadata, + "{s:s s:s s?:s s?:s s?:s s?:s s?:i}", + "api", &apiName, + "uid", &sndCardPath, + "info", &info, + "author", &author, + "version", &version, + "date", &date, + "snd-dev-id", &cardId)) { + afb_req_fail(request, "api_metadata", "Can't metadata of api to register"); + return; + } + + addedHal = HalUtlAddHalToHalList(&halMgrData->halDataList); + + addedHal->internal = 0; + // TBD JAI : initialize external to unavailable once event from external hal will be handled + addedHal->status = HAL_STATUS_READY; + + addedHal->apiName = strdup(apiName); + addedHal->sndCardPath = strdup(sndCardPath); + + if(info) + addedHal->info = strdup(info); + + if(author) + addedHal->author = strdup(author); + + if(version) + addedHal->version = strdup(version); + + if(date) + addedHal->date = strdup(date); + + addedHal->sndCardId = cardId; + + // TBD JAI: add subscription to this api status events, if subscription fails, remove hal from list + + afb_req_success(request, NULL, "Api successfully registered"); +} + +void HalMgrUnload(afb_req_t request) +{ + char *apiName; + + afb_api_t apiHandle; + struct HalMgrData *halMgrData; + struct HalData *halToRemove; + + json_object *requestJson; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get hal manager api handle"); + return; + } + + halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); + if(! halMgrData) { + afb_req_fail(request, "hal_manager_data", "Can't get hal manager data"); + return; + } + + if(! (requestJson = afb_req_json(request))) { + afb_req_fail(request, "request_json", "Can't get request json"); + return; + } + + if(wrap_json_unpack(requestJson, "{s:s}", "api", &apiName)) { + afb_req_fail(request, "requested_api", "Can't get api to remove"); + return; + } + + halToRemove = HalUtlSearchHalDataByApiName(&halMgrData->halDataList, apiName); + if(! halToRemove) { + afb_req_fail(request, "requested_api", "Can't find api to remove"); + return; + } + + if(halToRemove->internal) { + afb_req_fail(request, "requested_api", "Can't remove an internal hal"); + return; + } + + if(HalUtlRemoveSelectedHalFromList(&halMgrData->halDataList, halToRemove)) { + afb_req_fail(request, "unregister_error", "Didn't succeed to remove specified api"); + return; + } + + // TBD JAI: remove subscription to this api status events + + afb_req_success(request, NULL, "Api successfully unregistered"); +} + +// TBD JAI : to implement +void HalMgrSubscribeEvent(afb_req_t request) +{ + AFB_REQ_WARNING(request, "Not implemented yet"); + + afb_req_success(request, json_object_new_boolean(0), NULL); +} + +// TBD JAI : to implement +void HalMgrUnsubscribeEvent(afb_req_t request) +{ + AFB_REQ_WARNING(request, "Not implemented yet"); + + afb_req_success(request, json_object_new_boolean(0), NULL); +} diff --git a/src/4a-hal-manager/4a-hal-manager-cb.h b/src/4a-hal-manager/4a-hal-manager-cb.h new file mode 100644 index 0000000..e0e144f --- /dev/null +++ b/src/4a-hal-manager/4a-hal-manager-cb.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _HALMGR_CB_INCLUDE_ +#define _HALMGR_CB_INCLUDE_ + +#include + +#include + +// Event handler +void HalMgrDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ); + +// Exported verbs callbacks +void HalMgrPing(afb_req_t request); +void HalMgrLoaded(afb_req_t request); +void HalMgrLoad(afb_req_t request); +void HalMgrUnload(afb_req_t request); +void HalMgrSubscribeEvent(afb_req_t request); +void HalMgrUnsubscribeEvent(afb_req_t request); + +#endif /* _HALMGR_CB_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-hal-manager/4a-hal-manager.c b/src/4a-hal-manager/4a-hal-manager.c new file mode 100644 index 0000000..4d2fbf1 --- /dev/null +++ b/src/4a-hal-manager/4a-hal-manager.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 "4a-hal-utilities-data.h" +#include "4a-hal-utilities-verbs-loader.h" + +#include "../4a-internals-hal/4a-internals-hal-api-loader.h" + +#include "4a-hal-manager.h" +#include "4a-hal-manager-cb.h" + +// Default api to print log when apihandle not available +afb_api_t AFB_default; + +// Local (static) Hal manager data structure +static struct HalMgrData localHalMgrGlobalData; + +/******************************************************************************* + * HAL Manager verbs table * + ******************************************************************************/ + +// Hal manager exported verbs +afb_verb_t HalManagerApiStaticVerbs[] = +{ + /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ + { .verb = "ping", .callback = HalMgrPing, .info = "Ping test"}, + { .verb = "loaded", .callback = HalMgrLoaded, .info = "Show loaded HAL"}, + { .verb = "load", .callback = HalMgrLoad, .info = "Load an external HAL to HAL Manager"}, + { .verb = "unload", .callback = HalMgrUnload, .info = "Unload an external HAL to HAL Manager"}, + { .verb = "subscribe", .callback = HalMgrSubscribeEvent, .info = "Subscribe to an event"}, + { .verb = "unsuscribe", .callback = HalMgrUnsubscribeEvent, .info = "Unsubscribe to an event"}, + { .verb = NULL } // Marker for end of the array +}; + +/******************************************************************************* + * HAL Manager get 'HalData' linked list * + from HAL list function * + ******************************************************************************/ + +struct HalData **HalMngGetHalDataList(void) +{ + return &localHalMgrGlobalData.halDataList; +} + +/******************************************************************************* + * Dynamic API functions for hal manager * + ******************************************************************************/ + +static int HalMgrInitApi(afb_api_t apiHandle) +{ + struct HalData *currentHalData; + struct HalMgrData *halMgrData; + + if(! apiHandle) + return -1; + + // Hugely hack to make all V2 AFB_DEBUG to work in fileutils + AFB_default = apiHandle; + + // Retrieve section config from api handle + halMgrData = (struct HalMgrData *) afb_api_get_userdata(apiHandle); + if(! halMgrData) + return -2; + + if(HalUtlInitializeHalMgrData(apiHandle, halMgrData, HAL_MANAGER_API_NAME, HAL_MANAGER_API_INFO)) + return -3; + + currentHalData = halMgrData->halDataList; + + while(currentHalData) { + if(! currentHalData->apiName) + return -4; + else if(afb_api_require_api(apiHandle, currentHalData->apiName, 1)) + return -5; + + currentHalData = currentHalData->next; + } + + return 0; +} + +static int HalMgrLoadApi(void *cbdata, afb_api_t apiHandle) +{ + struct HalMgrData *halMgrData; + + if(! cbdata || ! apiHandle) + return -1; + + halMgrData = (struct HalMgrData *) cbdata; + + // Save closure as api's data context + afb_api_set_userdata(apiHandle, halMgrData); + + // Add static controls verbs + if(HalUtlLoadVerbs(apiHandle, HalManagerApiStaticVerbs)) { + AFB_API_ERROR(apiHandle, "Load section : fail to register static verbs"); + return 1; + } + + // Declare an event manager for Hal Manager + afb_api_on_event(apiHandle, HalMgrDispatchApiEvent); + + // Init Api function (does not receive user closure ???) + afb_api_on_init(apiHandle, HalMgrInitApi); + + afb_api_seal(apiHandle); + + return 0; +} + +int HalMgrCreateApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) +{ + if(! apiHandle || ! halMgrData) + return -1; + + // Create one API + return afb_api_new_api(apiHandle, HAL_MANAGER_API_NAME, HAL_MANAGER_API_INFO, 1, HalMgrLoadApi, halMgrData) ? 0 : -1; +} + +/******************************************************************************* + * Startup function * + ******************************************************************************/ + +int afbBindingEntry(afb_api_t apiHandle) +{ + int status = 0, rc; + + if(! apiHandle) + return -1; + + // Hugely hack to make all V2 AFB_DEBUG to work in fileutils + AFB_default = apiHandle; + + AFB_API_NOTICE(apiHandle, "Binding start"); + + // Load Hal-Manager using Api v3 + rc = HalMgrCreateApi(apiHandle, &localHalMgrGlobalData); + if(rc < 0) + status--; + + // Load internals Hal using Api v3 + rc = InternalHalCreateAllApi(apiHandle, &localHalMgrGlobalData); + if(rc < 0) + status -= rc; + + return status; +} \ No newline at end of file diff --git a/src/4a-hal-manager/4a-hal-manager.h b/src/4a-hal-manager/4a-hal-manager.h new file mode 100644 index 0000000..4a53bdd --- /dev/null +++ b/src/4a-hal-manager/4a-hal-manager.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _HALMGR_BINDING_INCLUDE_ +#define _HALMGR_BINDING_INCLUDE_ + +#include + +#define HAL_MANAGER_API_NAME "4a-hal-manager" +#define HAL_MANAGER_API_INFO "Manager for 4A HAL APIs" + +// HAL Manager get 'HalData' linked list +struct HalData **HalMngGetHalDataList(void); + +#endif /* _HALMGR_BINDING_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-alsacore-link.c b/src/4a-internals-hal/4a-internals-hal-alsacore-link.c new file mode 100644 index 0000000..d092ddf --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-alsacore-link.c @@ -0,0 +1,633 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include + +#include + +#include "4a-hal-utilities-alsa-data.h" +#include "4a-hal-utilities-data.h" + +#include "4a-internals-hal-alsacore-link.h" +#include "4a-internals-hal-value-handler.h" + +/******************************************************************************* + * Map to alsa control types * + ******************************************************************************/ + +static const char *const snd_ctl_elem_type_names[] = { + [SND_CTL_ELEM_TYPE_NONE]= "NONE", + [SND_CTL_ELEM_TYPE_BOOLEAN]= "BOOLEAN", + [SND_CTL_ELEM_TYPE_INTEGER]="INTEGER", + [SND_CTL_ELEM_TYPE_ENUMERATED]="ENUMERATED", + [SND_CTL_ELEM_TYPE_BYTES]="BYTES", + [SND_CTL_ELEM_TYPE_IEC958]="IEC958", + [SND_CTL_ELEM_TYPE_INTEGER64]="INTEGER64", +}; + +/******************************************************************************* + * Alsa control types map from string function * + ******************************************************************************/ + +snd_ctl_elem_type_t InternalHalMapsAlsaTypeToEnum(const char *label) +{ + int idx; + static int length = sizeof(snd_ctl_elem_type_names) / sizeof(char *); + + for(idx = 0; idx < length; idx++) { + if(! strcasecmp(label, snd_ctl_elem_type_names[idx])) + return (snd_ctl_elem_type_t) idx; + } + + return SND_CTL_ELEM_TYPE_NONE; +} + +/******************************************************************************* + * Internals HAL - Alsacore calls funtions * + ******************************************************************************/ + +int InternalHalGetCardIdByCardPath(afb_api_t apiHandle, char *devPath) +{ + int errorToReturn, cardId; + + char *returnedError = NULL, *returnedInfo = NULL; + + json_object *toSendJ, *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Api handle not available"); + return -1; + } + + if(! devPath) { + AFB_API_ERROR(apiHandle, "Dev path is not available"); + return -2; + } + + wrap_json_pack(&toSendJ, "{s:s}", "cardPath", devPath); + + if(afb_api_call_sync(apiHandle, + ALSACORE_API, + ALSACORE_GETINFO_VERB, + toSendJ, + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + ALSACORE_GETINFO_VERB, + ALSACORE_API, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + errorToReturn = -3; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + ALSACORE_GETINFO_VERB, + ALSACORE_API); + errorToReturn = -4; + } + else if(! json_object_is_type(responseJ, json_type_object)) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but the returned response is invalid", + ALSACORE_GETINFO_VERB, + ALSACORE_API); + errorToReturn = -5; + } + else if(wrap_json_unpack(responseJ, "{s:i}", "cardNb", &cardId)) { + AFB_API_WARNING(apiHandle, "Response card id is not present/valid"); + errorToReturn = -6; + } + else { + return cardId; + } + + if(responseJ) + json_object_put(responseJ); + + free(returnedError); + free(returnedInfo); + + return errorToReturn; +} + +int InternalHalSubscribeToAlsaCardEvent(afb_api_t apiHandle, char *cardId) +{ + int err = 0; + + char *returnedError = NULL, *returnedInfo = NULL; + + json_object *subscribeQueryJ, *responseJ = NULL; + + wrap_json_pack(&subscribeQueryJ, "{s:s}", "devid", cardId); + if(afb_api_call_sync(apiHandle, + ALSACORE_API, + ALSACORE_SUBSCRIBE_VERB, + subscribeQueryJ, + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + ALSACORE_SUBSCRIBE_VERB, + ALSACORE_API, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + err = -1; + } + + if(responseJ) + json_object_put(responseJ); + + free(returnedError); + free(returnedInfo); + + return err; +} + +int InternalHalGetAlsaCtlInfo(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl, json_object **returnedDataJ) +{ + int err = 0; + + char *returnedError = NULL, *returnedInfo = NULL; + + json_object *queryJ, *responseJ = NULL; + + *returnedDataJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Api handle not available"); + return -1; + } + + if(! cardId) { + AFB_API_ERROR(apiHandle, "Card id is not available"); + return -2; + } + + if(! currentAlsaCtl) { + AFB_API_ERROR(apiHandle, "Alsa control data structure is not available"); + return -3; + } + + if(currentAlsaCtl->name && currentAlsaCtl->numid > 0) { + AFB_API_DEBUG(apiHandle, + "Both a control name (%s) and a control uid (%i) are specified, control uid will be used", + currentAlsaCtl->name, + currentAlsaCtl->numid); + } + + if(currentAlsaCtl->numid > 0) { + wrap_json_pack(&queryJ, "{s:s s:i s:i}", "devid", cardId, "ctl", currentAlsaCtl->numid, "mode", 3); + } + else if(currentAlsaCtl->name) { + wrap_json_pack(&queryJ, "{s:s s:s s:i}", "devid", cardId, "ctl", currentAlsaCtl->name, "mode", 3); + } + else { + AFB_API_ERROR(apiHandle, "Need at least a control name or a control id"); + return -4; + } + + if(afb_api_call_sync(apiHandle, + ALSACORE_API, + ALSACORE_CTLGET_VERB, + queryJ, + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + ALSACORE_CTLGET_VERB, + ALSACORE_API, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + free(returnedError); + free(returnedInfo); + return -5; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + ALSACORE_CTLGET_VERB, + ALSACORE_API); + return -6; + } + else if(currentAlsaCtl->name && wrap_json_unpack(responseJ, "{s:i}", "id", ¤tAlsaCtl->numid)) { + AFB_API_ERROR(apiHandle, "Can't find alsa control 'id' from control 'name': '%s' on device '%s'", currentAlsaCtl->name, cardId); + json_object_put(responseJ); + return -7; + } + + *returnedDataJ = responseJ; + + return err; +} + +int InternalHalUpdateAlsaCtlProperties(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl) +{ + int err = 0; + + json_object *returnedDataJ; + + err = InternalHalGetAlsaCtlInfo(apiHandle, cardId, currentAlsaCtl, &returnedDataJ); + if(err) { + return err; + } + // TBD JAI : get dblinear/dbminmax/... values + else if(wrap_json_unpack(returnedDataJ, + "{s:{s?:i s?:i s?:i s?:i s?:i}}", + "ctl", + "type", (int *) ¤tAlsaCtl->alsaCtlProperties.type, + "count", ¤tAlsaCtl->alsaCtlProperties.count, + "min", ¤tAlsaCtl->alsaCtlProperties.minval, + "max", ¤tAlsaCtl->alsaCtlProperties.maxval, + "step", ¤tAlsaCtl->alsaCtlProperties.step)) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to get control %i properties on device '%s' : '%s'", + currentAlsaCtl->numid, + cardId, + json_object_get_string(returnedDataJ)); + + err = -8; + } + + if(returnedDataJ) + json_object_put(returnedDataJ); + + return err; +} + +int InternalHalGetAlsaCtlValues(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl, json_object **returnedValuesJ) +{ + int err = 0; + + json_object *returnedDataJ = NULL, *returnedValuesArrayJ; + + *returnedValuesJ = NULL; + + err = InternalHalGetAlsaCtlInfo(apiHandle, cardId, currentAlsaCtl, &returnedDataJ); + if(err) { + return err; + } + else if(wrap_json_unpack(returnedDataJ, "{s:o}", "val", &returnedValuesArrayJ)) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to get control %i values on device '%s' : '%s'", + currentAlsaCtl->numid, + cardId, + json_object_get_string(returnedValuesArrayJ)); + + err = -8; + } + else if(! json_object_is_type(returnedValuesArrayJ, json_type_array)) { + AFB_API_ERROR(apiHandle, + "Json returned by control %i values on device '%s' are not an array ('%s')", + currentAlsaCtl->numid, + cardId, + json_object_get_string(returnedValuesArrayJ)); + + err = -9; + } + + if(! err) + *returnedValuesJ = json_object_get(returnedValuesArrayJ); + + if(returnedDataJ) + json_object_put(returnedDataJ); + + return err; +} + +int InternalHalSetAlsaCtlValue(afb_api_t apiHandle, char *cardId, int ctlId, json_object *valuesJ) +{ + int err = 0; + + char *returnedError = NULL, *returnedInfo = NULL; + + json_object *queryJ, *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Api handle not available"); + return -1; + } + + if(! cardId) { + AFB_API_ERROR(apiHandle, "Card id is not available"); + return -2; + } + + if(ctlId <= 0) { + AFB_API_ERROR(apiHandle, "Alsa control id is not valid"); + return -3; + } + + if(! valuesJ) { + AFB_API_ERROR(apiHandle, "Values to set json is not available"); + return -4; + } + + wrap_json_pack(&queryJ, "{s:s s:{s:i s:o}}", "devid", cardId, "ctl", "id", ctlId, "val", json_object_get(valuesJ)); + + if(afb_api_call_sync(apiHandle, + ALSACORE_API, + ALSACORE_CTLSET_VERB, + queryJ, + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + ALSACORE_CTLSET_VERB, + ALSACORE_API, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + err = -5; + } + + if(responseJ) + json_object_put(responseJ); + + free(returnedError); + free(returnedInfo); + + return err; +} + +int InternalHalCreateAlsaCtl(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *alsaCtlToCreate) +{ + int err = 0; + + char *returnedError = NULL, *returnedInfo = NULL; + + json_object *queryJ, *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Api handle not available"); + return -1; + } + + if(! cardId) { + AFB_API_ERROR(apiHandle, "Card id is not available"); + return -2; + } + + if(! alsaCtlToCreate) { + AFB_API_ERROR(apiHandle, "Alsa control data structure is not available"); + return -3; + } + + if(! alsaCtlToCreate->alsaCtlCreation) { + AFB_API_ERROR(apiHandle, "Alsa control data for creation structure is not available"); + return -4; + } + + wrap_json_pack(&queryJ, "{s:s s:{s:i s:s s?:i s?:i s?:i s:i s:i}}", + "devid", cardId, + "ctl", + "ctl", -1, + "name", alsaCtlToCreate->name, + "min", alsaCtlToCreate->alsaCtlCreation->minval, + "max", alsaCtlToCreate->alsaCtlCreation->maxval, + "step", alsaCtlToCreate->alsaCtlCreation->step, + "type", (int) alsaCtlToCreate->alsaCtlCreation->type, + "count", alsaCtlToCreate->alsaCtlCreation->count); + + if(afb_api_call_sync(apiHandle, + ALSACORE_API, + ALSACORE_ADDCTL_VERB, + queryJ, + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + ALSACORE_ADDCTL_VERB, + ALSACORE_API, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + err = -5; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + ALSACORE_ADDCTL_VERB, + ALSACORE_API); + err = -6; + } + else if(wrap_json_unpack(responseJ, "{s:i}", "id", &alsaCtlToCreate->numid)) { + AFB_API_ERROR(apiHandle, + "Can't get create id from %s of %s api", + ALSACORE_ADDCTL_VERB, + ALSACORE_API); + err = -7; + } + else if(wrap_json_unpack(responseJ, "{s:o}", "ctl", NULL)) { + AFB_API_WARNING(apiHandle, "Control %s was already present but has been updated", alsaCtlToCreate->name); + } + + if(responseJ) + json_object_put(responseJ); + + free(returnedError); + free(returnedInfo); + + return err; +} + +/******************************************************************************* + * Internals HAL - Alsacore controls request callback * + ******************************************************************************/ + +void InternalHalActionOnAlsaCtl(afb_req_t request) +{ + char cardIdString[6]; + + afb_api_t apiHandle; + + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + struct InternalHalAlsaMap *currentAlsaCtl; + + json_object *requestJson, + *valueJ, + *convertedJ, + *answerJ, + *previousControlValuesJ, + *normalizedPreviousControlValuesJ, + *appliedControlValuesJ, + *normalizedAppliedControlValuesJ; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get current hal controller api handle"); + return; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + afb_req_fail(request, "hal_controller_config", "Can't get current hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + afb_req_fail(request, "hal_controller_data", "Can't get current hal controller data"); + return; + } + + if(currentHalData->status == HAL_STATUS_UNAVAILABLE) { + afb_req_fail(request, "hal_unavailable", "Seems that hal is not available"); + return; + } + + currentAlsaCtl = (struct InternalHalAlsaMap *) afb_req_get_vcbdata(request); + if(! currentAlsaCtl) { + afb_req_fail(request, "alsa_control_data", "Can't get current alsa control data"); + return; + } + + if(currentAlsaCtl->ctl.numid <= 0) { + afb_req_fail(request, "alsa_control_id", "Alsa control id is not valid"); + return; + } + + snprintf(cardIdString, 6, "hw:%i", currentHalData->sndCardId); + + if(InternalHalGetAlsaCtlValues(apiHandle, cardIdString, ¤tAlsaCtl->ctl, &previousControlValuesJ)) { + afb_req_fail_f(request, "previous_values", "Error when trying to get unchanged alsa control values"); + return; + } + else if(InternalHalConvertJsonValues(apiHandle, + ¤tAlsaCtl->ctl.alsaCtlProperties, + previousControlValuesJ, + &normalizedPreviousControlValuesJ, + CONVERSION_ALSACORE_TO_NORMALIZED)) { + afb_req_fail_f(request, + "request_json", + "Error when trying to normalize unchanged alsa control values json '%s'", + json_object_get_string(previousControlValuesJ)); + json_object_put(previousControlValuesJ); + return; + } + + if(! (requestJson = afb_req_json(request))) { + wrap_json_pack(&answerJ, + "{s:o}", + "current", normalizedPreviousControlValuesJ); + afb_req_success(request, answerJ, "Current controls values"); + json_object_put(previousControlValuesJ); + return; + } + + if(! json_object_is_type(requestJson, json_type_object)) { + afb_req_fail_f(request, "request_json", "Request json is not valid '%s'", json_object_get_string(requestJson)); + json_object_put(previousControlValuesJ); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + + if(wrap_json_unpack(requestJson, "{s:o}", "value", &valueJ)) { + afb_req_fail_f(request, + "request_json", "Error when trying to get request value object inside request '%s'", + json_object_get_string(requestJson)); + json_object_put(previousControlValuesJ); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + + if((! json_object_is_type(valueJ, json_type_string)) && + InternalHalConvertJsonValues(apiHandle, + ¤tAlsaCtl->ctl.alsaCtlProperties, + valueJ, + &convertedJ, + CONVERSION_NORMALIZED_TO_ALSACORE)) { + afb_req_fail_f(request, + "request_json", + "Error when trying to convert request values '%s'", + json_object_get_string(valueJ)); + json_object_put(previousControlValuesJ); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + else if(json_object_is_type(valueJ, json_type_string) && + InternalHalChangePreviousValuesUsingJson(apiHandle, + ¤tAlsaCtl->ctl.alsaCtlProperties, + valueJ, + previousControlValuesJ, + &convertedJ)) { + afb_req_fail_f(request, + "previous_values", + "Error when trying to generate changed alsa control values (values : '%s', previous :'%s')", + json_object_get_string(valueJ), + json_object_get_string(previousControlValuesJ)); + json_object_put(previousControlValuesJ); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + + json_object_put(previousControlValuesJ); + + if(InternalHalSetAlsaCtlValue(apiHandle, cardIdString, currentAlsaCtl->ctl.numid, convertedJ)) { + afb_req_fail_f(request, + "alsa_control_call_error", + "Error while trying to set value on alsa control %i, device '%s', converted message '%s'", + currentAlsaCtl->ctl.numid, + cardIdString, + json_object_get_string(convertedJ)); + json_object_put(convertedJ); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + + json_object_put(convertedJ); + + if(InternalHalGetAlsaCtlValues(apiHandle, cardIdString, ¤tAlsaCtl->ctl, &appliedControlValuesJ)) { + afb_req_fail_f(request, "applied_values", "Error when trying to get applied alsa control values"); + json_object_put(normalizedPreviousControlValuesJ); + return; + } + else if(InternalHalConvertJsonValues(apiHandle, + ¤tAlsaCtl->ctl.alsaCtlProperties, + appliedControlValuesJ, + &normalizedAppliedControlValuesJ, + CONVERSION_ALSACORE_TO_NORMALIZED)) { + afb_req_fail_f(request, + "request_json", + "Error when trying to normalize applied values json '%s'", + json_object_get_string(appliedControlValuesJ)); + json_object_put(normalizedPreviousControlValuesJ); + json_object_put(appliedControlValuesJ); + return; + } + + json_object_put(appliedControlValuesJ); + + wrap_json_pack(&answerJ, + "{s:o, s:o}", + "previous", normalizedPreviousControlValuesJ, + "current", normalizedAppliedControlValuesJ); + + afb_req_success(request, answerJ, "Values correctly applied on alsa control"); +} \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-alsacore-link.h b/src/4a-internals-hal/4a-internals-hal-alsacore-link.h new file mode 100644 index 0000000..065e017 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-alsacore-link.h @@ -0,0 +1,53 @@ +/* +* Copyright (C) 2018 "IoT.bzh" +* Author Jonathan Aillet +* +* 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 _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ +#define _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ + +#include + +#include + +#include + +#include + +#include + +#include "4a-hal-utilities-alsa-data.h" + +#define ALSACORE_API "alsacore" +#define ALSACORE_SUBSCRIBE_VERB "subscribe" +#define ALSACORE_GETINFO_VERB "infoget" +#define ALSACORE_CTLGET_VERB "ctlget" +#define ALSACORE_CTLSET_VERB "ctlset" +#define ALSACORE_ADDCTL_VERB "addcustomctl" + +// Alsa control types map from string function +snd_ctl_elem_type_t InternalHalMapsAlsaTypeToEnum(const char *label); + +// Internals HAL alsacore calls funtions +int InternalHalGetCardIdByCardPath(afb_api_t apiHandle, char *devPath); +int InternalHalSubscribeToAlsaCardEvent(afb_api_t apiHandle, char *cardId); +int InternalHalUpdateAlsaCtlProperties(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *currentAlsaCtl); +int InternalHalSetAlsaCtlValue(afb_api_t apiHandle, char *cardId, int ctlId, json_object *valuesJ); +int InternalHalCreateAlsaCtl(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaCtl *alsaCtlToCreate); + +// Internals HAL alsacore controls request callback +void InternalHalActionOnAlsaCtl(afb_req_t request); + +#endif /* _INTERNALS_HAL_ALSACORE_LINK_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-api-loader.c b/src/4a-internals-hal/4a-internals-hal-api-loader.c new file mode 100644 index 0000000..94891b8 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-api-loader.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include + +#include + +#include "4a-hal-utilities-verbs-loader.h" +#include "4a-internals-hal-api-loader.h" +#include "4a-internals-hal-alsacore-link.h" +#include "4a-internals-hal-cb.h" +#include "4a-internals-hal-mixer-link.h" + +// Default api to print log when apihandle not available +afb_api_t AFB_default; + +/******************************************************************************* + * Json parsing functions using controller * + ******************************************************************************/ + +// Config Section definition +static CtlSectionT ctrlSectionsDefault[] = +{ + { .key = "resources", .loadCB = PluginConfig }, + { .key = "halmixer", .loadCB = InternalHalHalMixerConfig }, + { .key = "onload", .loadCB = OnloadConfig }, + { .key = "controls", .loadCB = ControlConfig }, + { .key = "events", .loadCB = EventConfig }, + { .key = "halmap", .loadCB = InternalHalHalMapConfig }, + { .key = NULL } +}; + +/******************************************************************************* + * Dynamic HAL verbs' functions * + ******************************************************************************/ + +// Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT +static afb_verb_t InternalHalApiStaticVerbs[] = +{ + /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ + { .verb = "info", .callback = InternalHalInfo, .info = "List available streams/playbacks/captures/controls for this api" }, + { .verb = "subscribe", .callback = InternalHalSubscribe, .info = "Subscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, + { .verb = "unsubscribe", .callback = InternalHalUnsubscribe, .info = "Unsubscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, + { .verb = NULL } // Marker for end of the array +}; + +/******************************************************************************* + * Dynamic API functions for internals hal * + ******************************************************************************/ + +static int InternalHalInitOneApi(afb_api_t apiHandle) +{ + CtlConfigT *ctrlConfig; + struct HalData *currentHalData; + + if(! apiHandle) + return -1; + + // Hugely hack to make all V2 AFB_DEBUG to work in fileutils + AFB_default = apiHandle; + + // Retrieve section config from api handle + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) + return -2; + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) + return -3; + + // Fill HalDatadata structure + currentHalData->internal = 1; + + currentHalData->sndCardPath = (char *) ctrlConfig->uid; + currentHalData->info = (char *) ctrlConfig->info; + + currentHalData->author = (char *) ctrlConfig->author; + currentHalData->version = (char *) ctrlConfig->version; + currentHalData->date = (char *) ctrlConfig->date; + + currentHalData->internalHalData->apiHandle = apiHandle; + currentHalData->internalHalData->ctrlConfig = ctrlConfig; + + currentHalData->sndCardId = InternalHalGetCardIdByCardPath(apiHandle, currentHalData->sndCardPath); + + currentHalData->internalHalData->streamUpdates = afb_api_make_event(apiHandle, HAL_STREAM_UPDATES_EVENT_NAME); + if(! currentHalData->internalHalData->streamUpdates) + return -4; + + if(currentHalData->sndCardId < 0) + currentHalData->status = HAL_STATUS_UNAVAILABLE; + else + currentHalData->status = HAL_STATUS_AVAILABLE; + + // TBD JAI: handle refresh of hal status for dynamic card (/dev/by-id) + + return CtlConfigExec(apiHandle, ctrlConfig); +} + +static int InternalHalLoadOneApi(void *cbdata, afb_api_t apiHandle) +{ + int err; + CtlConfigT *ctrlConfig; + CtlSectionT *ctrlCurrentSections; + + if(! cbdata || ! apiHandle) + return -1; + + ctrlConfig = (CtlConfigT*) cbdata; + + // Save closure as api's data context + afb_api_set_userdata(apiHandle, ctrlConfig); + + // Add static controls verbs + if(HalUtlLoadVerbs(apiHandle, InternalHalApiStaticVerbs)) { + AFB_API_ERROR(apiHandle, "Load Section : fail to register static V2 verbs"); + return 1; + } + + ctrlCurrentSections = malloc(sizeof(ctrlSectionsDefault)); + memcpy(ctrlCurrentSections, ctrlSectionsDefault, sizeof(ctrlSectionsDefault)); + + // Load section for corresponding Api + if((err = CtlLoadSections(apiHandle, ctrlConfig, ctrlCurrentSections))) + return err; + + // Declare an event manager for this Api + afb_api_on_event(apiHandle, InternalHalDispatchApiEvent); + + // Init Api function (does not receive user closure ???) + afb_api_on_init(apiHandle, InternalHalInitOneApi); + + return 0; +} + +int InternalHalCreateApi(afb_api_t apiHandle, char *path, struct HalMgrData *halMgrData) +{ + CtlConfigT *ctrlConfig; + struct HalData *currentHalData; + + if(! apiHandle || ! path || ! halMgrData) + return -1; + + // Create one Api per file + ctrlConfig = CtlLoadMetaData(apiHandle, path); + if(! ctrlConfig) { + AFB_API_ERROR(apiHandle, "No valid control config file in:\n-- %s", path); + return -2; + } + + if(! ctrlConfig->api) { + AFB_API_ERROR(apiHandle, "API Missing from metadata in:\n-- %s", path); + return -3; + } + + // Allocation of current hal controller data + currentHalData = HalUtlAddHalToHalList(&halMgrData->halDataList); + if(! currentHalData) + return -4; + + currentHalData->apiName = (char *) ctrlConfig->api; + + // Stores hal data in controller config + setExternalData(ctrlConfig, (void *) currentHalData); + + // Allocation of the structure that will be used to store internal hal data + currentHalData->internalHalData = calloc(1, sizeof(struct InternalHalData)); + + // Create one API + if(! afb_api_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, InternalHalLoadOneApi, ctrlConfig)) + return -5; + + return 0; +} + +int InternalHalCreateAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData) +{ + int index, status = 0; + char *dirList, *fileName, *fullPath; + char filePath[CONTROL_MAXPATH_LEN]; + + filePath[CONTROL_MAXPATH_LEN - 1] = '\0'; + + json_object *configJ, *entryJ; + + if(! apiHandle || ! halMgrData) + return -1; + + // Hugely hack to make all V2 AFB_DEBUG to work in fileutils + AFB_default = apiHandle; + + AFB_API_NOTICE(apiHandle, "Begining to create all APIs"); + + dirList = getenv("CONTROL_CONFIG_PATH"); + if(! dirList) + dirList = CONTROL_CONFIG_PATH; + + configJ = CtlConfigScan(dirList, "hal"); + if(! configJ) { + AFB_API_WARNING(apiHandle, "No hal-(binder-middle-name)*.json config file(s) found in %s, 4a-hal-manager will only works with external hal", dirList); + return 0; + } + + // We load 1st file others are just warnings + for(index = 0; index < (int) json_object_array_length(configJ); index++) { + entryJ = json_object_array_get_idx(configJ, index); + + if(wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullPath, "filename", &fileName)) { + AFB_API_ERROR(apiHandle, "HOOPs invalid JSON entry = %s", json_object_get_string(entryJ)); + return -2; + } + + strncpy(filePath, fullPath, sizeof(filePath) - 1); + strncat(filePath, "/", sizeof(filePath) - 1); + strncat(filePath, fileName, sizeof(filePath) - 1); + + if(InternalHalCreateApi(apiHandle, filePath, halMgrData) < 0) + status--; + } + + return status; +} \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-api-loader.h b/src/4a-internals-hal/4a-internals-hal-api-loader.h new file mode 100644 index 0000000..fa878e2 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-api-loader.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _INTERNALS_HAL_API_LOADER_INCLUDE_ +#define _INTERNALS_HAL_API_LOADER_INCLUDE_ + +#include + +#include + +#include "4a-hal-utilities-data.h" + +// Verbs that can be use to create api +int InternalHalCreateApi(afb_api_t apiHandle, char *path, struct HalMgrData *halMgrData); +int InternalHalCreateAllApi(afb_api_t apiHandle, struct HalMgrData *halMgrData); + +#endif /* _INTERNALS_HAL_API_LOADER_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-cb.c b/src/4a-internals-hal/4a-internals-hal-cb.c new file mode 100644 index 0000000..0102d8d --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-cb.c @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include "4a-hal-utilities-data.h" + +#include "4a-internals-hal-cb.h" +#include "4a-internals-hal-alsacore-link.h" +#include "4a-internals-hal-mixer-link.h" +#include "4a-internals-hal-value-handler.h" + +/******************************************************************************* + * Internals HAL Event handler function * + ******************************************************************************/ + +void InternalHalDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ) +{ + int numid, idx = 0, cardidx; + + CtlConfigT *ctrlConfig; + CtlSourceT source; + + struct HalData *currentHalData; + struct InternalHalAlsaMapT *currentHalAlsaCtlsT; + + json_object *valuesJ, *normalizedValuesJ; + + AFB_API_DEBUG(apiHandle, "Evtname=%s [msg=%s]", evtLabel, json_object_get_string(eventJ)); + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + AFB_API_ERROR(apiHandle, "Can't get current internal hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + AFB_API_WARNING(apiHandle, "Can't get current internal hal controller data"); + return; + } + + // Extract sound card index from event + while(evtLabel[idx] != '\0' && evtLabel[idx] != ':') + idx++; + + if(evtLabel[idx] != '\0' && + sscanf(&evtLabel[idx + 1], "%d", &cardidx) == 1 && + currentHalData->sndCardId == cardidx) { + if(wrap_json_unpack(eventJ, "{s:i s:o !}", "id", &numid, "val", &valuesJ)) { + AFB_API_ERROR(apiHandle, "Invalid Alsa Event label=%s value=%s", evtLabel, json_object_get_string(eventJ)); + return; + } + + currentHalAlsaCtlsT = currentHalData->internalHalData->alsaMapT; + + // Search for corresponding numid in halCtls, if found, launch callback (if available) + for(idx = 0; idx < currentHalAlsaCtlsT->ctlsCount; idx++) { + if(currentHalAlsaCtlsT->ctls[idx].ctl.numid == numid) { + if(currentHalAlsaCtlsT->ctls[idx].action) { + source.uid = currentHalAlsaCtlsT->ctls[idx].action->uid; + source.api = currentHalAlsaCtlsT->ctls[idx].action->api; + source.request = NULL; + + (void) ActionExecOne(&source, currentHalAlsaCtlsT->ctls[idx].action, valuesJ); + } + else { + AFB_API_NOTICE(apiHandle, + "The alsa control id '%i' is corresponding to a known control but without any action registered", + numid); + } + + if((! currentHalAlsaCtlsT->ctls[idx].alsaControlEvent) || + InternalHalConvertJsonValues(apiHandle, + ¤tHalAlsaCtlsT->ctls[idx].ctl.alsaCtlProperties, + valuesJ, + &normalizedValuesJ, + CONVERSION_ALSACORE_TO_NORMALIZED) || + (afb_event_push(currentHalAlsaCtlsT->ctls[idx].alsaControlEvent, normalizedValuesJ) < 0)) { + AFB_API_ERROR(apiHandle, + "Couldn't generate an event for known halmap %s (alsa control id %i)", + currentHalAlsaCtlsT->ctls[idx].uid, + currentHalAlsaCtlsT->ctls[idx].ctl.numid); + } + + return; + } + } + + AFB_API_WARNING(apiHandle, + "Alsacore event with an unrecognized numid: %i, evtname=%s [msg=%s]", + numid, + evtLabel, + json_object_get_string(eventJ)); + + return; + } + + AFB_API_INFO(apiHandle, + "Not an alsacore event '%s' [msg=%s]", + evtLabel, + json_object_get_string(eventJ)); + + CtrlDispatchApiEvent(apiHandle, evtLabel, eventJ); +} + +/******************************************************************************* + * Internals HAL - 'halmixer' section parsing/handling functions * + ******************************************************************************/ + +int InternalHalHalMixerConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *MixerJ) +{ + int err = 0; + + CtlConfigT *ctrlConfig; + struct HalData *currentHalData; + + if(! apiHandle || ! section) + return -1; + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) + return -2; + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) + return -3; + + if(MixerJ) { + if(json_object_is_type(MixerJ, json_type_object)) + currentHalData->internalHalData->halMixerJ = MixerJ; + else + return -4; + + if(wrap_json_unpack(MixerJ, "{s:s}", "mixerapi", ¤tHalData->internalHalData->mixerApiName)) + return -5; + + wrap_json_unpack(MixerJ, "{s?:s}", "prefix", ¤tHalData->internalHalData->prefix); + } + else if(currentHalData->status == HAL_STATUS_AVAILABLE) { + err = InternalHalAttachToMixer(apiHandle); + if(err) { + AFB_API_ERROR(apiHandle, "Error %i while attaching to mixer", err); + return -6; + } + } + + return 0; +} + +/******************************************************************************* + * Internals HAL - 'halmap' section parsing/handling functions * + ******************************************************************************/ + +int InternalHalProcessOneHalMapObject(afb_api_t apiHandle, struct InternalHalAlsaMap *alsaMap, json_object *AlsaMapJ) +{ + char *action = NULL, *typename = NULL; + + json_object *alsaJ = NULL, *createAlsaCtlJ = NULL; + + AFB_API_DEBUG(apiHandle, "AlsaMapJ=%s", json_object_get_string(AlsaMapJ)); + + if(wrap_json_unpack(AlsaMapJ, "{s:s s?:s s:o s?:s !}", + "uid", &alsaMap->uid, + "info", &alsaMap->info, + "alsa", &alsaJ, + "action", &action)) { + AFB_API_ERROR(apiHandle, "Parsing error, map should only contains [label]|[uid]|[tag]|[info]|[alsa]|[action] in:\n-- %s", json_object_get_string(AlsaMapJ)); + return -1; + } + + if(wrap_json_unpack(alsaJ, "{s?:s s?:i s?:i s?:o !}", + "name", &alsaMap->ctl.name, + "numid", &alsaMap->ctl.numid, + "value", &alsaMap->ctl.value, + "create", &createAlsaCtlJ)) { + AFB_API_ERROR(apiHandle, "Parsing error, alsa json should only contains [name]|[numid]||[value]|[create] in:\n-- %s", json_object_get_string(alsaJ)); + return -2; + } + + if(createAlsaCtlJ) { + alsaMap->ctl.alsaCtlCreation = &alsaMap->ctl.alsaCtlProperties; + + if(wrap_json_unpack(createAlsaCtlJ, + "{s:s s:i s:i s:i s:i !}", + "type", &typename, + "count", &alsaMap->ctl.alsaCtlCreation->count, + "minval", &alsaMap->ctl.alsaCtlCreation->minval, + "maxval", &alsaMap->ctl.alsaCtlCreation->maxval, + "step", &alsaMap->ctl.alsaCtlCreation->step)) { + AFB_API_ERROR(apiHandle, "Parsing error, alsa creation json should only contains [type]|[count]|[minval]|[maxval]|[step] in:\n-- %s", json_object_get_string(alsaJ)); + return -3; + } + + if(typename) { + alsaMap->ctl.alsaCtlCreation->type = InternalHalMapsAlsaTypeToEnum(typename); + if(alsaMap->ctl.alsaCtlCreation->type == SND_CTL_ELEM_TYPE_NONE) { + AFB_API_ERROR(apiHandle, "Couldn't get alsa type from string %s in:\n-- %s", typename, json_object_get_string(alsaJ)); + return -4; + } + } + + if(! alsaMap->ctl.name) + alsaMap->ctl.name = (char *) alsaMap->uid; + } + else if(alsaMap->ctl.name && alsaMap->ctl.numid > 0) { + AFB_API_ERROR(apiHandle, + "Can't have both a control name (%s) and a control uid (%i) in alsa object:\n-- %s", + alsaMap->ctl.name, + alsaMap->ctl.numid, + json_object_get_string(alsaJ)); + return -5; + } + else if(! alsaMap->ctl.name && alsaMap->ctl.numid <= 0) { + AFB_API_ERROR(apiHandle, + "Need at least a control name or a control uid in alsa object:\n-- %s", + json_object_get_string(alsaJ)); + return -6; + } + + if(action) + alsaMap->actionJ = AlsaMapJ; + + return 0; +} + +int InternalHalHandleOneHalMapObject(afb_api_t apiHandle, char *cardId, struct InternalHalAlsaMap *alsaMap) +{ + int err; + + json_object *valueJ, *convertedValueJ = NULL; + + if(! (alsaMap->alsaControlEvent = afb_api_make_event(apiHandle, alsaMap->uid))) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to create event for current alsa control to load action using alsa object:\n-- %s", + json_object_get_string(alsaMap->actionJ)); + return -1; + } + + if(alsaMap->ctl.alsaCtlCreation) { + if(InternalHalCreateAlsaCtl(apiHandle, cardId, &alsaMap->ctl)) { + AFB_API_ERROR(apiHandle, "An error happened when trying to create a new alsa control"); + return -2; + } + } + else if(InternalHalUpdateAlsaCtlProperties(apiHandle, cardId, &alsaMap->ctl)) { + AFB_API_ERROR(apiHandle, "An error happened when trying to get existing alsa control info"); + return -3; + } + + if(alsaMap->ctl.value) { + // TBD JAI : handle alsa controls type + valueJ = json_object_new_int(alsaMap->ctl.value); + err = 0; + + if(InternalHalConvertJsonValues(apiHandle, &alsaMap->ctl.alsaCtlProperties, valueJ, &convertedValueJ, CONVERSION_NORMALIZED_TO_ALSACORE)) { + AFB_API_ERROR(apiHandle, "Error when trying to convert initiate value json '%s'", json_object_get_string(valueJ)); + err = -4; + } + else if(InternalHalSetAlsaCtlValue(apiHandle, cardId, alsaMap->ctl.numid, convertedValueJ)) { + AFB_API_ERROR(apiHandle, + "Error while trying to set initial value on alsa control %i, device '%s', value '%s'", + alsaMap->ctl.numid, + cardId, + json_object_get_string(valueJ)); + err = -5; + } + + json_object_put(valueJ); + + if(convertedValueJ) + json_object_put(convertedValueJ); + + if(err) + return err; + } + + if(alsaMap->actionJ) { + alsaMap->action = calloc(1, sizeof(CtlActionT)); + if(ActionLoadOne(apiHandle, alsaMap->action, alsaMap->actionJ, 0)) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to load action using alsa object:\n-- %s", + json_object_get_string(alsaMap->actionJ)); + return -6; + } + } + + if(afb_api_add_verb(apiHandle, alsaMap->uid, alsaMap->info, InternalHalActionOnAlsaCtl, (void *) alsaMap, NULL, 0, 0)) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to create verb for current alsa control to load action using alsa object:\n-- %s", + json_object_get_string(alsaMap->actionJ)); + return -7; + } + + return 0; +} + +int InternalHalProcessAllHalMap(afb_api_t apiHandle, json_object *AlsaMapJ, struct InternalHalAlsaMapT *currentInternalHalAlsaMapT) +{ + int idx, err = 0; + + struct InternalHalAlsaMap *ctlMaps; + + json_type alsaMapType; + + alsaMapType = json_object_get_type(AlsaMapJ); + switch(alsaMapType) { + case json_type_array: + currentInternalHalAlsaMapT->ctlsCount = (unsigned int) json_object_array_length(AlsaMapJ); + break; + + case json_type_object: + currentInternalHalAlsaMapT->ctlsCount = 1; + break; + + default: + currentInternalHalAlsaMapT->ctlsCount = 0; + currentInternalHalAlsaMapT->ctls = NULL; + AFB_API_WARNING(apiHandle, "Couldn't get content of 'halmap' section in : '%s'", json_object_get_string(AlsaMapJ)); + return -1; + } + + ctlMaps = calloc(currentInternalHalAlsaMapT->ctlsCount, sizeof(struct InternalHalAlsaMap)); + + for(idx = 0; idx < currentInternalHalAlsaMapT->ctlsCount; idx++) + err += InternalHalProcessOneHalMapObject(apiHandle, &ctlMaps[idx], alsaMapType == json_type_array ? json_object_array_get_idx(AlsaMapJ, idx) : AlsaMapJ); + + currentInternalHalAlsaMapT->ctls = ctlMaps; + + return err; +} + +int InternalHalHandleAllHalMap(afb_api_t apiHandle, int sndCardId, struct InternalHalAlsaMapT *currentInternalHalAlsaMapT) +{ + int idx, err = 0; + + char cardIdString[6]; + + snprintf(cardIdString, 6, "hw:%i", sndCardId); + + InternalHalSubscribeToAlsaCardEvent(apiHandle, cardIdString); + + for(idx = 0; idx < currentInternalHalAlsaMapT->ctlsCount; idx++) + err += InternalHalHandleOneHalMapObject(apiHandle, cardIdString, ¤tInternalHalAlsaMapT->ctls[idx]); + + return err; +} + +int InternalHalHalMapConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *AlsaMapJ) +{ + CtlConfigT *ctrlConfig; + struct HalData *currentHalData; + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) + return -1; + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) + return -2; + + if(AlsaMapJ) { + currentHalData->internalHalData->alsaMapT = calloc(1, sizeof(struct InternalHalAlsaMapT)); + + if(InternalHalProcessAllHalMap(apiHandle, AlsaMapJ, currentHalData->internalHalData->alsaMapT)) { + AFB_API_ERROR(apiHandle, "Failed to process 'halmap' section"); + return -3; + } + } + else if(currentHalData->status == HAL_STATUS_UNAVAILABLE) { + AFB_API_WARNING(apiHandle, "Hal is unavailable, 'halmap' section data can't be handle"); + return 1; + } + else if(currentHalData->sndCardId < 0) { + AFB_API_ERROR(apiHandle, "Hal alsa card id is not valid, 'halmap' section data can't be handle"); + return -6; + } + else if(! currentHalData->internalHalData->alsaMapT) { + AFB_API_WARNING(apiHandle, "'halmap' section data is empty"); + return 2; + } + else if(! (currentHalData->internalHalData->alsaMapT->ctlsCount > 0)) { + AFB_API_WARNING(apiHandle, "No alsa controls defined in 'halmap' section"); + return 3; + } + else if(InternalHalHandleAllHalMap(apiHandle, currentHalData->sndCardId, currentHalData->internalHalData->alsaMapT)) { + AFB_API_ERROR(apiHandle, "Failed to handle 'halmap' section"); + return -9; + } + + return 0; +} + +/******************************************************************************* + * Internals HAL verbs functions * + ******************************************************************************/ + +json_object *InternalHalGetJsonArrayForMixerDataTable(afb_api_t apiHandle, + struct InternalHalMixerData **mixerDataList, + enum MixerDataType dataType) +{ + json_object *mixerDataArrayJ, *currentMixerDataJ; + + struct InternalHalMixerData *currentMixerData; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Api handle is not valid"); + return NULL; + } + + mixerDataArrayJ = json_object_new_array(); + if(! mixerDataArrayJ) { + AFB_API_ERROR(apiHandle, "Can't generate json mixer data array"); + return NULL; + } + + currentMixerData = *mixerDataList; + + while(currentMixerData) { + switch(dataType) { + case MIXER_DATA_STREAMS: + wrap_json_pack(¤tMixerDataJ, + "{s:s s:s}", + "name", currentMixerData->verb, + "cardId", currentMixerData->streamCardId); + break; + + case MIXER_DATA_PLAYBACKS: + case MIXER_DATA_CAPTURES : + wrap_json_pack(¤tMixerDataJ, + "{s:s s:s}", + "name", currentMixerData->verb, + "mixer-name", currentMixerData->verbToCall, + "uid", currentMixerData->streamCardId ? currentMixerData->streamCardId : "none"); + break; + + default: + json_object_put(mixerDataArrayJ); + return NULL; + } + json_object_array_add(mixerDataArrayJ, currentMixerDataJ); + + currentMixerData = currentMixerData->next; + } + + return mixerDataArrayJ; +} + +json_object *InternalHalGetJsonArrayForControls(afb_api_t apiHandle, struct InternalHalAlsaMapT *currentAlsaMapDataT) +{ + unsigned int idx; + + json_object *alsaMapDataArray, *currentAlsaMapData; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); + return NULL; + } + + if(! currentAlsaMapDataT) { + AFB_API_ERROR(apiHandle, "Can't get Alsa map data table to handle"); + return NULL; + } + + if(! (alsaMapDataArray = json_object_new_array())) { + AFB_API_ERROR(apiHandle, "Can't generate json mixer data array"); + return NULL; + } + + for(idx = 0; idx < currentAlsaMapDataT->ctlsCount; idx++) { + wrap_json_pack(¤tAlsaMapData, + "{s:s s:s}", + "name", currentAlsaMapDataT->ctls[idx].uid, + "info", currentAlsaMapDataT->ctls[idx].info ? currentAlsaMapDataT->ctls[idx].info : "none"); + + json_object_array_add(alsaMapDataArray, currentAlsaMapData); + } + + return alsaMapDataArray; +} + +void InternalHalInfo(afb_req_t request) +{ + char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; + + afb_api_t apiHandle; + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + + json_object *requestJson, *toReturnJ = NULL, *requestAnswer, *streamsArray, *playbacksArray, *capturesArray, *controlsArray; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); + return; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + afb_req_fail(request, "hal_controller_config", "Can't get current internal hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + afb_req_fail(request, "hal_controller_data", "Can't get current internal hal controller data"); + return; + } + + if(! (requestJson = afb_req_json(request))) { + AFB_REQ_NOTICE(request, "Can't get request json"); + } + else if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) { + apiToCall = currentHalData->internalHalData->mixerApiName; + if(! apiToCall) { + afb_req_fail(request, "mixer_api", "Can't get mixer api"); + return; + } + + if(InternalHalGetInfoFromMixer(apiHandle, apiToCall, requestJson, &toReturnJ, &returnedError, &returnedInfo)) { + afb_req_fail_f(request, + "mixer_info", + "Call to mixer info verb didn't succeed with status '%s' and info '%s'", + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + return; + } + + afb_req_success(request, toReturnJ, "Mixer requested data"); + return; + } + + streamsArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, + ¤tHalData->internalHalData->streamsData, + MIXER_DATA_STREAMS); + if(! streamsArray) { + afb_req_fail(request, "streams_data", "Didn't succeed to generate streams data array"); + return; + } + + playbacksArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, + ¤tHalData->internalHalData->playbacksData, + MIXER_DATA_PLAYBACKS); + if(! playbacksArray) { + afb_req_fail(request, "playbacks_data", "Didn't succeed to generate playbacks data array"); + return; + } + + capturesArray = InternalHalGetJsonArrayForMixerDataTable(apiHandle, + ¤tHalData->internalHalData->capturesData, + MIXER_DATA_CAPTURES); + if(! capturesArray) { + afb_req_fail(request, "captures_data", "Didn't succeed to generate captures data array"); + return; + } + + controlsArray = InternalHalGetJsonArrayForControls(apiHandle, + currentHalData->internalHalData->alsaMapT); + if(! controlsArray) { + afb_req_fail(request, "controls_data", "Didn't succeed to generate controls data array"); + return; + } + + wrap_json_pack(&requestAnswer, + "{s:o s:o s:o s:o}", + "streams", streamsArray, + "playbacks", playbacksArray, + "captures", capturesArray, + "controls", controlsArray); + + afb_req_success(request, requestAnswer, "Requested data"); +} + +void InternalHalSubscribeUnsubscribe(afb_req_t request, enum SubscribeUnsubscribeType subscribeUnsubscribeType) +{ + int arrayIdx, searchIdx, count, subscriptionFound, subscriptionDoneNb = 0; + + char *currentSubscriptionString; + + afb_api_t apiHandle; + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData; + struct InternalHalMixerData *currentStreamData; + struct InternalHalAlsaMapT *InternalHalAlsaMapT; + + json_object *requestJson, *requestedSubscriptionsJ, *requestedSubscriptionJ = NULL; + json_type requestJsonType; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); + return; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + afb_req_fail(request, "hal_controller_config", "Can't get current internal hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + afb_req_fail(request, "hal_controller_data", "Can't get current internal hal controller data"); + return; + } + + if(! currentHalData->internalHalData) { + afb_req_fail(request, "hal_controller_data", "Current internal hal data is not valid"); + return; + } + + InternalHalAlsaMapT = currentHalData->internalHalData->alsaMapT; + + if(! (requestJson = afb_req_json(request))) { + afb_req_fail(request, "request_json", "Can't get request json"); + return; + } + + if(wrap_json_unpack(requestJson, "{s:o}", "events", &requestedSubscriptionsJ)) { + afb_req_fail(request, "request_json", "Request json invalid"); + return; + } + + requestJsonType = json_object_get_type(requestedSubscriptionsJ); + switch(requestJsonType) { + case json_type_string: + count = 1; + requestedSubscriptionJ = requestedSubscriptionsJ; + break; + + case json_type_array: + count = (int) json_object_array_length(requestedSubscriptionsJ); + break; + + default: + afb_req_fail(request, "request_json", "Request json invalid"); + return; + } + + for(arrayIdx = 0; arrayIdx < count; arrayIdx++) { + if(requestJsonType == json_type_array) { + requestedSubscriptionJ = json_object_array_get_idx(requestedSubscriptionsJ, arrayIdx); + if(! json_object_is_type(requestedSubscriptionJ, json_type_string)) { + afb_req_fail_f(request, "request_json", "Request json number %i in array invalid", arrayIdx); + return; + } + } + + subscriptionFound = 0; + currentSubscriptionString = (char *) json_object_get_string(requestedSubscriptionJ); + + if(! strcasecmp(currentSubscriptionString, HAL_STREAM_UPDATES_EVENT_NAME)) { + if(currentHalData->internalHalData->streamUpdates && + subscribeUnsubscribeType == SUBSCRIPTION && + afb_req_subscribe(request, currentHalData->internalHalData->streamUpdates)) { + afb_req_fail_f(request, + "request_stream_list_updates_event", + "Error while trying to subscribe to stream list updates event"); + return; + } + else if(currentHalData->internalHalData->streamUpdates && + subscribeUnsubscribeType == UNSUBSCRIPTION && + afb_req_unsubscribe(request, currentHalData->internalHalData->streamUpdates)) { + afb_req_fail_f(request, + "request_stream_list_updates_event", + "Error while trying to unsubscribe to stream list updates event"); + return; + } + + subscriptionFound = 1; + subscriptionDoneNb++; + } + + currentStreamData = currentHalData->internalHalData->streamsData; + while(currentStreamData && + (! subscriptionFound)) { + if(! strcasecmp(currentSubscriptionString, currentStreamData->verb)) { + if(currentStreamData->event && + subscribeUnsubscribeType == SUBSCRIPTION && + afb_req_subscribe(request, currentStreamData->event)) { + afb_req_fail_f(request, + "request_stream_event", + "Error while trying to subscribe to %s stream events", + currentStreamData->verb); + return; + } + else if(currentStreamData->event && + subscribeUnsubscribeType == UNSUBSCRIPTION && + afb_req_unsubscribe(request, currentStreamData->event)) { + afb_req_fail_f(request, + "request_stream_event", + "Error while trying to unsubscribe to %s stream events", + currentStreamData->verb); + return; + } + + subscriptionFound = 1; + subscriptionDoneNb++; + + break; + } + + currentStreamData = currentStreamData->next; + } + + searchIdx = 0; + while((searchIdx < (InternalHalAlsaMapT ? InternalHalAlsaMapT->ctlsCount : 0)) && + (! subscriptionFound)) { + if(! strcasecmp(currentSubscriptionString, InternalHalAlsaMapT->ctls[searchIdx].uid)) { + if(InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent && + subscribeUnsubscribeType == SUBSCRIPTION && + afb_req_subscribe(request, InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent)) { + afb_req_fail_f(request, + "request_control_event", + "Error while trying to subscribe to %s halmap controls events", + InternalHalAlsaMapT->ctls[searchIdx].uid); + return; + } + else if(InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent && + subscribeUnsubscribeType == UNSUBSCRIPTION && + afb_req_unsubscribe(request, InternalHalAlsaMapT->ctls[searchIdx].alsaControlEvent)) { + afb_req_fail_f(request, + "request_stream_event", + "Error while trying to unsubscribe to %s halmap controls events", + InternalHalAlsaMapT->ctls[searchIdx].uid); + return; + } + + subscriptionFound = 1; + subscriptionDoneNb++; + + break; + } + + searchIdx++; + } + } + + if(subscriptionDoneNb == 0) + afb_req_fail_f(request, + "events_not_found", + "%s failed, event(s) were not found", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription"); + if(subscriptionDoneNb == count) + afb_req_success_f(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed for all the %i events requested", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb); + else if(subscriptionDoneNb < count) + afb_req_success_f(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed but only to %i events requested out of %i", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb, + count); + else + afb_req_success_f(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed but to more events than requested (%i out of %i)", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb, + count); +} + +void InternalHalSubscribe(afb_req_t request) +{ + InternalHalSubscribeUnsubscribe(request, SUBSCRIPTION); +} + +void InternalHalUnsubscribe(afb_req_t request) +{ + InternalHalSubscribeUnsubscribe(request, UNSUBSCRIPTION); +} diff --git a/src/4a-internals-hal/4a-internals-hal-cb.h b/src/4a-internals-hal/4a-internals-hal-cb.h new file mode 100644 index 0000000..ff35656 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-cb.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _INTERNALS_HAL_CB_INCLUDE_ +#define _INTERNALS_HAL_CB_INCLUDE_ + +#include + +#include + +#include + +// Enum for the type of subscription/subscription +enum SubscribeUnsubscribeType { + SUBSCRIPTION = 1, + UNSUBSCRIPTION = 2 +}; + +// Internals HAL event handler function +void InternalHalDispatchApiEvent(afb_api_t apiHandle, const char *evtLabel, json_object *eventJ); + +// Internals HAL sections parsing functions +int InternalHalHalMixerConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *MixerJ); +int InternalHalHalMapConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *AlsaMapJ); + +// Internals HAL verbs functions +void InternalHalInfo(afb_req_t request); +void InternalHalSubscribe(afb_req_t request); +void InternalHalUnsubscribe(afb_req_t request); + +#endif /* _HALMGR_CB_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-mixer-link.c b/src/4a-internals-hal/4a-internals-hal-mixer-link.c new file mode 100644 index 0000000..95e9099 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-mixer-link.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include "4a-hal-utilities-data.h" + +#include "4a-hal-utilities-hal-streams-handler.h" +#include "4a-hal-utilities-verbs-loader.h" + +#include "../4a-hal-manager/4a-hal-manager.h" + +#include "4a-internals-hal-mixer-link.h" +#include "4a-internals-hal-cb.h" + +/******************************************************************************* + * Internals HAL handle mixer calls functions * + ******************************************************************************/ + +int InternalHalHandleMixerData(afb_api_t apiHandle, + struct InternalHalMixerData **mixerDataList, + json_object *currentDataJ, + enum MixerDataType dataType) +{ + int idx, mixerDataNb, verbStart, size; + int err = (int) MIXER_NO_ERROR; + + char *currentDataVerbName, *currentStreamCardId; + + json_type currentDataType; + json_object *currentJ; + + struct InternalHalMixerData *currentMixerData; + + currentDataType = json_object_get_type(currentDataJ); + switch(currentDataType) { + case json_type_object: + mixerDataNb = 1; + break; + case json_type_array: + mixerDataNb = (unsigned int) json_object_array_length(currentDataJ); + break; + default: + mixerDataNb = 0; + AFB_API_ERROR(apiHandle, "No data returned"); + return (int) MIXER_ERROR_DATA_EMPTY; + } + + for(idx = 0; idx < mixerDataNb; idx++) { + if(currentDataType == json_type_array) + currentJ = json_object_array_get_idx(currentDataJ, (int) idx); + else + currentJ = currentDataJ; + + if(wrap_json_unpack(currentJ, "{s:s}", "verb", ¤tDataVerbName)) { + AFB_API_ERROR(apiHandle, "Can't find verb in current data object"); + err += (int) MIXER_ERROR_DATA_NAME_UNAVAILABLE; + } + else if(dataType == MIXER_DATA_STREAMS && wrap_json_unpack(currentJ, "{s:s}", "alsa", ¤tStreamCardId)) { + AFB_API_ERROR(apiHandle, "Can't find card id in current data object"); + err += (int) MIXER_ERROR_DATA_CARDID_UNAVAILABLE; + } + else { + switch(dataType) { + case MIXER_DATA_STREAMS: + size = (int) strlen(currentDataVerbName); + for(verbStart = 0; verbStart < size; verbStart++) { + if(currentDataVerbName[verbStart] == '#') { + verbStart++; + break; + } + } + + if(verbStart == size) + verbStart = 0; + + if(! HalUtlAddStreamDataAndCreateStreamVerb(apiHandle, + ¤tDataVerbName[verbStart], + currentDataVerbName, + currentStreamCardId)) { + AFB_API_ERROR(apiHandle, + "Error while adding stream '%s'", + currentDataVerbName); + err += (int) MIXER_ERROR_STREAM_NOT_ADDED; + } + + break; + + case MIXER_DATA_PLAYBACKS: + case MIXER_DATA_CAPTURES: + currentMixerData = HalUtlAddMixerDataToMixerDataList(mixerDataList); + + currentMixerData->verb = strdup((dataType == MIXER_DATA_PLAYBACKS) ? HAL_PLAYBACK_ID : HAL_CAPTURE_ID); + currentMixerData->verbToCall = strdup(currentDataVerbName); + + if((! currentMixerData->verb) || + (! currentMixerData->verbToCall)) { + HalUtlRemoveSelectedMixerData(mixerDataList, currentMixerData); + err += (int) MIXER_ERROR_STREAM_ALLOCATION_FAILED; + } + break; + + default: + break; + } + } + } + + if(dataType == MIXER_DATA_PLAYBACKS) { + if(afb_api_add_verb(apiHandle, + HAL_PLAYBACK_ID, + "Playback action transferred to mixer", + HalUtlActionOnPlayback, + (void *) *mixerDataList, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for playbacks : '%s'", HAL_PLAYBACK_ID); + err += (int) MIXER_ERROR_PLAYBACK_VERB_NOT_CREATED; + } + } + + if(dataType == MIXER_DATA_CAPTURES) { + if(afb_api_add_verb(apiHandle, + HAL_CAPTURE_ID, + "Capture action transferred to mixer", + HalUtlActionOnCapture, + (void *) *mixerDataList, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for captures : '%s'", HAL_CAPTURE_ID); + err += (int) MIXER_ERROR_CAPTURE_VERB_NOT_CREATED; + } + } + + return err; +} + +int InternalHalHandleMixerAttachResponse(afb_api_t apiHandle, struct InternalHalData *currentHalSpecificData, json_object *mixerResponseJ) +{ + int err = (int) MIXER_NO_ERROR; + + json_object *mixerStreamsJ = NULL, *mixerPlaybacksJ = NULL, *mixerCapturesJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); + return (int) MIXER_ERROR_API_UNAVAILABLE; + } + + if(wrap_json_unpack(mixerResponseJ, "{s?:o s?:o s?:o}", "streams", &mixerStreamsJ, "playbacks", &mixerPlaybacksJ, "captures", &mixerCapturesJ)) { + AFB_API_ERROR(apiHandle, "Can't get streams|playbacks|captures object in '%s'", json_object_get_string(mixerResponseJ)); + return (int) MIXER_ERROR_DATA_UNAVAILABLE; + } + + if(mixerStreamsJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->streamsData, mixerStreamsJ, MIXER_DATA_STREAMS); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer streams data '%s'", json_object_get_string(mixerStreamsJ)); + } + + if(mixerPlaybacksJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->playbacksData, mixerPlaybacksJ, MIXER_DATA_PLAYBACKS); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer playbacks data '%s'", json_object_get_string(mixerPlaybacksJ)); + } + + if(mixerCapturesJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->capturesData, mixerCapturesJ, MIXER_DATA_CAPTURES); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer captures data '%s'", json_object_get_string(mixerCapturesJ)); + } + + if(! currentHalSpecificData->streamsData) { + AFB_API_WARNING(apiHandle, "No stream detected in mixer response, %s verb won't be created", HAL_ALL_STREAMS_VERB); + } + else if(afb_api_add_verb(apiHandle, + HAL_ALL_STREAMS_VERB, + "Send a stream action on all streams", + HalUtlActionOnAllStream, + (void *) currentHalSpecificData->streamsData, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for all streams : '%s'", HAL_ALL_STREAMS_VERB); + return (int) MIXER_ERROR_ALL_STREAMS_VERB_NOT_CREATED; + } + + return err; +} + +int InternalHalAttachToMixer(afb_api_t apiHandle) +{ + int err = 0, mixerError; + + char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; + + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData, *concurentHalData = NULL; + + json_object *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); + return -1; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + AFB_API_ERROR(apiHandle, "Can't get current hal controller config"); + return -2; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + AFB_API_ERROR(apiHandle, "Can't get current hal controller data"); + return -3; + } + + switch(currentHalData->status) { + case HAL_STATUS_UNAVAILABLE: + AFB_API_ERROR(apiHandle, "Seems that the hal corresponding card was not found by alsacore at startup"); + return -4; + + case HAL_STATUS_READY: + AFB_API_NOTICE(apiHandle, "Seems that the hal mixer is already initialized"); + return 1; + + case HAL_STATUS_AVAILABLE: + break; + } + + concurentHalData = HalUtlSearchReadyHalDataByCardId(HalMngGetHalDataList(), currentHalData->sndCardId); + if(concurentHalData) { + AFB_API_ERROR(apiHandle, + "Trying to attach mixer for hal '%s' but the alsa device %i is already in use with mixer by hal '%s'", + currentHalData->apiName, + currentHalData->sndCardId, + concurentHalData->apiName); + return -5; + } + + apiToCall = currentHalData->internalHalData->mixerApiName; + if(! apiToCall) { + AFB_API_ERROR(apiHandle, "Can't get mixer api"); + return -6; + } + + if(afb_api_call_sync(apiHandle, + apiToCall, + MIXER_ATTACH_VERB, + json_object_get(currentHalData->internalHalData->halMixerJ), + &responseJ, + &returnedError, + &returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + MIXER_ATTACH_VERB, + apiToCall, + returnedError ? returnedError : "not returned", + returnedInfo ? returnedInfo : "not returned"); + err = -7; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + MIXER_ATTACH_VERB, + apiToCall); + err = -8; + } + else { + mixerError = InternalHalHandleMixerAttachResponse(apiHandle, currentHalData->internalHalData, responseJ); + if(mixerError != (int) MIXER_NO_ERROR) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but this warning was risen by response decoder : %i '%s'", + MIXER_ATTACH_VERB, + apiToCall, + mixerError, + json_object_get_string(responseJ)); + err = -9; + } + else { + AFB_API_NOTICE(apiHandle, + "Seems that %s call to api %s succeed with no warning raised : '%s'", + MIXER_ATTACH_VERB, + apiToCall, + json_object_get_string(responseJ)); + currentHalData->status = HAL_STATUS_READY; + } + } + + if(responseJ) + json_object_put(responseJ); + + free(returnedError); + free(returnedInfo); + + return err; +} + +int InternalHalGetInfoFromMixer(afb_api_t apiHandle, + char *apiToCall, + json_object *requestJson, + json_object **toReturnJ, + char **returnedError, + char **returnedInfo) +{ + json_object *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); + return -1; + } + + if(! apiToCall) { + AFB_API_ERROR(apiHandle, "Can't get mixer api"); + return -2; + } + + if(! requestJson) { + AFB_API_ERROR(apiHandle, "Can't get request json"); + return -3; + } + + if(*returnedError || *returnedInfo) { + AFB_API_ERROR(apiHandle, "'returnedError' and 'returnedInfo' strings should be empty and set to 'NULL'"); + return -4; + } + + if(*toReturnJ) { + AFB_API_ERROR(apiHandle, "'toReturnJ' should be empty and set to 'NULL'"); + return -5; + } + + if(afb_api_call_sync(apiHandle, + apiToCall, + MIXER_INFO_VERB, + json_object_get(requestJson), + &responseJ, + returnedError, + returnedInfo)) { + AFB_API_ERROR(apiHandle, + "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", + apiToCall, + MIXER_INFO_VERB, + *returnedError ? *returnedError : "not returned", + *returnedInfo ? *returnedInfo : "not returned"); + return -6; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + MIXER_INFO_VERB, + apiToCall); + json_object_put(responseJ); + return -7; + } + else { + AFB_API_NOTICE(apiHandle, + "Seems that %s call to api %s succeed with no warning raised : '%s'", + MIXER_INFO_VERB, + apiToCall, + json_object_get_string(responseJ)); + *toReturnJ = responseJ; + } + + return 0; +} \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-mixer-link.h b/src/4a-internals-hal/4a-internals-hal-mixer-link.h new file mode 100644 index 0000000..6c1f827 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-mixer-link.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ +#define _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ + +#include + +#include + +#include + +#include + +#include "4a-hal-utilities-data.h" + +#define MIXER_ATTACH_VERB "attach" +#define MIXER_INFO_VERB "info" + +#define HAL_PLAYBACK_ID "playback" +#define HAL_CAPTURE_ID "capture" + +#define HAL_ALL_STREAMS_VERB "all-streams" + +// Enum for the type of object sent back by the mixer +enum MixerDataType { + MIXER_DATA_STREAMS = 1, + MIXER_DATA_PLAYBACKS = 2, + MIXER_DATA_CAPTURES = 3 +}; + +// Enum for the type of error detected +enum MixerStatus { + MIXER_NO_ERROR=0, + MIXER_ERROR_API_UNAVAILABLE=-1, + MIXER_ERROR_DATA_UNAVAILABLE=-2, + MIXER_ERROR_DATA_EMPTY =-3, + MIXER_ERROR_PLAYBACK_VERB_NOT_CREATED =-4, + MIXER_ERROR_CAPTURE_VERB_NOT_CREATED =-5, + MIXER_ERROR_ALL_STREAMS_VERB_NOT_CREATED =-6, + MIXER_ERROR_DATA_NAME_UNAVAILABLE=-10, + MIXER_ERROR_DATA_CARDID_UNAVAILABLE=-100, + MIXER_ERROR_STREAM_NOT_ADDED =-1000, + MIXER_ERROR_STREAM_ALLOCATION_FAILED =-10000 +}; + +// Internals HAL handle mixer calls functions +int InternalHalAttachToMixer(afb_api_t apiHandle); +int InternalHalGetInfoFromMixer(afb_api_t apiHandle, + char *apiToCall, + json_object *requestJson, + json_object **toReturnJ, + char **returnedError, + char **returnedInfo); + +#endif /* _INTERNALS_HAL_SOFTMIXER_LINK_INCLUDE_ */ \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-value-handler.c b/src/4a-internals-hal/4a-internals-hal-value-handler.c new file mode 100644 index 0000000..64083a9 --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-value-handler.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 + +#include + +#include + +#include "4a-internals-hal-value-handler.h" +#include "4a-internals-hal-alsacore-link.h" + +/******************************************************************************* + * Simple conversion value to/from percentage functions * + ******************************************************************************/ + +int InternalHalConvertValueToPercentage(double val, double min, double max) +{ + double range; + + range = max - min; + if(range <= 0) + return -INT_MAX; + + val -= min; + + return (int) round(val / range * 100); +} + +int InternalHalConvertPercentageToValue(int percentage, int min, int max) +{ + int range; + + range = max - min; + if(range <= 0) + return -INT_MAX; + + return (int) round((double) percentage * (double) range * 0.01 + (double) min); +} + +/******************************************************************************* + * Convert json object from percentage to value * + ******************************************************************************/ + +int InternalHalConvertJsonValueForIntegerControl(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int initialValue, convertedValue; + + if(! json_object_is_type(toConvertJ, json_type_int)) { + AFB_API_ERROR(apiHandle, + "Can't convert json value, unrecognized json format (must be an integer) : '%s'", + json_object_get_string(toConvertJ)); + return -1; + } + + initialValue = json_object_get_int(toConvertJ); + + switch(requestedConversion) { + case CONVERSION_NORMALIZED_TO_ALSACORE: + if(initialValue < 0 || initialValue > 100) { + AFB_API_ERROR(apiHandle, + "Cannot convert '%i' value, value should be between 0 and 100 ('%s')", + initialValue, + json_object_get_string(toConvertJ)); + return -2; + } + + convertedValue = InternalHalConvertPercentageToValue(initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(convertedValue == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -3; + } + + if(alsaCtlProperties->step) { + // Round value to the nearest step + convertedValue = (int) round((double) convertedValue / (double) alsaCtlProperties->step); + convertedValue *= alsaCtlProperties->step; + } + break; + + case CONVERSION_ALSACORE_TO_NORMALIZED: + convertedValue = InternalHalConvertValueToPercentage(initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(convertedValue == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + initialValue, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -4; + } + + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert '%i' value, unrecognized conversion type : '%i'", + initialValue, + (int) requestedConversion); + *ConvertedJ = NULL; + return -5; + } + + *ConvertedJ = json_object_new_int(convertedValue); + + return 0; +} + +int InternalHalConvertJsonValueForBooleanControl(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int initialValue; + + switch(json_object_get_type(toConvertJ)) { + case json_type_int: + initialValue = json_object_get_int(toConvertJ); + break; + + case json_type_boolean: + initialValue = json_object_get_boolean(toConvertJ); + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert json value, unrecognized format (must be an integer or a boolean) : '%s'", + json_object_get_string(toConvertJ)); + return -1; + } + + if(initialValue < 0 || initialValue > 1) { + AFB_API_ERROR(apiHandle, + "Cannot convert '%i' value, value should be 0 or 1 ('%s')", + initialValue, + json_object_get_string(toConvertJ)); + return -2; + } + + switch(requestedConversion) { + case CONVERSION_NORMALIZED_TO_ALSACORE: + *ConvertedJ = json_object_new_int(initialValue); + break; + + case CONVERSION_ALSACORE_TO_NORMALIZED: + *ConvertedJ = json_object_new_boolean(initialValue); + break; + + default: + AFB_API_ERROR(apiHandle, + "Can't convert '%i' value, unrecognized conversion type : '%i'", + initialValue, + (int) requestedConversion); + *ConvertedJ = NULL; + return -3; + } + + return 0; +} + +int InternalHalConvertJsonValues(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion) +{ + int conversionError = 0, idx, count; + + json_type toConvertType; + json_object *toConvertObjectJ, *convertedValueJ, *convertedArrayJ; + + *ConvertedJ = NULL; + + toConvertType = json_object_get_type(toConvertJ); + count = (toConvertType == json_type_array) ? (int) json_object_array_length(toConvertJ) : 1; + + convertedArrayJ = json_object_new_array(); + + for(idx = 0; idx < count; idx++) { + if(toConvertType == json_type_array) + toConvertObjectJ = json_object_array_get_idx(toConvertJ, idx); + else + toConvertObjectJ = toConvertJ; + + switch(alsaCtlProperties->type) { + case SND_CTL_ELEM_TYPE_INTEGER: + case SND_CTL_ELEM_TYPE_INTEGER64: + conversionError = InternalHalConvertJsonValueForIntegerControl(apiHandle, + alsaCtlProperties, + toConvertObjectJ, + &convertedValueJ, + requestedConversion); + if(conversionError) { + AFB_API_ERROR(apiHandle, + "Error %i happened in when trying to convert index %i for integer control ('%s')", + conversionError, + idx, + json_object_get_string(toConvertObjectJ)); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + break; + + case SND_CTL_ELEM_TYPE_BOOLEAN: + conversionError = InternalHalConvertJsonValueForBooleanControl(apiHandle, + alsaCtlProperties, + toConvertObjectJ, + &convertedValueJ, + requestedConversion); + if(conversionError) { + AFB_API_ERROR(apiHandle, + "Error %i happened in when trying to convert index %i for boolean control ('%s')", + conversionError, + idx, + json_object_get_string(toConvertObjectJ)); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + break; + + default: + AFB_API_ERROR(apiHandle, + "Conversion not handle for the alsa control type %i", + (int) alsaCtlProperties->type); + json_object_put(convertedArrayJ); + return -(idx + 1); + } + + json_object_array_put_idx(convertedArrayJ, idx, convertedValueJ); + } + + *ConvertedJ = convertedArrayJ; + + return 0; +} + +int InternalHalChangePreviousValuesUsingJson(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *requestedPercentageVariationJ, + json_object *previousControlValuesJ, + json_object **ChangedJ) +{ + int requestedPercentageVariation, requestedVariation, toChangeValue, changedValue, idx, count; + + char *requestedPercentageVariationString, *conversionEnd; + + json_object *toChangeObjectJ, *changedArrayJ; + + *ChangedJ = NULL; + + requestedPercentageVariationString = (char *) json_object_get_string(requestedPercentageVariationJ); + + requestedPercentageVariation = (int) strtol(requestedPercentageVariationString, &conversionEnd, 10); + if(conversionEnd == requestedPercentageVariationString) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease an integer control \ + but string sent in json is not a increase/decrease string : '%s'", + json_object_get_string(requestedPercentageVariationJ)); + return -1; + } + + if(alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER && + alsaCtlProperties->type != SND_CTL_ELEM_TYPE_INTEGER64) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease values on a incompatible \ + control type (%i), control type must be an integer", + alsaCtlProperties->type); + return -2; + } + + if(requestedPercentageVariation < -100 || requestedPercentageVariation > 100) { + AFB_API_ERROR(apiHandle, + "Tried to increase/decrease values but specified change is \ + not a valid percentage, it should be between -100 and 100"); + return -3; + } + + requestedVariation = InternalHalConvertPercentageToValue((int) abs(requestedPercentageVariation), + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + if(requestedVariation == -INT_MAX) { + AFB_API_ERROR(apiHandle, + "Didn't succeed to convert %i (using min %i et max %i)", + requestedPercentageVariation, + alsaCtlProperties->minval, + alsaCtlProperties->maxval); + return -4; + } + + if(requestedPercentageVariation < 0) + requestedVariation = -requestedVariation; + + count = (int) json_object_array_length(previousControlValuesJ); + + changedArrayJ = json_object_new_array(); + + for(idx = 0; idx < count; idx++) { + toChangeObjectJ = json_object_array_get_idx(previousControlValuesJ, idx); + + if(! json_object_is_type(toChangeObjectJ, json_type_int)) { + AFB_API_ERROR(apiHandle, + "Current json object %s is not an integer", + json_object_get_string(toChangeObjectJ)); + return -(10 + idx); + } + + toChangeValue = json_object_get_int(toChangeObjectJ); + + if((toChangeValue + requestedVariation) < alsaCtlProperties->minval) + changedValue = alsaCtlProperties->minval; + else if((toChangeValue + requestedVariation) > alsaCtlProperties->maxval) + changedValue = alsaCtlProperties->maxval; + else + changedValue = toChangeValue + requestedVariation; + + json_object_array_put_idx(changedArrayJ, idx, json_object_new_int(changedValue)); + } + + *ChangedJ = changedArrayJ; + + return 0; +} \ No newline at end of file diff --git a/src/4a-internals-hal/4a-internals-hal-value-handler.h b/src/4a-internals-hal/4a-internals-hal-value-handler.h new file mode 100644 index 0000000..f0288ac --- /dev/null +++ b/src/4a-internals-hal/4a-internals-hal-value-handler.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet + * + * 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 _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ +#define _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ + +#include + +#include + +#include + +#include "4a-internals-hal-alsacore-link.h" + +// Enum for the type of conversion requested +enum ConversionType { + CONVERSION_NORMALIZED_TO_ALSACORE = 1, + CONVERSION_ALSACORE_TO_NORMALIZED = 2 +}; + +// Simple conversion value to/from percentage functions +int InternalHalConvertValueToPercentage(double val, double min, double max); +int InternalHalConvertPercentageToValue(int percentage, int min, int max); + +// Convert json object from percentage to value +int InternalHalConvertJsonValues(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *toConvertJ, + json_object **ConvertedJ, + enum ConversionType requestedConversion); + +// Increase/Decrease previous values using percentage passed in Json +int InternalHalChangePreviousValuesUsingJson(afb_api_t apiHandle, + struct InternalHalAlsaCtlProperties *alsaCtlProperties, + json_object *requestedPercentageVariationJ, + json_object *previousControlValuesJ, + json_object **ChangedJ); + +#endif /* _INTERNALS_HAL_VALUE_CONVERSION_INCLUDE_ */ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..b863c5f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,51 @@ +########################################################################### +# Copyright 2015, 2016, 2017, 2018 IoT.bzh +# +# author: Fulup Ar Foll +# contrib: Romain Forlot +# conrtib: Jonathan Aillet +# +# 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(4a-hal) + + # Define project Targets + add_library(${TARGET_NAME} MODULE + 4a-hal-manager/4a-hal-manager.c + 4a-hal-manager/4a-hal-manager-cb.c + 4a-internals-hal/4a-internals-hal-alsacore-link.c + 4a-internals-hal/4a-internals-hal-api-loader.c + 4a-internals-hal/4a-internals-hal-cb.c + 4a-internals-hal/4a-internals-hal-mixer-link.c + 4a-internals-hal/4a-internals-hal-value-handler.c + ) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "" + LABELS "BINDING" # Need to be in V3 + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + 4a-hal-utilities + ) + + # Define target includes for this target client + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ) -- cgit 1.2.3-korg