aboutsummaryrefslogtreecommitdiffstats
path: root/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c
diff options
context:
space:
mode:
authorJonathan Aillet <jonathan.aillet@iot.bzh>2018-06-08 11:16:26 +0200
committerJonathan Aillet <jonathan.aillet@iot.bzh>2018-10-08 15:52:51 +0200
commit7297c6b5d2dc47574e981c76a282e67fcef230c0 (patch)
tree32235026a9a8a89c8e333c2572ea71b3f739c6f5 /4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c
parent180b6af527b44dc8d5c4c9f7931e9ccf45d13811 (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.c297
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, &currentCtlHalAlsaMapT->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;
}