/* * 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 - Linked list cleaning function declaration * ******************************************************************************/ void HalUtlFreeSelectedProbedDeviceAllocation(struct InternalHalProbedDevice *probedDeviceToFree); void HalUtlFreeSelectedMixerDataAllocation(struct InternalHalMixerData *mixerDataToFree); void HalUtlFreeSelectedHalMapDataAllocation(struct InternalHalAlsaMap *halMapDataToFree); void HalUtlFreeSelectedHalAllocation(struct HalData *halDataToFree); /******************************************************************************* * Internal Hal - Generic function for linked list * ******************************************************************************/ void *HalUtlAddNodeInList(struct cds_list_head *listHead, enum LinkedListType listType) { void *returned = NULL; struct cds_list_head *nodeToAdd; if(! listHead) return NULL; switch(listType) { case LINKED_LIST_FOR_DEPENDENCIES_DATA: returned = calloc(1, sizeof(struct InternalHalProbedDevice)); if(! returned) return NULL; nodeToAdd = &((struct InternalHalProbedDevice *) returned)->node; break; case LINKED_LIST_FOR_MIXER_DATA: returned = calloc(1, sizeof(struct InternalHalMixerData)); if(! returned) return NULL; nodeToAdd = &((struct InternalHalMixerData *) returned)->node; break; case LINKED_LIST_FOR_HALMAP_DATA: returned = calloc(1, sizeof(struct InternalHalAlsaMap)); if(! returned) return NULL; nodeToAdd = &((struct InternalHalAlsaMap *) returned)->node; ((struct InternalHalAlsaMap *) returned)->cardNb = HAL_UNKNOWN_DEVICE; break; case LINKED_LIST_FOR_HAL_DATA: returned = calloc(1, sizeof(struct HalData)); if(! returned) return NULL; nodeToAdd = &((struct HalData *) returned)->node; break; default: return NULL; } cds_list_add_tail(nodeToAdd, listHead); return returned; } int HalUtlRemoveNodeFromList(struct cds_list_head *listHead, void *dataToRemove, enum LinkedListType listType) { if(! listHead || cds_list_empty(listHead) || ! dataToRemove) return -1; switch(listType) { case LINKED_LIST_FOR_DEPENDENCIES_DATA: cds_list_del(&((struct InternalHalProbedDevice *) dataToRemove)->node); HalUtlFreeSelectedProbedDeviceAllocation((struct InternalHalProbedDevice *) dataToRemove); break; case LINKED_LIST_FOR_MIXER_DATA: cds_list_del(&((struct InternalHalMixerData *) dataToRemove)->node); HalUtlFreeSelectedMixerDataAllocation((struct InternalHalMixerData *) dataToRemove); break; case LINKED_LIST_FOR_HALMAP_DATA: cds_list_del(&((struct InternalHalAlsaMap *) dataToRemove)->node); HalUtlFreeSelectedHalMapDataAllocation((struct InternalHalAlsaMap *) dataToRemove); break; case LINKED_LIST_FOR_HAL_DATA: cds_list_del(&((struct HalData *) dataToRemove)->node); HalUtlFreeSelectedHalAllocation((struct HalData *) dataToRemove); break; default: return -2; } return 0; } int HalUtlRemoveAllNodeFromList(struct cds_list_head *listHead, enum LinkedListType listType) { int nodesRemoved = 0; struct cds_list_head *nodeToRemove, *savedNode; if(! listHead) return -1; if(cds_list_empty(listHead)) return 0; cds_list_for_each_safe(nodeToRemove, savedNode, listHead) { switch(listType) { case LINKED_LIST_FOR_DEPENDENCIES_DATA: if(HalUtlRemoveSelectedProbedDeviceFromList(listHead, cds_list_entry(nodeToRemove, struct InternalHalProbedDevice, node))) return -2; break; case LINKED_LIST_FOR_MIXER_DATA: if(HalUtlRemoveSelectedMixerData(listHead, cds_list_entry(nodeToRemove, struct InternalHalMixerData, node))) return -3; break; case LINKED_LIST_FOR_HALMAP_DATA: if(HalUtlRemoveSelectedHalMapData(listHead, cds_list_entry(nodeToRemove, struct InternalHalAlsaMap, node))) return -4; break; case LINKED_LIST_FOR_HAL_DATA: if(HalUtlRemoveSelectedHalFromList(listHead, cds_list_entry(nodeToRemove, struct HalData, node))) return -5; break; default: return -6; } nodesRemoved++; } return nodesRemoved; } int HalUtlGetNumberOfNodesInList(struct cds_list_head *listHead) { int numberOfNodes = 0; struct cds_list_head *listNode; if(! listHead) return -1; if(cds_list_empty(listHead)) return 0; cds_list_for_each(listNode, listHead) numberOfNodes++; return numberOfNodes; } /******************************************************************************* * Internal Hal - Probed devices structure handling functions * ******************************************************************************/ enum ProbedDeviceClasses HalUtlGetProbedDeviceClassFromString(char *probedDeviceString) { if(! probedDeviceString) return INVALID_PROBED_DEVICE; if(! strcasecmp("static", probedDeviceString)) return STATIC_PROBED_DEVICE; if(! strcasecmp("dynamic", probedDeviceString)) return DYNAMIC_PROBED_DEVICE; if(! strcasecmp("mandatory", probedDeviceString)) return MANDATORY_PROBED_DEVICE; return INVALID_PROBED_DEVICE; } char *HalUtlGetProbedDeviceClassString(enum ProbedDeviceClasses deviceClass) { switch(deviceClass) { case STATIC_PROBED_DEVICE: return "static"; case DYNAMIC_PROBED_DEVICE: return "dynamic"; case MANDATORY_PROBED_DEVICE: return "mandatory"; case INVALID_PROBED_DEVICE: return "invalid"; default: return "unknown"; } return NULL; } int HalUtlIsDependencySelected(struct InternalHalProbedDevice *probedDevice, enum DependencyStatus requestedStatus) { if(! probedDevice) { return 0; } switch(requestedStatus) { case UNAVAILABLE_DEPENDENCY: if(! probedDevice->deviceData) return 1; else return 0; case AVAILABLE_DEPENDENCY: if(probedDevice->deviceData) return 1; else return 0; case ALL_DEPENDENCY: return 1; default: return 0; } } void HalUtlFreeSelectedProbedDeviceDataAllocation(struct InternalHalDeviceData *probedDeviceDataToFree) { if(! probedDeviceDataToFree) return; free(probedDeviceDataToFree->extendedCardNb); free(probedDeviceDataToFree->cardId); free(probedDeviceDataToFree->cardShortName); free(probedDeviceDataToFree->cardLongName); free(probedDeviceDataToFree->cardDriver); free(probedDeviceDataToFree->cardMixerName); free(probedDeviceDataToFree->cardComponents); free(probedDeviceDataToFree->playbackDeviceId); free(probedDeviceDataToFree->playbackDeviceName); free(probedDeviceDataToFree); } void HalUtlFreeSelectedProbedDeviceAllocation(struct InternalHalProbedDevice *probedDeviceToFree) { if(! probedDeviceToFree) return; free(probedDeviceToFree->uid); HalUtlFreeSelectedProbedDeviceDataAllocation(probedDeviceToFree->deviceData); if(probedDeviceToFree->requestedDeviceJ) json_object_put(probedDeviceToFree->requestedDeviceJ); free(probedDeviceToFree); } struct InternalHalProbedDevice *HalUtlAddProbedDeviceToProbedDeviceList(struct cds_list_head *probedDevicesListHead) { return (struct InternalHalProbedDevice *) HalUtlAddNodeInList(probedDevicesListHead, LINKED_LIST_FOR_DEPENDENCIES_DATA); } int HalUtlRemoveSelectedProbedDeviceFromList(struct cds_list_head *probedDevicesListHead, struct InternalHalProbedDevice *probedDeviceToRemove) { return HalUtlRemoveNodeFromList(probedDevicesListHead, (void *) probedDeviceToRemove, LINKED_LIST_FOR_DEPENDENCIES_DATA); } int HalUtlRemoveAllProbedDevicesFromList(struct cds_list_head *probedDevicesListHead) { return HalUtlRemoveAllNodeFromList(probedDevicesListHead, LINKED_LIST_FOR_DEPENDENCIES_DATA); } int HalUtlGetNumberOfProbedDevicesInList(struct cds_list_head *probedDevicesListHead) { return HalUtlGetNumberOfNodesInList(probedDevicesListHead); } struct InternalHalProbedDevice *HalUtlSearchProbedDeviceDataById(struct cds_list_head *probedDevicesListHead, char *uid) { struct InternalHalProbedDevice *currentProbedDevice; if(! probedDevicesListHead || cds_list_empty(probedDevicesListHead) || ! uid) return NULL; cds_list_for_each_entry(currentProbedDevice, probedDevicesListHead, node) { if(! strcmp(uid, currentProbedDevice->uid)) return currentProbedDevice; } return NULL; } int HalUtlGetProbedDeviceCardNbUsingUid(struct cds_list_head *probedDevicesListHead, char *uid) { struct InternalHalProbedDevice *currentProbedDeviceData; currentProbedDeviceData = HalUtlSearchProbedDeviceDataById(probedDevicesListHead, uid); if(! currentProbedDeviceData || ! currentProbedDeviceData->deviceData) return HAL_UNKNOWN_DEVICE; return currentProbedDeviceData->deviceData->cardNb; } struct InternalHalDeviceData *HalUtlAllocateAndFillProbedDeviceDataUsingInfoGetResponse(json_object *responseJ) { struct InternalHalDeviceData *currentProbedDeviceData; char *cardId, *cardShortName, *cardLongName, *cardDriver, *cardMixerName, *cardComponents, *playbackDeviceId = NULL, *playbackDeviceName = NULL; if(! responseJ) return NULL; currentProbedDeviceData = calloc(1, sizeof(struct InternalHalDeviceData)); if(! currentProbedDeviceData) return NULL; currentProbedDeviceData->cardNb = HAL_UNKNOWN_DEVICE; currentProbedDeviceData->playbackDeviceNb = HAL_UNKNOWN_DEVICE; if(wrap_json_unpack(responseJ, "{s:i, s:s, s:s, s:s, s:s, s:s, s:s, s?:i, s?:s, s?:s !}", "cardNb", ¤tProbedDeviceData->cardNb, "cardId", &cardId, "cardShortName", &cardShortName, "cardLongName", &cardLongName, "cardDriver", &cardDriver, "cardMixerName", &cardMixerName, "cardComponents", &cardComponents, "playbackDeviceNb", ¤tProbedDeviceData->playbackDeviceNb, "playbackDeviceId", &playbackDeviceId, "playbackDeviceName", &playbackDeviceName) || currentProbedDeviceData->cardNb == HAL_UNKNOWN_DEVICE || (currentProbedDeviceData->playbackDeviceNb == HAL_UNKNOWN_DEVICE && asprintf(¤tProbedDeviceData->extendedCardNb, "hw:%i", currentProbedDeviceData->cardNb) < 0) || (currentProbedDeviceData->playbackDeviceNb != HAL_UNKNOWN_DEVICE && asprintf(¤tProbedDeviceData->extendedCardNb, "hw:%i,%i", currentProbedDeviceData->cardNb, currentProbedDeviceData->playbackDeviceNb) < 0)) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardId = strdup(cardId); if(! currentProbedDeviceData->cardId) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardShortName = strdup(cardShortName); if(! currentProbedDeviceData->cardShortName) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardLongName = strdup(cardLongName); if(! currentProbedDeviceData->cardLongName) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardDriver = strdup(cardDriver); if(! currentProbedDeviceData->cardDriver) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardMixerName = strdup(cardMixerName); if(! currentProbedDeviceData->cardMixerName) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } currentProbedDeviceData->cardComponents = strdup(cardComponents); if(! currentProbedDeviceData->cardComponents) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } if(playbackDeviceId) { currentProbedDeviceData->playbackDeviceId = strdup(playbackDeviceId); if(! currentProbedDeviceData->playbackDeviceId) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } } if(playbackDeviceName) { currentProbedDeviceData->playbackDeviceName = strdup(playbackDeviceName); if(! currentProbedDeviceData->playbackDeviceName) { HalUtlFreeSelectedProbedDeviceDataAllocation(currentProbedDeviceData); return NULL; } } return currentProbedDeviceData; } json_object *HalUtlGetCompactJsonForSpecificDependencies(afb_api_t apiHandle, struct InternalHalProbedDevice *requestedProbedDevice) { int wrapRet; char *cardNb; json_object *requestedProbedDeviceJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! requestedProbedDevice) { AFB_API_ERROR(apiHandle, "Requested dependency is not valid"); return NULL; } if(! requestedProbedDevice->deviceData || requestedProbedDevice->deviceData->cardNb == HAL_UNKNOWN_DEVICE) cardNb = NULL; else cardNb = requestedProbedDevice->deviceData->extendedCardNb; wrapRet = wrap_json_pack(&requestedProbedDeviceJ, "{s:s s:s}", "uid", requestedProbedDevice->uid, "cardNb", cardNb ? cardNb : "none"); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate (uid: '%s') dependency compact json object", requestedProbedDevice->uid); return NULL; } return requestedProbedDeviceJ; } json_object *HalUtlGetFullJsonForSpecificDependencies(afb_api_t apiHandle, struct InternalHalProbedDevice *requestedProbedDevice) { int wrapRet; json_object *requestedProbedDeviceJ, *additionalInfoJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! requestedProbedDevice) { AFB_API_ERROR(apiHandle, "Requested dependency is not valid"); return NULL; } wrapRet = wrap_json_pack(&requestedProbedDeviceJ, "{s:s s:s s:b}", "uid", requestedProbedDevice->uid, "class", HalUtlGetProbedDeviceClassString(requestedProbedDevice->deviceClass), "available", requestedProbedDevice->deviceData ? 1 : 0); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate first part of requested (uid: '%s') dependency full json object", requestedProbedDevice->uid); return NULL; } if(! requestedProbedDevice->deviceData || requestedProbedDevice->deviceData->cardNb == HAL_UNKNOWN_DEVICE) return requestedProbedDeviceJ; wrapRet = wrap_json_pack(&additionalInfoJ, "{s:i s:s s:s s:s s:s s:s s:s s:s}", "cardNb", requestedProbedDevice->deviceData->cardNb, "cardId", requestedProbedDevice->deviceData->cardId, "cardShortName", requestedProbedDevice->deviceData->cardShortName, "cardLongName", requestedProbedDevice->deviceData->cardLongName, "cardDriver", requestedProbedDevice->deviceData->cardDriver, "cardMixerName", requestedProbedDevice->deviceData->cardMixerName, "cardComponents", requestedProbedDevice->deviceData->cardComponents, "extendedCardNb", requestedProbedDevice->deviceData->extendedCardNb); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate second part of requested (uid: '%s') dependency full json object", requestedProbedDevice->uid); json_object_put(requestedProbedDeviceJ); return NULL; } wrap_json_object_add(requestedProbedDeviceJ, additionalInfoJ); if(requestedProbedDevice->deviceData->playbackDeviceNb == HAL_UNKNOWN_DEVICE) return requestedProbedDeviceJ; wrapRet = wrap_json_pack(&additionalInfoJ, "{s:i s:s s:s}", "playbackDeviceNb", requestedProbedDevice->deviceData->playbackDeviceNb, "playbackDeviceId", requestedProbedDevice->deviceData->playbackDeviceId, "playbackDeviceName", requestedProbedDevice->deviceData->playbackDeviceName); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate third part of requested (uid: '%s') dependency full json object", requestedProbedDevice->uid); json_object_put(requestedProbedDeviceJ); return NULL; } wrap_json_object_add(requestedProbedDeviceJ, additionalInfoJ); return requestedProbedDeviceJ; } json_object *HalUtlGetJsonForSpecificDependencies(afb_api_t apiHandle, struct InternalHalProbedDevice *requestedProbedDevice, enum DependencyInfoJsonFormat jsonFormat) { json_object *requestedProbedDeviceJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! requestedProbedDevice) { AFB_API_ERROR(apiHandle, "Requested dependency is not valid"); return NULL; } switch(jsonFormat) { case DEPENDENCY_COMPACT_JSON: requestedProbedDeviceJ = HalUtlGetCompactJsonForSpecificDependencies(apiHandle,requestedProbedDevice); if(! requestedProbedDeviceJ) { AFB_API_ERROR(apiHandle, "An error happened when generating compact json for selected dependency (uid: '%s')", requestedProbedDevice->uid); return NULL; } return requestedProbedDeviceJ; case DEPENDENCY_FULL_JSON: requestedProbedDeviceJ = HalUtlGetFullJsonForSpecificDependencies(apiHandle,requestedProbedDevice); if(! requestedProbedDeviceJ) { AFB_API_ERROR(apiHandle, "An error happened when generating full json for selected dependency (uid: '%s')", requestedProbedDevice->uid); return NULL; } return requestedProbedDeviceJ; default: AFB_API_ERROR(apiHandle, "Unrecognized requested json format"); return NULL; } } json_object *HalUtlGetJsonForSpecificDependenciesUsingUid(afb_api_t apiHandle, struct cds_list_head *probedDevicesListHead, char *uid, enum DependencyInfoJsonFormat jsonFormat) { json_object *requestedProbedDeviceJ; struct InternalHalProbedDevice *requestedProbedDevice; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! probedDevicesListHead) { AFB_API_ERROR(apiHandle, "Probed device list is not valid"); return NULL; } if(cds_list_empty(probedDevicesListHead)) { AFB_API_INFO(apiHandle, "Probed device list is empty"); return NULL; } if(! uid) { AFB_API_ERROR(apiHandle, "Requested dependency uid is not valid"); return NULL; } requestedProbedDevice = HalUtlSearchProbedDeviceDataById(probedDevicesListHead, uid); if(! requestedProbedDevice) { AFB_API_ERROR(apiHandle, "Requested dependency uid ('%s) was not found in probed device list", uid); return NULL; } requestedProbedDeviceJ = HalUtlGetJsonForSpecificDependencies(apiHandle, requestedProbedDevice, jsonFormat); if(! requestedProbedDeviceJ) { AFB_API_ERROR(apiHandle, "An error happened when generating json for selected dependency (uid: '%s')", requestedProbedDevice->uid); return NULL; } return requestedProbedDeviceJ; } json_object *HalUtlGetJsonArrayForSelectedDependencies(afb_api_t apiHandle, struct cds_list_head *probedDevicesListHead, enum DependencyInfoJsonFormat jsonFormat, enum DependencyStatus requestedStatus) { json_object *requestedProbedDeviceJ, *requestedDependenciesInfoJ; struct InternalHalProbedDevice *currentProbedDevice; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! probedDevicesListHead || cds_list_empty(probedDevicesListHead)) { AFB_API_ERROR(apiHandle, "Probed device list is not valid or empty"); return NULL; } requestedDependenciesInfoJ = json_object_new_array(); if(! requestedDependenciesInfoJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate probed devices (dependencies) json array"); return NULL; } cds_list_for_each_entry(currentProbedDevice, probedDevicesListHead, node) { requestedProbedDeviceJ = NULL; if(HalUtlIsDependencySelected(currentProbedDevice, requestedStatus)) { requestedProbedDeviceJ = HalUtlGetJsonForSpecificDependencies(apiHandle, currentProbedDevice, jsonFormat); if(! requestedProbedDeviceJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to get json for probed devices (dependencies) with uid : '%s'", currentProbedDevice->uid); json_object_put(requestedDependenciesInfoJ); return NULL; } } if(requestedProbedDeviceJ) json_object_array_add(requestedDependenciesInfoJ, requestedProbedDeviceJ); } return requestedDependenciesInfoJ; } json_object *HalUtlGetJsonArrayForAvailableDependencies(afb_api_t apiHandle, struct cds_list_head *probedDevicesListHead, enum DependencyInfoJsonFormat jsonFormat) { json_object *requestedDependenciesInfoJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! probedDevicesListHead) { AFB_API_ERROR(apiHandle, "Probed device list is not valid"); return NULL; } if(cds_list_empty(probedDevicesListHead)) { AFB_API_INFO(apiHandle, "Probed device list is empty"); return NULL; } requestedDependenciesInfoJ = HalUtlGetJsonArrayForSelectedDependencies(apiHandle, probedDevicesListHead, jsonFormat, AVAILABLE_DEPENDENCY); if(! requestedDependenciesInfoJ) { AFB_API_ERROR(apiHandle, "Didn't succeed get available devices (dependencies) info"); return NULL; } if(! json_object_array_length(requestedDependenciesInfoJ)) { AFB_API_INFO(apiHandle, "No available devices (dependencies) in list"); json_object_put(requestedDependenciesInfoJ); return NULL; } return requestedDependenciesInfoJ; } json_object *HalUtlGetJsonArrayForAllDependencies(afb_api_t apiHandle, struct cds_list_head *probedDevicesListHead, enum DependencyInfoJsonFormat jsonFormat) { json_object *requestedDependenciesInfoJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! probedDevicesListHead) { AFB_API_ERROR(apiHandle, "Probed device list is not valid"); return NULL; } if(cds_list_empty(probedDevicesListHead)) { AFB_API_INFO(apiHandle, "Probed device list is empty"); return NULL; } requestedDependenciesInfoJ = HalUtlGetJsonArrayForSelectedDependencies(apiHandle, probedDevicesListHead, jsonFormat, ALL_DEPENDENCY); if(! requestedDependenciesInfoJ) { AFB_API_ERROR(apiHandle, "Didn't succeed get all devices (dependencies) info"); return NULL; } if(! json_object_array_length(requestedDependenciesInfoJ)) { AFB_API_ERROR(apiHandle, "No devices (dependencies) info returned but list is not empty"); json_object_put(requestedDependenciesInfoJ); return NULL; } return requestedDependenciesInfoJ; } /******************************************************************************* * Internal Hal - Streams data handling functions * ******************************************************************************/ void HalUtlFreeSelectedMixerDataAllocation(struct InternalHalMixerData *mixerDataToFree) { if(! mixerDataToFree) return; free(mixerDataToFree->verb); free(mixerDataToFree->verbToCall); free(mixerDataToFree->streamCardId); free(mixerDataToFree); } struct InternalHalMixerData *HalUtlAddMixerDataToMixerDataList(struct cds_list_head *mixerDataListHead) { return (struct InternalHalMixerData *) HalUtlAddNodeInList(mixerDataListHead, LINKED_LIST_FOR_MIXER_DATA); } int HalUtlRemoveSelectedMixerData(struct cds_list_head *mixerDataListHead, struct InternalHalMixerData *mixerDataToRemove) { return HalUtlRemoveNodeFromList(mixerDataListHead, (void *) mixerDataToRemove, LINKED_LIST_FOR_MIXER_DATA); } int HalUtlRemoveAllMixerData(struct cds_list_head *mixerDataListHead) { return HalUtlRemoveAllNodeFromList(mixerDataListHead, LINKED_LIST_FOR_MIXER_DATA); } int HalUtlGetNumberOfMixerDataInList(struct cds_list_head *mixerDataListHead) { return HalUtlGetNumberOfNodesInList(mixerDataListHead); } struct InternalHalMixerData *HalUtlSearchMixerDataByProperties(struct cds_list_head *mixerDataListHead, char *verb, char *verbToCall, char *streamCardId) { struct InternalHalMixerData *currentMixerData; if(! mixerDataListHead || cds_list_empty(mixerDataListHead) || ! verb || ! verbToCall) return NULL; cds_list_for_each_entry(currentMixerData, mixerDataListHead, node) { if(! strcmp(verb, currentMixerData->verb) && ! strcmp(verbToCall, currentMixerData->verbToCall) && ((! streamCardId && ! currentMixerData->streamCardId) || (streamCardId && currentMixerData->streamCardId && ! strcmp(streamCardId, currentMixerData->streamCardId)))) return currentMixerData; } return NULL; } json_object *HalUtlGetJsonArrayForSpecificMixerData(afb_api_t apiHandle, struct InternalHalMixerData *mixerData) { int wrapRet; json_object *currentMixerDataJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(! mixerData) { AFB_API_ERROR(apiHandle, "Mixer data to use to generate json object are empty"); return NULL; } wrapRet = wrap_json_pack(¤tMixerDataJ, "{s:s s:s}", "name", mixerData->verb, "cardId", mixerData->streamCardId); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate current mixer json object"); return NULL; } return currentMixerDataJ; } json_object *HalUtlGetJsonArrayForAllMixersData(afb_api_t apiHandle, struct cds_list_head *mixerDataListHead) { json_object *mixerDataArrayJ, *currentMixerDataJ; struct InternalHalMixerData *currentMixerData; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Api handle is not valid"); return NULL; } if(cds_list_empty(mixerDataListHead)) { AFB_API_INFO(apiHandle, "Mixer data list is empty"); return NULL; } mixerDataArrayJ = json_object_new_array(); if(! mixerDataArrayJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate requested mixer data json array"); return NULL; } cds_list_for_each_entry(currentMixerData, mixerDataListHead, node) { currentMixerDataJ = HalUtlGetJsonArrayForSpecificMixerData(apiHandle, currentMixerData); if(! currentMixerDataJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to generate current mixer data json object"); json_object_put(mixerDataArrayJ); return NULL; } json_object_array_add(mixerDataArrayJ, currentMixerDataJ); } if(! json_object_array_length(mixerDataArrayJ)) { AFB_API_ERROR(apiHandle, "No mixer info returned but list is not empty"); json_object_put(mixerDataArrayJ); return NULL; } return mixerDataArrayJ; } /******************************************************************************* * Internal Hal - Alsa Map data handling functions * ******************************************************************************/ void HalUtlFreeSelectedHalMapDataAllocation(struct InternalHalAlsaMap *halMapDataToFree) { free(halMapDataToFree->targetUid); free(halMapDataToFree->targetInfo); free(halMapDataToFree->targetedDependency); free(halMapDataToFree->uid); free(halMapDataToFree->info); free(halMapDataToFree->action); if(halMapDataToFree->ctl.name != halMapDataToFree->uid) free(halMapDataToFree->ctl.name); if(halMapDataToFree->ctl.alsaCtlCreation) { free(halMapDataToFree->ctl.alsaCtlCreation->enums); free(halMapDataToFree->ctl.alsaCtlCreation->dbscale); free(halMapDataToFree->ctl.alsaCtlCreation); } else if(halMapDataToFree->ctl.alsaCtlProperties) { free(halMapDataToFree->ctl.alsaCtlProperties->enums); free(halMapDataToFree->ctl.alsaCtlProperties->dbscale); free(halMapDataToFree->ctl.alsaCtlProperties); } free(halMapDataToFree); } struct InternalHalAlsaMap *HalUtlAddHalMapDataToHalMapDataList(struct cds_list_head *halMapListHead) { return (struct InternalHalAlsaMap *) HalUtlAddNodeInList(halMapListHead, LINKED_LIST_FOR_HALMAP_DATA); } int HalUtlRemoveSelectedHalMapData(struct cds_list_head *halMapListHead, struct InternalHalAlsaMap *halMapDataToRemove) { return HalUtlRemoveNodeFromList(halMapListHead, (void *) halMapDataToRemove, LINKED_LIST_FOR_HALMAP_DATA); } int HalUtlRemoveAllHalMapData(struct cds_list_head *halMapListHead) { return HalUtlRemoveAllNodeFromList(halMapListHead, LINKED_LIST_FOR_HALMAP_DATA); } int HalUtlGetNumberOfHalMapDataInList(struct cds_list_head *halMapListHead) { return HalUtlGetNumberOfNodesInList(halMapListHead); } json_object *HalUtGetJsonArrayForSpecificHalMapControl(afb_api_t apiHandle, struct InternalHalAlsaMap *currentHalMapData) { int wrapRet; json_object *currentAlsaMapInfoJ, *additionalInfoJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); return NULL; } if(! currentHalMapData) { AFB_API_ERROR(apiHandle, "ALSA control data to use to generate json object are empty"); return NULL; } wrapRet = wrap_json_pack(¤tAlsaMapInfoJ, "{s:s s:s s:s}", "name", currentHalMapData->uid, "info", currentHalMapData->info ? currentHalMapData->info : "none", "target", currentHalMapData->targetedDependency); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate current halmap control first part of info json object"); return NULL; } if(currentHalMapData->cardNb == HAL_UNKNOWN_DEVICE || ! currentHalMapData->ctl.alsaCtlProperties) { json_object_object_add(currentAlsaMapInfoJ, "available", json_object_new_boolean(0)); } else { wrapRet = wrap_json_pack(&additionalInfoJ, "{s:b s:i s:s}", "available", 1, "cardNb", currentHalMapData->cardNb, "cardControlName", currentHalMapData->ctl.name ? currentHalMapData->ctl.name : "'N/A'"); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate current halmap control second part of info json object"); json_object_put(currentAlsaMapInfoJ); return NULL; } wrap_json_object_add(currentAlsaMapInfoJ, additionalInfoJ); } wrapRet = wrap_json_pack(&additionalInfoJ, "{s:s s:s}", "halmap-uid", currentHalMapData->targetUid, "halmap-info", currentHalMapData->targetInfo ? currentHalMapData->targetInfo : "none"); if(wrapRet) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate current halmap control third part of info json object"); json_object_put(currentAlsaMapInfoJ); return NULL; } wrap_json_object_add(currentAlsaMapInfoJ, additionalInfoJ); return currentAlsaMapInfoJ; } json_object *HalUtGetJsonArrayForAllHalMapControls(afb_api_t apiHandle, struct cds_list_head *halMapListHead) { struct InternalHalAlsaMap *currentHalMapData; json_object *halMapDataArrayJ, *currentHalMapDataJ; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); return NULL; } if(! halMapListHead) { AFB_API_ERROR(apiHandle, "HalMap data list is not valid"); return NULL; } if(cds_list_empty(halMapListHead)) { AFB_API_INFO(apiHandle, "HalMap data list is empty"); return NULL; } halMapDataArrayJ = json_object_new_array(); if(! halMapDataArrayJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate ALSA controls data json array"); return NULL; } cds_list_for_each_entry(currentHalMapData, halMapListHead, node) { currentHalMapDataJ = HalUtGetJsonArrayForSpecificHalMapControl(apiHandle, currentHalMapData); if(! currentHalMapDataJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to generate current HalMap data json object"); json_object_put(halMapDataArrayJ); return NULL; } json_object_array_add(halMapDataArrayJ, currentHalMapDataJ); } if(! json_object_array_length(halMapDataArrayJ)) { AFB_API_ERROR(apiHandle, "No HalMap info returned but list is not empty"); json_object_put(halMapDataArrayJ); return NULL; } return halMapDataArrayJ; } /******************************************************************************* * Hal data handling functions * ******************************************************************************/ void HalUtlFreeSelectedHalAllocation(struct HalData *halDataToFree) { if(! halDataToFree) return; if(halDataToFree->internal) { free(halDataToFree->internalHalData->mixerApiName); free(halDataToFree->internalHalData->prefix); HalUtlRemoveAllProbedDevicesFromList(&halDataToFree->internalHalData->probedDevicesListHead); HalUtlRemoveAllMixerData(&halDataToFree->internalHalData->streamsDataListHead); HalUtlRemoveAllHalMapData(&halDataToFree->internalHalData->halMapListHead); free(halDataToFree->internalHalData); } free(halDataToFree); } struct HalData *HalUtlAddHalToHalList(struct cds_list_head *halDataListHead) { return (struct HalData *) HalUtlAddNodeInList(halDataListHead, LINKED_LIST_FOR_HAL_DATA); } int HalUtlRemoveSelectedHalFromList(struct cds_list_head *halDataListHead, struct HalData *halToRemove) { return HalUtlRemoveNodeFromList(halDataListHead, (void *) halToRemove, LINKED_LIST_FOR_HAL_DATA); } int HalUtlRemoveAllHalFromList(struct cds_list_head *halDataListHead) { return HalUtlRemoveAllNodeFromList(halDataListHead, LINKED_LIST_FOR_HAL_DATA); } int HalUtlGetNumberOfHalInList(struct cds_list_head *halDataListHead) { return HalUtlGetNumberOfNodesInList(halDataListHead); } struct HalData *HalUtlSearchHalDataByApiName(struct cds_list_head *halDataListHead, char *apiName) { struct HalData *currentHalData; if(! halDataListHead || cds_list_empty(halDataListHead) || ! apiName) return NULL; cds_list_for_each_entry(currentHalData, halDataListHead, node) { if(! strcmp(apiName, currentHalData->apiName)) return currentHalData; } return NULL; } /******************************************************************************* * Hal Manager data handling functions * ******************************************************************************/ int 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; HalUtlRemoveAllHalFromList(&halMgrData->halDataListHead); free(halMgrData->apiName); free(halMgrData->info); free(halMgrData); }