diff options
author | Jonathan Aillet <jonathan.aillet@iot.bzh> | 2018-06-08 11:16:26 +0200 |
---|---|---|
committer | Jonathan Aillet <jonathan.aillet@iot.bzh> | 2018-10-08 15:52:51 +0200 |
commit | 7297c6b5d2dc47574e981c76a282e67fcef230c0 (patch) | |
tree | 32235026a9a8a89c8e333c2572ea71b3f739c6f5 /4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c | |
parent | 180b6af527b44dc8d5c4c9f7931e9ccf45d13811 (diff) |
Process and handle alsa controls map
Process and handle alsa controls map by :
Parse and store info from 'halmap' section into a structure.
If the hal is available :
- Test if controls are available (if use of existing control).
- Create new controls (if use of control to create).
- Add a verb for each element of the section.
- Handle call to alsa when a verb request is detected.
- Resgister to event from this device.
- Handle call to action if event on this control is detected.
Change-Id: I246e16e9d02e64a1778f5c78d2458a33bdfb6d7e
Signed-off-by: Jonathan Aillet <jonathan.aillet@iot.bzh>
Diffstat (limited to '4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c')
-rw-r--r-- | 4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c | 297 |
1 files changed, 294 insertions, 3 deletions
diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c index 5168a1d..e52639f 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c @@ -31,6 +31,86 @@ #include "4a-hal-controllers-alsacore-link.h" /******************************************************************************* + * HAL controller event handler function * + ******************************************************************************/ + +void HalCtlsDispatchApiEvent(afb_dynapi *apiHandle, const char *evtLabel, json_object *eventJ) +{ + int numid, idx; + + char cardIdString[6]; + + char *alsaCoreLabel; + + CtlConfigT *ctrlConfig; + CtlSourceT source; + + struct SpecificHalData *currentHalData; + struct CtlHalAlsaMapT *currentHalAlsaCtlsT; + + json_object *valuesJ; + + AFB_ApiDebug(apiHandle, "%s: evtname=%s [msg=%s]", __func__, evtLabel, json_object_get_string(eventJ)); + + ctrlConfig = (CtlConfigT *) afb_dynapi_get_userdata(apiHandle); + if(! ctrlConfig) { + AFB_ApiError(apiHandle, "%s: Can't get current hal controller config", __func__); + return; + } + + currentHalData = (struct SpecificHalData *) ctrlConfig->external; + if(! currentHalData) { + AFB_ApiWarning(apiHandle, "%s: Can't get current hal controller data", __func__); + return; + } + + snprintf(cardIdString, 6, "hw:%i", currentHalData->sndCardId); + currentHalAlsaCtlsT = currentHalData->ctlHalSpecificData->ctlHalAlsaMapT; + + asprintf(&alsaCoreLabel, "%s/%s", ALSACORE_API, cardIdString); + + if(strcmp(evtLabel, alsaCoreLabel) == 0 && + ! wrap_json_unpack(eventJ, "{s:i s:o !}", "id", &numid, "val", &valuesJ)) { + free(alsaCoreLabel); + + // 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; + + // TODO JAI: add weighting passing values (new valueJ object) + + (void) ActionExecOne(&source, currentHalAlsaCtlsT->ctls[idx].action, valuesJ); + } + + return; + } + } + + AFB_ApiWarning(apiHandle, "%s: alsacore event with an unrecognized numid: %i, evtname=%s [msg=%s]", + __func__, + numid, + evtLabel, + json_object_get_string(eventJ)); + + return; + } + + free(alsaCoreLabel); + + AFB_ApiNotice(apiHandle, + "%s: not an alsacore event '%s' [msg=%s]", + __func__, + evtLabel, + json_object_get_string(eventJ)); + + CtrlDispatchApiEvent(apiHandle, evtLabel, eventJ); +} + +/******************************************************************************* * HAL controllers sections parsing functions * ******************************************************************************/ @@ -66,10 +146,221 @@ int HalCtlsHalMixerConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object return 0; } -// TODO JAI : to implement -int HalCtlsHalMapConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *StreamControlsJ) +int HalCtlsProcessOneHalMapObject(AFB_ApiT apiHandle, struct CtlHalAlsaMap *alsaMap, json_object *AlsaMapJ) +{ + char *action = NULL, *typename = NULL; + + json_object *alsaJ = NULL, *createAlsaCtlJ = NULL; + + AFB_ApiDebug(apiHandle, "%s: AlsaMapJ=%s", __func__, 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_ApiError(apiHandle, "%s: parsing error, map should only contains [label]|[uid]|[tag]|[info]|[alsa]|[action] in:\n-- %s", __func__, 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_ApiError(apiHandle, "%s: parsing error, alsa json should only contains [name]|[numid]||[value]|[create] in:\n-- %s", __func__, 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_ApiError(apiHandle, "%s: parsing error, alsa creation json should only contains [type]|[count]|[minval]|[maxval]|[step] in:\n-- %s", __func__, json_object_get_string(alsaJ)); + return -3; + } + + if(typename && (alsaMap->ctl.alsaCtlCreation->type = HalCtlsMapsAlsaTypeToEnum(typename)) == SND_CTL_ELEM_TYPE_NONE) { + AFB_ApiError(apiHandle, "%s: Couldn't get alsa type from string %s in:\n-- %s", __func__, 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_ApiError(apiHandle, + "%s: Can't have both a control name (%s) and a control uid (%i) in alsa object:\n-- %s", + __func__, + alsaMap->ctl.name, + alsaMap->ctl.numid, + json_object_get_string(alsaJ)); + return -5; + } + else if(! alsaMap->ctl.name && alsaMap->ctl.numid <= 0) { + AFB_ApiError(apiHandle, + "%s: Need at least a control name or a control uid in alsa object:\n-- %s", + __func__, + json_object_get_string(alsaJ)); + return -6; + } + + if(action) + alsaMap->actionJ = AlsaMapJ; + + return 0; +} + +int HalCtlsHandleOneHalMapObject(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaMap *alsaMap) +{ + json_object *valueJ; + + if(alsaMap->ctl.alsaCtlCreation) { + if(HalCtlsCreateAlsaCtl(apiHandle, cardId, &alsaMap->ctl)) { + AFB_ApiError(apiHandle, + "%s: An error happened when trying to create a new alsa control", + __func__); + return -1; + } + } + else if(HalCtlsGetAlsaCtlInfo(apiHandle, cardId, &alsaMap->ctl)) { + AFB_ApiError(apiHandle, + "%s: An error happened when trying to get existing alsa control info", + __func__); + return -2; + } + + if(alsaMap->ctl.value) { + // TODO JAI: add weighting passing values on currentAlsaCtl->value (and put them into valueJ json) + + valueJ = json_object_new_int(alsaMap->ctl.value); + if(HalCtlsSetAlsaCtlValue(apiHandle, cardId, alsaMap->ctl.numid, valueJ)) { + AFB_ApiError(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)); + return -3; + } + } + + if(alsaMap->actionJ) { + alsaMap->action = calloc(1, sizeof(CtlActionT)); + if(ActionLoadOne(apiHandle, alsaMap->action, alsaMap->actionJ, 0)) { + AFB_ApiError(apiHandle, + "%s: Didn't succeed to load action using alsa object:\n-- %s", + __func__, + json_object_get_string(alsaMap->actionJ)); + return -4; + } + } + + if(afb_dynapi_add_verb(apiHandle, alsaMap->uid, alsaMap->info, HalCtlsActionOnAlsaCtl, (void *) alsaMap, NULL, 0)) { + AFB_ApiError(apiHandle, + "%s: Didn't to create verb for current alsa control to load action using alsa object:\n-- %s", + __func__, + json_object_get_string(alsaMap->actionJ)); + return -5; + } + + return 0; +} + +int HalCtlsProcessAllHalMap(AFB_ApiT apiHandle, json_object *AlsaMapJ, struct CtlHalAlsaMapT *currentCtlHalAlsaMapT) { - AFB_ApiWarning(apiHandle, "JAI :%s not implemented yet", __func__); + int idx, err = 0; + + struct CtlHalAlsaMap *ctlMaps; + + switch(json_object_get_type(AlsaMapJ)) { + case json_type_array: + currentCtlHalAlsaMapT->ctlsCount = json_object_array_length(AlsaMapJ); + break; + + case json_type_object: + currentCtlHalAlsaMapT->ctlsCount = 1; + break; + + default: + currentCtlHalAlsaMapT->ctlsCount = 0; + currentCtlHalAlsaMapT->ctls = NULL; + AFB_ApiWarning(apiHandle, "%s: couldn't get content of 'halmap' section in:\n-- %s", __func__, json_object_get_string(AlsaMapJ)); + return -3; + } + + ctlMaps = calloc(currentCtlHalAlsaMapT->ctlsCount, sizeof(struct CtlHalAlsaMap)); + + for(idx = 0; idx < currentCtlHalAlsaMapT->ctlsCount; idx++) + err += HalCtlsProcessOneHalMapObject(apiHandle, &ctlMaps[idx], currentCtlHalAlsaMapT->ctlsCount == 1 ? AlsaMapJ : json_object_array_get_idx(AlsaMapJ, idx)); + + currentCtlHalAlsaMapT->ctls = ctlMaps; + + return err; +} + +int HalCtlsHandleAllHalMap(AFB_ApiT apiHandle, int sndCardId, struct CtlHalAlsaMapT *currentCtlHalAlsaMapT) +{ + int idx, err = 0; + + char cardIdString[6]; + + snprintf(cardIdString, 6, "hw:%i", sndCardId); + + HalCtlsSubscribeToAlsaCardEvent(apiHandle, cardIdString); + + for(idx = 0; idx < currentCtlHalAlsaMapT->ctlsCount; idx++) + err += HalCtlsHandleOneHalMapObject(apiHandle, cardIdString, ¤tCtlHalAlsaMapT->ctls[idx]); + + return err; +} + +int HalCtlsHalMapConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *AlsaMapJ) +{ + CtlConfigT *ctrlConfig; + struct SpecificHalData *currentHalData; + + ctrlConfig = (CtlConfigT *) afb_dynapi_get_userdata(apiHandle); + if(! ctrlConfig) + return -1; + + currentHalData = (struct SpecificHalData *) ctrlConfig->external; + if(! currentHalData) + return -2; + + if(AlsaMapJ) { + currentHalData->ctlHalSpecificData->ctlHalAlsaMapT = calloc(1, sizeof(struct CtlHalAlsaMapT)); + + if(HalCtlsProcessAllHalMap(apiHandle, AlsaMapJ, currentHalData->ctlHalSpecificData->ctlHalAlsaMapT)) { + AFB_ApiError(apiHandle, "%s: failed to process 'halmap' section", __func__); + return -3; + } + } + else if(currentHalData->status == HAL_STATUS_UNAVAILABLE) { + AFB_ApiWarning(apiHandle, "%s: hal is unavailable, 'halmap' section data can't be handle", __func__); + return 1; + } + else if(currentHalData->sndCardId < 0) { + AFB_ApiError(apiHandle, "%s: hal alsa card id is not valid, 'halmap' section data can't be handle", __func__); + return -6; + } + else if(! currentHalData->ctlHalSpecificData->ctlHalAlsaMapT) { + AFB_ApiWarning(apiHandle, "%s: 'halmap' section data is empty", __func__); + return 2; + } + else if(! (currentHalData->ctlHalSpecificData->ctlHalAlsaMapT->ctlsCount > 0)) { + AFB_ApiWarning(apiHandle, "%s: no alsa controls defined in 'halmap' section", __func__); + return 3; + } + else if(HalCtlsHandleAllHalMap(apiHandle, currentHalData->sndCardId, currentHalData->ctlHalSpecificData->ctlHalAlsaMapT)) { + AFB_ApiError(apiHandle, "%s: failed to handle 'halmap' section", __func__); + return -9; + } return 0; } |