diff options
Diffstat (limited to '4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c')
-rw-r--r-- | 4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c | 243 |
1 files changed, 243 insertions, 0 deletions
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 new file mode 100644 index 0000000..94891b8 --- /dev/null +++ b/4a-hal/4a-internals-hal/4a-internals-hal-api-loader.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author Jonathan Aillet <jonathan.aillet@iot.bzh> + * + * 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 <stdio.h> +#include <string.h> + +#include <filescan-utils.h> +#include <wrap-json.h> + +#include <afb/afb-binding.h> + +#include <ctl-config.h> + +#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 |