summaryrefslogtreecommitdiffstats
path: root/4a-hal/4a-internals-hal/4a-internals-hal-cb.c
diff options
context:
space:
mode:
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.c790
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,
+ &currentHalAlsaCtlsT->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", &currentHalData->internalHalData->mixerApiName))
+ return -5;
+
+ wrap_json_unpack(MixerJ, "{s?:s}", "prefix", &currentHalData->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, &currentInternalHalAlsaMapT->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(&currentMixerDataJ,
+ "{s:s s:s}",
+ "name", currentMixerData->verb,
+ "cardId", currentMixerData->streamCardId);
+ break;
+
+ case MIXER_DATA_PLAYBACKS:
+ case MIXER_DATA_CAPTURES :
+ wrap_json_pack(&currentMixerDataJ,
+ "{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(&currentAlsaMapData,
+ "{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,
+ &currentHalData->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,
+ &currentHalData->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,
+ &currentHalData->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);
+}