diff options
author | Jonathan Aillet <jonathan.aillet@iot.bzh> | 2019-04-18 12:40:25 +0200 |
---|---|---|
committer | Jonathan Aillet <jonathan.aillet@iot.bzh> | 2019-05-24 12:05:52 +0200 |
commit | 68138a3ec7a78ad7304d291ff92d8e5292847c4e (patch) | |
tree | 9157134d50a749c838afdf93a49c4ce17a018347 /4a-hal/4a-internals-hal/4a-internals-hal-cb.c | |
parent | 196e723e79a1f5eae41cf4a8b1450df0679a4af8 (diff) |
Clarify internals hal functions and files names
The purpose of this commit is to have of a more standard way to
name files and functions used to generate/handle hal api
(generated from hal json configuration file).
It occurred to me that 'hal-controller' was not a good name
because it is harder for people who don't know about
the app-controller to understanded what is the purpose of
these files/functions.
It was renamed to 'internal-hal' because it's about hal
that are all handle/load by hal-manager in opposition of
external-hal that are independant binding/binder that can register
themselves to hal-manager.
BUG-AGL: SPEC-2329
Change-Id: I11b7efe64ec474b004a2a15ed8969b9db95d428f
Signed-off-by: Jonathan Aillet <jonathan.aillet@iot.bzh>
Diffstat (limited to '4a-hal/4a-internals-hal/4a-internals-hal-cb.c')
-rw-r--r-- | 4a-hal/4a-internals-hal/4a-internals-hal-cb.c | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-cb.c b/4a-hal/4a-internals-hal/4a-internals-hal-cb.c new file mode 100644 index 0000000..0102d8d --- /dev/null +++ b/4a-hal/4a-internals-hal/4a-internals-hal-cb.c @@ -0,0 +1,790 @@ +/* + * 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 <wrap-json.h> + +#include <afb/afb-binding.h> + +#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); +} |