/* * 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 error; CtlConfigT *ctrlConfig; struct HalData *currentHalData; AFB_API_DEBUG(apiHandle, "Evtname=%s [msg=%s]", evtLabel, json_object_get_string(eventJ)); ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) { 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; } if((strlen(evtLabel) > ALSACORE_API_NAME_LENGTH) && ! strncmp(evtLabel, ALSACORE_API, ALSACORE_API_NAME_LENGTH)) { error = InternalHalHandleAlsaCoreEvents(apiHandle, evtLabel, eventJ, currentHalData); if(error < 0) { AFB_API_ERROR(apiHandle, "Error %i caught when tried to handle alsacore event evtname=%s [msg=%s]", error, evtLabel, json_object_get_string(eventJ)); return; } else if(error > 0) { AFB_API_INFO(apiHandle, "Warning %i raised when tried to handle alsacore event evtname=%s [msg=%s]", error, evtLabel, json_object_get_string(eventJ)); } else { return; } } AFB_API_INFO(apiHandle, "Not an internally handled event '%s' [msg=%s]", evtLabel, json_object_get_string(eventJ)); CtrlDispatchApiEvent(apiHandle, evtLabel, eventJ); } /******************************************************************************* * Internals HAL - 'haldependencies' section parsing/handling functions * ******************************************************************************/ json_type InternalHalDependencyGetExpectedContentTypeFromKey(char *key) { if(! key) return json_type_null; if(! strcmp(key, "cardNb") || ! strcmp(key, "playbackDeviceNb")) return json_type_int; if(! strcmp(key, "cardPath") || ! strcmp(key, "cardId") || ! strcmp(key, "cardShortName") || ! strcmp(key, "cardLongName") || ! strcmp(key, "cardDriver") || ! strcmp(key, "cardMixerName") || ! strcmp(key, "cardComponents") || ! strcmp(key, "playbackDeviceId") || ! strcmp(key, "playbackDeviceName")) return json_type_string; if(! strcmp(key, "AnyOf")) return json_type_object; return json_type_null; } int InternalHalDependencyIsObjectToAddValid(json_object *objectToAddJ) { struct json_object_iterator currentPropertyToAdd, lastPropertyToAdd; json_type currentPropertyValueExpectedType; if(! objectToAddJ) return -1; currentPropertyToAdd = json_object_iter_begin(objectToAddJ); lastPropertyToAdd = json_object_iter_end(objectToAddJ); while(! json_object_iter_equal(¤tPropertyToAdd, &lastPropertyToAdd)) { currentPropertyValueExpectedType = InternalHalDependencyGetExpectedContentTypeFromKey((char *) json_object_iter_peek_name(¤tPropertyToAdd)); if(! json_object_is_type(json_object_iter_peek_value(¤tPropertyToAdd), currentPropertyValueExpectedType)) return -2; json_object_iter_next(¤tPropertyToAdd); } return 0; } int InternalHalProcessOneDependencyProperty(afb_api_t apiHandle, char *key, json_object *valueJ, json_object **deviceToProbeRequestGenerationJ) { int valueIdx, previouslyGeneratedRequestIdx, valueCount, previouslyGeneratedRequestCount; json_object *previouslyGeneratedRequestJ, *updatedGeneratedRequestJ, *currentValueJ, *objectToBeefUpJ; json_type expectedContentType, contentType; if(! key || ! valueJ || ! deviceToProbeRequestGenerationJ) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } previouslyGeneratedRequestJ = *deviceToProbeRequestGenerationJ; if(! previouslyGeneratedRequestJ) { previouslyGeneratedRequestCount = 0; } else if(! json_object_is_type(previouslyGeneratedRequestJ, json_type_array)) { AFB_API_ERROR(apiHandle, "Invalid previously generated request (not an array : '%s')", json_object_get_string(previouslyGeneratedRequestJ)); return -2; } else { previouslyGeneratedRequestCount = (int) json_object_array_length(previouslyGeneratedRequestJ); } expectedContentType = InternalHalDependencyGetExpectedContentTypeFromKey(key); if(expectedContentType == json_type_null) { AFB_API_ERROR(apiHandle, "Unrecognized key '%s'", key); return -3; } contentType = json_object_get_type(valueJ); switch(contentType) { case json_type_int: case json_type_string: valueCount = 1; break; case json_type_array: valueCount = (int) json_object_array_length(valueJ); break; default: AFB_API_ERROR(apiHandle, "Value doesn't have the expected type (value: '%s')", json_object_get_string(valueJ)); return -4; } updatedGeneratedRequestJ = json_object_new_array(); if(! updatedGeneratedRequestJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate updated request json array"); return -5; } for(valueIdx = 0; valueIdx < valueCount; valueIdx++) { if(contentType == json_type_array) currentValueJ = json_object_array_get_idx(valueJ, valueIdx); else currentValueJ = valueJ; if(! json_object_is_type(currentValueJ, expectedContentType)) { AFB_API_ERROR(apiHandle, "Current value '%s' (index %i in value array) does not have the expected type, " "won't be able to process property (key '%s')", json_object_get_string(currentValueJ), valueIdx, key); json_object_put(updatedGeneratedRequestJ); return -6; } previouslyGeneratedRequestIdx = 0; do { if(! previouslyGeneratedRequestCount) objectToBeefUpJ = json_object_new_object(); else objectToBeefUpJ = wrap_json_clone(json_object_array_get_idx(previouslyGeneratedRequestJ, previouslyGeneratedRequestIdx)); if(! objectToBeefUpJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate/clone object to beef up json object"); json_object_put(objectToBeefUpJ); json_object_put(updatedGeneratedRequestJ); return -7; } if(! json_object_is_type(currentValueJ, json_type_object)) { json_object_object_add(objectToBeefUpJ, key, wrap_json_clone(currentValueJ)); } else if(! InternalHalDependencyIsObjectToAddValid(currentValueJ)) { wrap_json_object_add(objectToBeefUpJ, wrap_json_clone(currentValueJ)); } else { AFB_API_ERROR(apiHandle, "Object '%s' is not valid", json_object_get_string(currentValueJ)); json_object_put(objectToBeefUpJ); json_object_put(updatedGeneratedRequestJ); return -8; } json_object_array_add(updatedGeneratedRequestJ, objectToBeefUpJ); previouslyGeneratedRequestIdx++; } while(previouslyGeneratedRequestIdx < previouslyGeneratedRequestCount); } *deviceToProbeRequestGenerationJ = updatedGeneratedRequestJ; json_object_put(previouslyGeneratedRequestJ); return 0; } int InternalHalProcessOneHalDependency(afb_api_t apiHandle, json_object *DependencyJ, struct InternalHalProbedDevice *halDeviceToProbe) { int ret; json_object *dependencyUidJ, *dependencyClassJ; struct json_object_iterator dependencyCurrentProperty, dependencyLastProperty; if(! apiHandle || ! DependencyJ || ! halDeviceToProbe) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } if(! json_object_object_get_ex(DependencyJ, "uid", &dependencyUidJ)) { AFB_API_ERROR(apiHandle, "No dependency 'uid' has been specified, won't be able to process it ('%s')", json_object_get_string(DependencyJ)); return -2; } else if(! json_object_is_type(dependencyUidJ, json_type_string)) { AFB_API_ERROR(apiHandle, "Specified dependency 'uid' is not a string ('%s')", json_object_get_string(dependencyUidJ)); return -3; } halDeviceToProbe->uid = strdup(json_object_get_string(dependencyUidJ)); if(! halDeviceToProbe->uid) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) dependency 'uid' string"); return -4; } if(! json_object_object_get_ex(DependencyJ, "class", &dependencyClassJ)) { AFB_API_NOTICE(apiHandle, "No class has been specified for dependency with uid:'%s', will be considered as static", halDeviceToProbe->uid); halDeviceToProbe->deviceClass = STATIC_PROBED_DEVICE; } else if(! json_object_is_type(dependencyClassJ, json_type_string)) { AFB_API_ERROR(apiHandle, "Specified dependency class is not a string ('%s')", json_object_get_string(dependencyClassJ)); return -5; } else { halDeviceToProbe->deviceClass = HalUtlGetProbedDeviceClassFromString((char *) json_object_get_string(dependencyClassJ)); if(halDeviceToProbe->deviceClass == INVALID_PROBED_DEVICE) { AFB_API_ERROR(apiHandle, "Specified device class is unknown ('%s')", json_object_get_string(dependencyClassJ)); return -6; } } dependencyCurrentProperty = json_object_iter_begin(DependencyJ); dependencyLastProperty = json_object_iter_end(DependencyJ); while(! json_object_iter_equal(&dependencyCurrentProperty, &dependencyLastProperty)) { if(! strcmp("uid", json_object_iter_peek_name(&dependencyCurrentProperty)) || ! strcmp("class", json_object_iter_peek_name(&dependencyCurrentProperty))) { json_object_iter_next(&dependencyCurrentProperty); continue; } ret = InternalHalProcessOneDependencyProperty(apiHandle, (char *) json_object_iter_peek_name(&dependencyCurrentProperty), json_object_iter_peek_value(&dependencyCurrentProperty), &halDeviceToProbe->requestedDeviceJ); if(ret) { AFB_API_ERROR(apiHandle, "Error %i while processing property with key '%s' and value '%s' in dependency '%s'", ret, json_object_iter_peek_name(&dependencyCurrentProperty), json_object_get_string(json_object_iter_peek_value(&dependencyCurrentProperty)), json_object_get_string(DependencyJ)); return -7; } json_object_iter_next(&dependencyCurrentProperty); } return 0; } int InternalHalProcessAllHalDependencies(afb_api_t apiHandle, json_object *DependenciesJ, struct cds_list_head *halDevicesToProbeListHead) { int idx, dependenciesCount, ret; struct InternalHalProbedDevice *currentDeviceToProbe; json_type dependenciesJType; json_object *currentDependencyJ; if(! apiHandle || ! DependenciesJ || ! halDevicesToProbeListHead) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } dependenciesJType = json_object_get_type(DependenciesJ); switch(dependenciesJType) { case json_type_object: dependenciesCount = 1; break; case json_type_array: dependenciesCount = (int) json_object_array_length(DependenciesJ); break; default: AFB_API_ERROR(apiHandle, "'haldependencies' section is malformed, won't be able to handle it ('haldependencies' : '%s')", json_object_get_string(DependenciesJ)); return -2; } for(idx = 0; idx < dependenciesCount; idx++) { if(dependenciesJType == json_type_array) currentDependencyJ = json_object_array_get_idx(DependenciesJ, idx); else currentDependencyJ = DependenciesJ; if(! json_object_is_type(currentDependencyJ, json_type_object)) { AFB_API_ERROR(apiHandle, "Dependency ('%s') is not an object, section is malformed, won't be able to handle it ('haldependencies' : '%s')", json_object_get_string(currentDependencyJ), json_object_get_string(DependenciesJ)); HalUtlRemoveAllProbedDevicesFromList(halDevicesToProbeListHead); return -3; } currentDeviceToProbe = HalUtlAddProbedDeviceToProbedDeviceList(halDevicesToProbeListHead); if(! currentDeviceToProbe) { AFB_API_ERROR(apiHandle, "Error when tried to add a device to probe into device to probe list"); HalUtlRemoveAllProbedDevicesFromList(halDevicesToProbeListHead); return -4; } ret = InternalHalProcessOneHalDependency(apiHandle, currentDependencyJ, currentDeviceToProbe); if(ret) { AFB_API_ERROR(apiHandle, "Error %i returned when tried to process '%s' dependency", ret, json_object_get_string(currentDependencyJ)); HalUtlRemoveAllProbedDevicesFromList(halDevicesToProbeListHead); return -5; } } return 0; } int InternalHalHandleInfoGetResponse(afb_api_t apiHandle, json_object *currentResponseJ, struct InternalHalDeviceData **halDeviceDataToFill) { int idx, arraySize, ret = 0; struct InternalHalDeviceData *currentProbedDeviceData, *previouslyObtainedDevice; if(! apiHandle || ! currentResponseJ || ! halDeviceDataToFill) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } switch(json_object_get_type(currentResponseJ)) { case json_type_object: currentProbedDeviceData = HalUtlAllocateAndFillProbedDeviceDataUsingInfoGetResponse(currentResponseJ); if(! currentProbedDeviceData) { AFB_API_ERROR(apiHandle, "Unable to decode info get response object"); return -2; } if(! *halDeviceDataToFill) { *halDeviceDataToFill = currentProbedDeviceData; break; } previouslyObtainedDevice = *halDeviceDataToFill; if(previouslyObtainedDevice->cardNb != currentProbedDeviceData->cardNb || previouslyObtainedDevice->playbackDeviceNb != currentProbedDeviceData->playbackDeviceNb) { AFB_API_WARNING(apiHandle, "Different audio devices was returned by info get call"); free(previouslyObtainedDevice); *halDeviceDataToFill = NULL; ret = 1; } free(currentProbedDeviceData); break; case json_type_array: arraySize = (int) json_object_array_length(currentResponseJ); for(idx = 0; idx < arraySize; idx++) { ret = InternalHalHandleInfoGetResponse(apiHandle, json_object_array_get_idx(currentResponseJ, idx), halDeviceDataToFill); if(ret < 0) { AFB_API_ERROR(apiHandle, "Error %i while handling object %i of array ('%s') when handling info get response", ret, idx, json_object_get_string(currentResponseJ)); ret = -3; } if(ret) break; } break; case json_type_string: if(strcmp(json_object_get_string(currentResponseJ), "sndcard-not-found")) { AFB_API_ERROR(apiHandle, "Unrecognized string '%s' sent back by info get call", json_object_get_string(currentResponseJ)); return -4; } break; default: AFB_API_ERROR(apiHandle, "Unrecognized info get response format"); return -5; } return ret; } int InternalHalHandleOneHalDependencies(afb_api_t apiHandle, struct InternalHalProbedDevice *currentDeviceToProbe) { int ret, toReturn = 0; json_object *probedDeviceGetInfoResponseJ = NULL; if(! apiHandle || ! currentDeviceToProbe) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } if(! currentDeviceToProbe->uid || ! currentDeviceToProbe->requestedDeviceJ) { AFB_API_ERROR(apiHandle, "Specified device to probe is not valid (uid or request is not specified)"); return -2; } if(! json_object_is_type(currentDeviceToProbe->requestedDeviceJ, json_type_array)) { AFB_API_ERROR(apiHandle, "Device to probe request is not an array"); return -3; } ret = InternalHalGetCardInfo(apiHandle, json_object_get(currentDeviceToProbe->requestedDeviceJ), &probedDeviceGetInfoResponseJ); if(ret) { AFB_API_ERROR(apiHandle, "Error %i happened when tried to get card information for dependency with uid '%s' (using request : '%s')", ret, currentDeviceToProbe->uid, json_object_get_string(currentDeviceToProbe->requestedDeviceJ)); return -4; } ret = InternalHalHandleInfoGetResponse(apiHandle, probedDeviceGetInfoResponseJ, ¤tDeviceToProbe->deviceData); if(ret < 0) { AFB_API_ERROR(apiHandle, "Error %i happened when tried to handle card get info response for dependency with uid '%s' (using response : '%s')", ret, currentDeviceToProbe->uid, json_object_get_string(probedDeviceGetInfoResponseJ)); toReturn = -5; } else if(ret > 0) { AFB_API_WARNING(apiHandle, "Multiple card was found for dependency with uid '%s'(request : '%s', response : '%s')", currentDeviceToProbe->uid, json_object_get_string(currentDeviceToProbe->requestedDeviceJ), json_object_get_string(probedDeviceGetInfoResponseJ)); toReturn = 1; } else if(! currentDeviceToProbe->deviceData) { AFB_API_INFO(apiHandle, "No card was found for dependency with uid '%s'(request : '%s', response : '%s')", currentDeviceToProbe->uid, json_object_get_string(currentDeviceToProbe->requestedDeviceJ), json_object_get_string(probedDeviceGetInfoResponseJ)); toReturn = 2; } if(probedDeviceGetInfoResponseJ) json_object_put(probedDeviceGetInfoResponseJ); return toReturn; } int InternalHalHandleHalDependencies(afb_api_t apiHandle, struct HalData *currentHalData, struct cds_list_head *halDevicesToProbeListHead, enum DependencySelectionType dependencySelectionType, char *uid) { int ret, validatedDepedency, validatedDependenciesNumber = 0; struct InternalHalProbedDevice *halCurrentDeviceToProbe; if(! apiHandle || ! halDevicesToProbeListHead) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } if(cds_list_empty(halDevicesToProbeListHead)) { AFB_API_WARNING(apiHandle, "No device to probe in list, 'haldependencies' handling skipped"); return 0; } if(dependencySelectionType == UID_CORRESPONDING_DEPENDENCIES && ! uid) { AFB_API_ERROR(apiHandle, "Invalid uid"); return -2; } cds_list_for_each_entry(halCurrentDeviceToProbe, halDevicesToProbeListHead, node) { validatedDepedency = 0; switch(dependencySelectionType) { case ALL_DEPENDENCIES: validatedDepedency = 1; break; case UID_CORRESPONDING_DEPENDENCIES: if(! strcmp(uid, halCurrentDeviceToProbe->uid)) validatedDepedency = 1; break; default: AFB_API_ERROR(apiHandle, "Invalid dependencies enum type"); return -3; } if(validatedDepedency) { ret = InternalHalHandleOneHalDependencies(apiHandle, halCurrentDeviceToProbe); if(ret < 0) { AFB_API_ERROR(apiHandle, "Error %i happened when tried to handle device to probe with uid:'%s' and request:'%s'", ret, halCurrentDeviceToProbe->uid, json_object_get_string(halCurrentDeviceToProbe->requestedDeviceJ)); return -4; } if(ret > 0) AFB_API_INFO(apiHandle, "Didn't succeed to identifiate a unique device, uid:'%s' and request:'%s'", halCurrentDeviceToProbe->uid, json_object_get_string(halCurrentDeviceToProbe->requestedDeviceJ)); else validatedDependenciesNumber++; if(halCurrentDeviceToProbe->deviceClass == MANDATORY_PROBED_DEVICE && ! halCurrentDeviceToProbe->deviceData) { AFB_API_ERROR(apiHandle, "Mandatory device to probe not found, uid:'%s' and request:'%s'", halCurrentDeviceToProbe->uid, json_object_get_string(halCurrentDeviceToProbe->requestedDeviceJ)); return -5; } } } if(validatedDependenciesNumber) currentHalData->status = HAL_STATUS_AVAILABLE; return validatedDependenciesNumber; } int InternalHalHandleAllHalDependencies(afb_api_t apiHandle, struct HalData *currentHalData, struct cds_list_head *halDevicesToProbeListHead) { int returned; returned = InternalHalHandleHalDependencies(apiHandle, currentHalData, halDevicesToProbeListHead, ALL_DEPENDENCIES, NULL); if(returned < 0) return returned; return 0; } int InternalHalHalDependenciesConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *DependenciesJ) { CtlConfigT *ctrlConfig; struct HalData *currentHalData; ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) return -1; currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData) return -2; if(DependenciesJ && InternalHalProcessAllHalDependencies(apiHandle, DependenciesJ, ¤tHalData->internalHalData->probedDevicesListHead)) { AFB_API_ERROR(apiHandle, "Failed to process 'haldependencies' section"); return -3; } else if(! DependenciesJ && (InternalHalHandleAllHalDependencies(apiHandle, currentHalData, ¤tHalData->internalHalData->probedDevicesListHead)) < 0) { AFB_API_ERROR(apiHandle, "Failed to handle 'haldependencies' section"); return -4; } return 0; } /******************************************************************************* * Internals HAL - 'halmixer' section parsing/handling functions * ******************************************************************************/ int InternalHalHalMixerConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *MixerJ) { int err = 0, wrapRet; char *mixerApiName, *prefix = NULL; CtlConfigT *ctrlConfig; struct HalData *currentHalData; struct InternalHalProbedDevice *currentProbedDevice; if(! apiHandle || ! section) return -1; ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) 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; wrapRet = wrap_json_unpack(MixerJ, "{s:s s?:s}", "mixerapi", &mixerApiName, "prefix", &prefix); if(wrapRet) return -5; currentHalData->internalHalData->mixerApiName = strdup(mixerApiName); if(! currentHalData->internalHalData->mixerApiName) return -6; if(prefix) { currentHalData->internalHalData->prefix = strdup(prefix); if(! currentHalData->internalHalData->prefix) return -7; } } else if(currentHalData->status == HAL_STATUS_AVAILABLE) { cds_list_for_each_entry(currentProbedDevice, ¤tHalData->internalHalData->probedDevicesListHead, node) { if(! currentProbedDevice->deviceData) { currentProbedDevice->mixerLinkStatus = DEPENDENCY_MIXER_LINK_USELESS; continue; } if(currentProbedDevice->mixerLinkStatus == DEPENDENCY_MIXER_ATTACH_SUCCEED) { AFB_API_WARNING(apiHandle, "Mixer status is already initialized, moving to next one"); continue; } err = InternalHalAttachDependencyToMixer(apiHandle, currentProbedDevice); if(err) { AFB_API_ERROR(apiHandle, "Error %i while attaching to mixer", err); return -8; } } currentHalData->status = HAL_STATUS_READY; } return 0; } /******************************************************************************* * Internals HAL - 'halmap' section parsing/handling functions * ******************************************************************************/ int InternalHalProcessOneHalMapControl(afb_api_t apiHandle, struct InternalHalAlsaMap *halMapData, json_object *halMapControlJ) { char *uid, *info = NULL, *action = NULL, *name = NULL, *typename = NULL; json_object *alsaJ = NULL, *createAlsaCtlJ = NULL; if(! apiHandle || ! halMapData || ! halMapControlJ) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } if(wrap_json_unpack(halMapControlJ, "{s:s s?:s s:o s?:s !}", "uid", &uid, "info", &info, "alsa", &alsaJ, "action", &action)) { AFB_API_ERROR(apiHandle, "Parsing error, control json should only contains " "[uid]|[info]|[alsa] in : '%s'", json_object_get_string(halMapControlJ)); return -2; } halMapData->uid = strdup(uid); if(! halMapData->uid) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) control 'uid' string"); return -3; } if(info) { halMapData->info = strdup(info); if(! halMapData->info) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) control 'info' string"); return -4; } } if(wrap_json_unpack(alsaJ, "{s?:s s?:i s?:i s?:o !}", "name", &name, "numid", &halMapData->ctl.numid, "value", &halMapData->ctl.value, "create", &createAlsaCtlJ)) { AFB_API_ERROR(apiHandle, "Parsing error, alsa json should only contains " "[name]|[numid]||[value]|[create] in : '%s'", json_object_get_string(alsaJ)); return -5; } if(name) { halMapData->ctl.name = strdup(name); if(! halMapData->ctl.name) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) control 'info' string"); return -6; } } if(createAlsaCtlJ) { halMapData->ctl.alsaCtlCreation = calloc(1, sizeof(struct InternalHalAlsaCtlProperties)); if(! halMapData->ctl.alsaCtlCreation) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate alsa properties data structure for control to create"); return -7; } if(wrap_json_unpack(createAlsaCtlJ, "{s:s s:i s:i s:i s:i !}", "type", &typename, "count", &halMapData->ctl.alsaCtlCreation->count, "minval", &halMapData->ctl.alsaCtlCreation->minval, "maxval", &halMapData->ctl.alsaCtlCreation->maxval, "step", &halMapData->ctl.alsaCtlCreation->step)) { AFB_API_ERROR(apiHandle, "Parsing error, alsa creation json should only contains " "[type]|[count]|[minval]|[maxval]|[step] in : '%s'", json_object_get_string(alsaJ)); return -8; } if(typename) { halMapData->ctl.alsaCtlCreation->type = InternalHalMapsAlsaTypeToEnum(typename); if(halMapData->ctl.alsaCtlCreation->type == SND_CTL_ELEM_TYPE_NONE) { AFB_API_ERROR(apiHandle, "Couldn't get alsa type from string %s in : '%s'", typename, json_object_get_string(alsaJ)); return -9; } } if(! halMapData->ctl.name) halMapData->ctl.name = halMapData->uid; } else if(halMapData->ctl.name && halMapData->ctl.numid > 0) { AFB_API_ERROR(apiHandle, "Can't have both a control name (%s) and a control uid (%i) in alsa object : '%s'", halMapData->ctl.name, halMapData->ctl.numid, json_object_get_string(alsaJ)); return -10; } else if(! halMapData->ctl.name && halMapData->ctl.numid <= 0) { AFB_API_ERROR(apiHandle, "Need at least a control name or a control uid in alsa object : '%s'", json_object_get_string(alsaJ)); return -11; } if(action) halMapData->actionJ = json_object_get(halMapControlJ); return 0; } int InternalHalProcessOneHalMapObject(afb_api_t apiHandle, json_object *halMapForTargetJ, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead) { int idx, controlsCount, err = 0, halMapControlsJsonIsAnArray = 0; char *uid, *info = NULL, *target; struct InternalHalAlsaMap *currentHalMapData; json_object *controlsJ, *currentHalMapControlJ; json_type halMapControlsType; AFB_API_DEBUG(apiHandle, "halMapForTargetJ='%s'", json_object_get_string(halMapForTargetJ)); if(wrap_json_unpack(halMapForTargetJ, "{s:s s?:s s:s s:o !}", "uid", &uid, "info", &info, "target", &target, "controls", &controlsJ)) { AFB_API_ERROR(apiHandle, "Parsing error, map should only contains " "[uid]|[info]|[target]|[controls] in : '%s'", json_object_get_string(halMapForTargetJ)); return -1; } if(! HalUtlSearchProbedDeviceDataById(halDevicesToProbeListHead, target)) { AFB_API_ERROR(apiHandle, "Content of 'halmap' section is not valid because targeted dependency ('%s') is not present " "in 'haldependencies' section, json configuration file correction is needed", target); return -2; } halMapControlsType = json_object_get_type(controlsJ); switch(halMapControlsType) { case json_type_array: controlsCount = (int) json_object_array_length(controlsJ); halMapControlsJsonIsAnArray = 1; break; case json_type_object: controlsCount = 1; break; default: AFB_API_ERROR(apiHandle, "Content of 'halmap' controls section is not valid ('%s')", json_object_get_string(controlsJ)); return -3; } for(idx = 0; idx < controlsCount; idx++) { currentHalMapControlJ = halMapControlsJsonIsAnArray ? json_object_array_get_idx(controlsJ, idx) : controlsJ; currentHalMapData = HalUtlAddHalMapDataToHalMapDataList(halMapListHead); currentHalMapData->targetUid = strdup(uid); if(! currentHalMapData->targetUid) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) 'targetUid' string"); return -4; } if(info) { currentHalMapData->targetInfo = strdup(info); if(! currentHalMapData->targetInfo) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) 'targetInfo' string"); return -5; } } currentHalMapData->targetedDependency = strdup(target); if(! currentHalMapData->targetedDependency) { AFB_API_ERROR(apiHandle, "Didn't succeed to store (allocate) 'targetedDependency' string"); return -6; } err = InternalHalProcessOneHalMapControl(apiHandle, currentHalMapData, currentHalMapControlJ); if(err) { AFB_API_ERROR(apiHandle, "Error %i was returned when tried to proccess halmap control %i ('%s')", err, idx, json_object_get_string(currentHalMapControlJ)); HalUtlRemoveSelectedHalMapData(halMapListHead, currentHalMapData); return -7; } } return 0; } int InternalHalProcessAllHalMap(afb_api_t apiHandle, json_object *halMapJ, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead) { int idx, targetCount, err = 0, halMapJsonIsAnArray = 0; json_object *currentHalMapTargetJ; json_type alsaMapType; AFB_API_DEBUG(apiHandle, "halMapJ='%s'", json_object_get_string(halMapJ)); alsaMapType = json_object_get_type(halMapJ); switch(alsaMapType) { case json_type_array: targetCount = (int) json_object_array_length(halMapJ); halMapJsonIsAnArray = 1; break; case json_type_object: targetCount = 1; break; default: AFB_API_ERROR(apiHandle, "Content of 'halmap' section is not valid ('%s')", json_object_get_string(halMapJ)); return -1; } for(idx = 0; idx < targetCount; idx++) { currentHalMapTargetJ = halMapJsonIsAnArray ? json_object_array_get_idx(halMapJ, idx) : halMapJ; err = InternalHalProcessOneHalMapObject(apiHandle, currentHalMapTargetJ, halMapListHead, halDevicesToProbeListHead); if(err) { AFB_API_ERROR(apiHandle, "Error %i was returned when tried to proccess halmap target %i ('%s')", err, idx, json_object_get_string(currentHalMapTargetJ)); HalUtlRemoveAllHalMapData(halMapListHead); return -2; } } return 0; } int InternalHalHandleOneHalMapObject(afb_api_t apiHandle, struct InternalHalAlsaMap *halMapData) { int err; char cardNbString[6]; json_object *valueJ, *convertedValueJ = NULL; CtlActionT *toLoadAction; halMapData->alsaControlEvent = afb_api_make_event(apiHandle, halMapData->uid); if(! halMapData->alsaControlEvent) { AFB_API_ERROR(apiHandle, "Didn't succeed to create event for alsa control with uid %s", halMapData->uid); return -1; } snprintf(cardNbString, sizeof(cardNbString), "hw:%i", halMapData->cardNb); if(halMapData->ctl.alsaCtlCreation) { if(InternalHalCreateAlsaCtl(apiHandle, cardNbString, &halMapData->ctl)) { AFB_API_ERROR(apiHandle, "An error happened when trying to create a new alsa control"); return -2; } halMapData->ctl.alsaCtlProperties = halMapData->ctl.alsaCtlCreation; } else { halMapData->ctl.alsaCtlProperties = calloc(1, sizeof(struct InternalHalAlsaCtlProperties)); if(! halMapData->ctl.alsaCtlProperties) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate alsa properties data structure for control"); return -3; } if(InternalHalUpdateAlsaCtlProperties(apiHandle, cardNbString, &halMapData->ctl)) { AFB_API_ERROR(apiHandle, "An error happened when trying to get existing alsa control info"); free(halMapData->ctl.alsaCtlProperties); halMapData->ctl.alsaCtlProperties = NULL; return -4; } } if(halMapData->actionJ) { toLoadAction = malloc(sizeof(CtlActionT)); if(! toLoadAction) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate structure used to store action to perform " "when the corresponding ALSA control is detected"); return -5; } if(ActionLoadOne(apiHandle, toLoadAction, halMapData->actionJ, 0)) { AFB_API_ERROR(apiHandle, "Didn't succeed to load action using alsa object : '%s'", json_object_get_string(halMapData->actionJ)); free(toLoadAction); return -6; } halMapData->action = toLoadAction; } if(InternalHalSubscribeToAlsacoreCardEvent(apiHandle, cardNbString)) { AFB_API_ERROR(apiHandle, "Error when trying to subscribe to alsacore event for audio card '%s'", cardNbString); return -7; } if(halMapData->ctl.value) { // TBD JAI : handle alsa controls type valueJ = json_object_new_int(halMapData->ctl.value); if(! valueJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to allocate ALSA control value json string"); return -8; } err = 0; if(InternalHalConvertJsonValues(apiHandle, halMapData->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 = -9; } else if(InternalHalSetAlsaCtlValue(apiHandle, cardNbString, halMapData->ctl.numid, convertedValueJ)) { AFB_API_ERROR(apiHandle, "Error while trying to set initial value on alsa control %i, device '%s', value '%s'", halMapData->ctl.numid, cardNbString, json_object_get_string(valueJ)); err = -10; } json_object_put(valueJ); if(convertedValueJ) json_object_put(convertedValueJ); if(err) return err; } if(afb_api_add_verb(apiHandle, halMapData->uid, NULL, InternalHalActionOnAlsaCtl, (void *) halMapData, NULL, 0, 0)) { AFB_API_ERROR(apiHandle, "Didn't succeed to create verb %s for alsa control named %s on card %i", halMapData->uid, halMapData->ctl.name ? halMapData->ctl.name : "'N/A'", halMapData->cardNb); return -11; } return 0; } int InternalHalUnmanageOneHalMapObject(afb_api_t apiHandle, struct InternalHalAlsaMap *halMapData) { int err; char cardNbString[6]; if(! apiHandle || ! halMapData) { AFB_API_ERROR(apiHandle, "Invalid argument(s)"); return -1; } snprintf(cardNbString, sizeof(cardNbString), "hw:%i", halMapData->cardNb); err = afb_api_del_verb(apiHandle, halMapData->uid, NULL); if(err) AFB_API_WARNING(apiHandle, "Error %i returned when tried to remove halmap verb %s, " "verb may have not been added before", err, halMapData->uid); free(halMapData->action); halMapData->action = NULL; if(halMapData->ctl.alsaCtlCreation) { err = InternalHalDeleteAlsaCtl(apiHandle, cardNbString, &halMapData->ctl); if(err) AFB_API_WARNING(apiHandle, "Error %i returned when tried to custom ALSA control '%s', " "custom control may have not been added before", err, halMapData->ctl.name); } else { free(halMapData->ctl.alsaCtlProperties); halMapData->ctl.alsaCtlProperties = NULL; } if(afb_event_is_valid(halMapData->alsaControlEvent)) { afb_event_unref(halMapData->alsaControlEvent); halMapData->alsaControlEvent = NULL; } halMapData->cardNb = HAL_UNKNOWN_DEVICE; return 0; } int InternalHalProcessDependencyRelatedHalmap(afb_api_t apiHandle, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead, char *targetedDependency, enum DependencySelectionType halMapSelectionType, enum HalMapProcessingType halMapProcessingType) { int err = 0, validatedHalMap; struct InternalHalAlsaMap *currentHalMapData; if(cds_list_empty(halMapListHead)) { AFB_API_ERROR(apiHandle, "HalMap list is empty, nothing to process"); return 0; } if(halMapSelectionType == UID_CORRESPONDING_DEPENDENCIES && ! targetedDependency) { AFB_API_ERROR(apiHandle, "Invalid targeted dependency"); return -1; } cds_list_for_each_entry(currentHalMapData, halMapListHead, node) { validatedHalMap = 0; switch(halMapSelectionType) { case ALL_DEPENDENCIES: validatedHalMap = 1; break; case UID_CORRESPONDING_DEPENDENCIES: if(! strcmp(targetedDependency, currentHalMapData->targetedDependency)) validatedHalMap = 1; break; default: AFB_API_ERROR(apiHandle, "Invalid dependencies enum type"); return -2; } if(validatedHalMap) { currentHalMapData->cardNb = HalUtlGetProbedDeviceCardNbUsingUid(halDevicesToProbeListHead, currentHalMapData->targetedDependency); if(currentHalMapData->cardNb == HAL_UNKNOWN_DEVICE) { AFB_API_WARNING(apiHandle, "Current halmap control %s can't be %s because corresponding " "dependency ('%s') card is not available at the moment", currentHalMapData->uid, (halMapProcessingType == HANDLE_SELECTED_HALMAP) ? "handled" : "unmanaged", currentHalMapData->targetedDependency); continue; } if(halMapProcessingType == HANDLE_SELECTED_HALMAP) err = InternalHalHandleOneHalMapObject(apiHandle, currentHalMapData); else err = InternalHalUnmanageOneHalMapObject(apiHandle, currentHalMapData); if(err) { AFB_API_ERROR(apiHandle, "Error %i was returned when tried to %s halmap control with uid %s", err, (halMapProcessingType == HANDLE_SELECTED_HALMAP) ? "handle" : "unmanage", currentHalMapData->uid); return -3; } } } return 0; } int InternalHalHandleDependencyRelatedHalmap(afb_api_t apiHandle, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead, char *targetedDependency) { return InternalHalProcessDependencyRelatedHalmap(apiHandle, halMapListHead, halDevicesToProbeListHead, targetedDependency, UID_CORRESPONDING_DEPENDENCIES, HANDLE_SELECTED_HALMAP); } int InternalHalUnmanageDependencyRelatedHalmap(afb_api_t apiHandle, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead, char *targetedDependency) { return InternalHalProcessDependencyRelatedHalmap(apiHandle, halMapListHead, halDevicesToProbeListHead, targetedDependency, UID_CORRESPONDING_DEPENDENCIES, UNMANAGE_SELECTED_HALMAP); } int InternalHalHandleAllHalMap(afb_api_t apiHandle, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead) { return InternalHalProcessDependencyRelatedHalmap(apiHandle, halMapListHead, halDevicesToProbeListHead, NULL, ALL_DEPENDENCIES, HANDLE_SELECTED_HALMAP); } int InternalHalUnmanageAllHalMap(afb_api_t apiHandle, struct cds_list_head *halMapListHead, struct cds_list_head *halDevicesToProbeListHead) { return InternalHalProcessDependencyRelatedHalmap(apiHandle, halMapListHead, halDevicesToProbeListHead, NULL, ALL_DEPENDENCIES, UNMANAGE_SELECTED_HALMAP); } int InternalHalHalMapConfig(afb_api_t apiHandle, CtlSectionT *section, json_object *AlsaMapJ) { CtlConfigT *ctrlConfig; struct HalData *currentHalData; ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) return -1; currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData) return -2; if(AlsaMapJ) { if(InternalHalProcessAllHalMap(apiHandle, AlsaMapJ, ¤tHalData->internalHalData->halMapListHead, ¤tHalData->internalHalData->probedDevicesListHead)) { AFB_API_ERROR(apiHandle, "Failed to process 'halmap' section"); HalUtlRemoveAllHalMapData(¤tHalData->internalHalData->halMapListHead); return -4; } } else if(cds_list_empty(¤tHalData->internalHalData->halMapListHead)) { AFB_API_WARNING(apiHandle, "No alsa controls defined in 'halmap' section"); return 1; } else if(InternalHalHandleAllHalMap(apiHandle, ¤tHalData->internalHalData->halMapListHead, ¤tHalData->internalHalData->probedDevicesListHead)) { AFB_API_ERROR(apiHandle, "Failed to handle 'halmap' section"); return -5; } return 0; } /******************************************************************************* * Internals HAL verbs functions * ******************************************************************************/ int GenerateInternalHalInfoJson(afb_api_t apiHandle, struct HalData *currentHalData, json_object *requestJ, json_object **returnedJ) { int wrapRet, verboseLevel = 2; char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; json_object *mixerRequestJ = NULL, *toReturnJ = NULL, *requestAnswer, *streamsArray, *controlsArray, *dependenciesArray; if(! apiHandle || ! currentHalData || ! returnedJ) return -1; *returnedJ = NULL; if(requestJ) { wrapRet = wrap_json_unpack(requestJ, "{s?:i, s?:o !}", "verbose", &verboseLevel, "mixer", &mixerRequestJ); if(wrapRet) return -2; } if(mixerRequestJ && json_object_is_type(mixerRequestJ, json_type_object) && json_object_get_object(mixerRequestJ)->count > 0) { apiToCall = currentHalData->internalHalData->mixerApiName; if(! apiToCall) return-3; if(InternalHalGetInfoFromMixer(apiHandle, apiToCall, mixerRequestJ, &toReturnJ, &returnedError, &returnedInfo)) return -4; *returnedJ = toReturnJ; return 0; } requestAnswer = json_object_new_object(); if(verboseLevel >= 0) { dependenciesArray = HalUtlGetJsonArrayForAllDependencies(apiHandle, ¤tHalData->internalHalData->probedDevicesListHead, DEPENDENCY_FULL_JSON); if(dependenciesArray) json_object_object_add(requestAnswer, "dependencies", dependenciesArray); } if(verboseLevel >= 1) { controlsArray = HalUtGetJsonArrayForAllHalMapControls(apiHandle, ¤tHalData->internalHalData->halMapListHead); if(controlsArray) json_object_object_add(requestAnswer, "controls", controlsArray); } if(verboseLevel >= 2) { streamsArray = HalUtlGetJsonArrayForAllMixersData(apiHandle, ¤tHalData->internalHalData->streamsDataListHead); if(! streamsArray) streamsArray = json_object_new_array(); // Always return an array for 4a-hl-api (to prevent segfault) json_object_object_add(requestAnswer, "streams", streamsArray); } if(! json_object_get_object(requestAnswer)->count) { json_object_put(requestAnswer); requestAnswer = NULL; } *returnedJ = requestAnswer; return 0; } void InternalHalInfoVerb(afb_req_t request) { int err; afb_api_t apiHandle; CtlConfigT *ctrlConfig; struct HalData *currentHalData; json_object *requestJ, *toReturnJ; apiHandle = afb_req_get_api(request); if(! apiHandle) { afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); return; } ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) { 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; } requestJ = afb_req_json(request); err = GenerateInternalHalInfoJson(apiHandle, currentHalData, requestJ, &toReturnJ); if(err) { afb_req_fail_f(request, "get_info_fail", "Error %i happened when tried to get json info for request json '%s'", err, json_object_get_string(requestJ)); return; } afb_req_success(request, toReturnJ, "Requested data"); } void InternalHalSubscribeUnsubscribe(afb_req_t request, enum SubscribeUnsubscribeType subscribeUnsubscribeType) { int arrayIdx, count, subscriptionFound, subscriptionDoneNb = 0; char *currentSubscriptionString; afb_api_t apiHandle; CtlConfigT *ctrlConfig; struct HalData *currentHalData; struct InternalHalMixerData *currentStreamData; struct InternalHalAlsaMap *currentHalMapData; json_object *requestJson, *requestedSubscriptionsJ, *requestedSubscriptionJ = NULL, *subscriptionDoneNbJ = NULL; json_type requestJsonType; apiHandle = afb_req_get_api(request); if(! apiHandle) { afb_req_fail(request, "api_handle", "Can't get current internal hal api handle"); return; } ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) { 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; } requestJson = afb_req_json(request); if(! requestJson) { 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(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(request, "request_stream_list_updates_event", "Error while trying to unsubscribe to stream list updates event"); return; } subscriptionFound = 1; subscriptionDoneNb++; } cds_list_for_each_entry(currentStreamData, ¤tHalData->internalHalData->streamsDataListHead, node) { if(! subscriptionFound && ! 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; } } cds_list_for_each_entry(currentHalMapData, ¤tHalData->internalHalData->halMapListHead, node) { if(! subscriptionFound && ! strcasecmp(currentSubscriptionString, currentHalMapData->uid)) { if(currentHalMapData->alsaControlEvent && subscribeUnsubscribeType == SUBSCRIPTION && afb_req_subscribe(request, currentHalMapData->alsaControlEvent)) { afb_req_fail_f(request, "request_control_event", "Error while trying to subscribe to %s halmap controls events", currentHalMapData->uid); return; } else if(currentHalMapData->alsaControlEvent && subscribeUnsubscribeType == UNSUBSCRIPTION && afb_req_unsubscribe(request, currentHalMapData->alsaControlEvent)) { afb_req_fail_f(request, "request_stream_event", "Error while trying to unsubscribe to %s halmap controls events", currentHalMapData->uid); return; } subscriptionFound = 1; subscriptionDoneNb++; break; } } } if(! subscriptionDoneNb) { afb_req_fail_f(request, "events_not_found", "%s failed, event(s) were not found", subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription"); return; } else { subscriptionDoneNbJ = json_object_new_int(subscriptionDoneNb); if(! subscriptionDoneNbJ) { afb_req_fail(request, "subscriptionnb_json_integer", "Didn't succeed to allocate subscription number json integer"); return; } } if(subscriptionDoneNb == count) afb_req_success_f(request, subscriptionDoneNbJ, "%s succeed for all the %i events requested", subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", subscriptionDoneNb); else if(subscriptionDoneNb < count) afb_req_success_f(request, subscriptionDoneNbJ, "%s succeed but only to %i events requested out of %i", subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", subscriptionDoneNb, count); else afb_req_success_f(request, subscriptionDoneNbJ, "%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); }