From 7297c6b5d2dc47574e981c76a282e67fcef230c0 Mon Sep 17 00:00:00 2001 From: Jonathan Aillet Date: Fri, 8 Jun 2018 11:16:26 +0200 Subject: 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 --- .../4a-hal-controllers-alsacore-link.c | 360 +++++++++++++++++++++ .../4a-hal-controllers-alsacore-link.h | 63 +++- .../4a-hal-controllers-api-loader.c | 2 +- 4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c | 297 ++++++++++++++++- 4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h | 3 + 4a-hal/4a-hal-utilities/4a-hal-utilities-data.h | 4 +- 6 files changed, 722 insertions(+), 7 deletions(-) (limited to '4a-hal') diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c index f3c1388..462994a 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c @@ -21,11 +21,54 @@ #include #include +#include + +#include + +#include + #include "../4a-hal-utilities/4a-hal-utilities-data.h" #include "../4a-hal-utilities/4a-hal-utilities-appfw-responses-handler.h" #include "4a-hal-controllers-alsacore-link.h" +/******************************************************************************* + * Map to alsa control types * + ******************************************************************************/ + +static const char *const snd_ctl_elem_type_names[] = { + [SND_CTL_ELEM_TYPE_NONE]= "NONE", + [SND_CTL_ELEM_TYPE_BOOLEAN]= "BOOLEAN", + [SND_CTL_ELEM_TYPE_INTEGER]="INTEGER", + [SND_CTL_ELEM_TYPE_ENUMERATED]="ENUMERATED", + [SND_CTL_ELEM_TYPE_BYTES]="BYTES", + [SND_CTL_ELEM_TYPE_IEC958]="IEC958", + [SND_CTL_ELEM_TYPE_INTEGER64]="INTEGER64", +}; + +/******************************************************************************* + * Alsa control types map from string function * + ******************************************************************************/ + +snd_ctl_elem_type_t HalCtlsMapsAlsaTypeToEnum(const char *label) +{ + int idx; + static int length = sizeof(snd_ctl_elem_type_names) / sizeof(char *); + + for(idx = 0; idx < length; idx++) { + if(! strcasecmp(label, snd_ctl_elem_type_names[idx])) + return (snd_ctl_elem_type_t) idx; + } + + return SND_CTL_ELEM_TYPE_NONE; +} + +/******************************************************************************* + * TODO JAI : add function to free 'CtlHalAlsaMapT' * + ******************************************************************************/ + + + /******************************************************************************* * HAL controllers alsacore calls funtions * ******************************************************************************/ @@ -76,4 +119,321 @@ int HalCtlsGetCardIdByCardPath(AFB_ApiT apiHandle, char *devPath) } return cardId; +} + +int HalCtlsSubscribeToAlsaCardEvent(AFB_ApiT apiHandle, char *cardId) +{ + char *returnedStatus = NULL, *returnedInfo = NULL; + + enum CallError returnedError; + + json_object *subscribeQueryJ, *returnedJ, *returnedWarningJ; + + wrap_json_pack(&subscribeQueryJ, "{s:s}", "devid", cardId); + if(AFB_ServiceSync(apiHandle, ALSACORE_API, ALSACORE_SUBSCRIBE_VERB, subscribeQueryJ, &returnedJ)) { + returnedError = HalUtlHandleAppFwCallError(apiHandle, ALSACORE_API, ALSACORE_SUBSCRIBE_VERB, returnedJ, &returnedStatus, &returnedInfo); + AFB_ApiError(apiHandle, + "Error %i during call to verb %s of %s api with status '%s' and info '%s'", + (int) returnedError, + ALSACORE_SUBSCRIBE_VERB, + ALSACORE_API, + returnedStatus ? returnedStatus : "not returned", + returnedInfo ? returnedInfo : "not returned"); + return -1; + } + else if(! wrap_json_unpack(returnedJ, "{s:{s:o}}", "info", &returnedWarningJ)) { + AFB_ApiError(apiHandle, + "Warning raised during call to verb %s of %s api : '%s'", + ALSACORE_SUBSCRIBE_VERB, + ALSACORE_API, + json_object_get_string(returnedWarningJ)); + return -2; + } + + return 0; +} + +int HalCtlsGetAlsaCtlInfo(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaCtl *currentAlsaCtl) +{ + char *returnedStatus = NULL, *returnedInfo = NULL; + + enum CallError returnedError; + + json_object *queryJ, *returnedJ; + + if(! apiHandle) { + AFB_ApiError(apiHandle, "%s: api handle not available", __func__); + return -1; + } + + if(! cardId) { + AFB_ApiError(apiHandle, "%s: card id is not available", __func__); + return -2; + } + + if(! currentAlsaCtl) { + AFB_ApiError(apiHandle, "%s: alsa control data structure is not available", __func__); + return -3; + } + + if(currentAlsaCtl->name && currentAlsaCtl->numid > 0) { + AFB_ApiError(apiHandle, + "%s: Can't have both a control name (%s) and a control uid (%i)", + __func__, + currentAlsaCtl->name, + currentAlsaCtl->numid); + return -4; + } + else if(currentAlsaCtl->name) { + wrap_json_pack(&queryJ, "{s:s s:s}", "devid", cardId, "ctl", currentAlsaCtl->name); + } + else if(currentAlsaCtl->numid > 0) { + wrap_json_pack(&queryJ, "{s:s s:i}", "devid", cardId, "ctl", currentAlsaCtl->numid); + } + else { + AFB_ApiError(apiHandle, "%s: Need at least a control name or a control uid", __func__); + return -5; + } + + if(AFB_ServiceSync(apiHandle, ALSACORE_API, ALSACORE_CTLGET_VERB, queryJ, &returnedJ)) { + returnedError = HalUtlHandleAppFwCallError(apiHandle, ALSACORE_API, ALSACORE_CTLGET_VERB, returnedJ, &returnedStatus, &returnedInfo); + AFB_ApiError(apiHandle, + "Error %i during call to verb %s of %s api with status '%s' and info '%s'", + (int) returnedError, + ALSACORE_CTLGET_VERB, + ALSACORE_API, + returnedStatus ? returnedStatus : "not returned", + returnedInfo ? returnedInfo : "not returned"); + return -6; + } + + if(currentAlsaCtl->name && wrap_json_unpack(returnedJ, "{s:{s:i}}", "response", "id", ¤tAlsaCtl->numid)) { + AFB_ApiError(apiHandle, "Can't find alsa control 'id' from control 'name': '%s' on device '%s'", currentAlsaCtl->name, cardId); + return -7; + } + else if(! json_object_object_get_ex(returnedJ, "response", NULL)) { + AFB_ApiError(apiHandle, "Can't find alsa control 'id': %i on device '%s'", currentAlsaCtl->numid, cardId); + return -8; + } + + return 0; +} + +int HalCtlsSetAlsaCtlValue(AFB_ApiT apiHandle, char *cardId, int ctlId, json_object *valuesJ) +{ + char *returnedStatus = NULL, *returnedInfo = NULL; + + enum CallError returnedError; + + json_object *queryJ, *returnedJ, *returnedWarningJ; + + if(! apiHandle) { + AFB_ApiError(apiHandle, "%s: api handle not available", __func__); + return -1; + } + + if(! cardId) { + AFB_ApiError(apiHandle, "%s: card id is not available", __func__); + return -2; + } + + if(ctlId <= 0) { + AFB_ApiError(apiHandle, "%s: Alsa control id is not valid", __func__); + return -3; + } + + if(! valuesJ) { + AFB_ApiError(apiHandle, "%s: values to set json is not available", __func__); + return -4; + } + + wrap_json_pack(&queryJ, "{s:s s:{s:i s:o}}", "devid", cardId, "ctl", "id", ctlId, "val", valuesJ); + + if(AFB_ServiceSync(apiHandle, ALSACORE_API, ALSACORE_CTLSET_VERB, queryJ, &returnedJ)) { + returnedError = HalUtlHandleAppFwCallError(apiHandle, ALSACORE_API, ALSACORE_CTLSET_VERB, returnedJ, &returnedStatus, &returnedInfo); + AFB_ApiError(apiHandle, + "Error %i during call to verb %s of %s api with status '%s' and info '%s'", + (int) returnedError, + ALSACORE_CTLSET_VERB, + ALSACORE_API, + returnedStatus ? returnedStatus : "not returned", + returnedInfo ? returnedInfo : "not returned"); + return 1; + } + + if(! wrap_json_unpack(returnedJ, "{s:{s:o}}", "request", "info", &returnedWarningJ)) { + AFB_ApiError(apiHandle, + "Warning raised during call to verb %s of %s api : '%s'", + ALSACORE_CTLSET_VERB, + ALSACORE_API, + json_object_get_string(returnedWarningJ)); + return 2; + } + + return 0; +} + +int HalCtlsCreateAlsaCtl(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaCtl *alsaCtlToCreate) +{ + char *returnedStatus = NULL, *returnedInfo = NULL; + + enum CallError returnedError; + + json_object *queryJ, *returnedJ, *returnedWarningJ, *responseJ; + + if(! apiHandle) { + AFB_ApiError(apiHandle, "%s: api handle not available", __func__); + return -1; + } + + if(! cardId) { + AFB_ApiError(apiHandle, "%s: card id is not available", __func__); + return -2; + } + + if(! alsaCtlToCreate) { + AFB_ApiError(apiHandle, "%s: alsa control data structure is not available", __func__); + return -3; + } + + if(! alsaCtlToCreate->alsaCtlCreation) { + AFB_ApiError(apiHandle, "%s: alsa control data for creation structure is not available", __func__); + return -4; + } + + wrap_json_pack(&queryJ, "{s:s s:{s:i s:s s:i s:i s:i s:i s:i s:i} s:i}", + "devid", cardId, + "ctl", + "ctl", -1, + "name", alsaCtlToCreate->name, + "min", alsaCtlToCreate->alsaCtlCreation->minval, + "max", alsaCtlToCreate->alsaCtlCreation->maxval, + "step", alsaCtlToCreate->alsaCtlCreation->step, + "type", (int) alsaCtlToCreate->alsaCtlCreation->type, + "count", alsaCtlToCreate->alsaCtlCreation->count); + + if(AFB_ServiceSync(apiHandle, ALSACORE_API, ALSACORE_ADDCTL_VERB, queryJ, &returnedJ)) { + returnedError = HalUtlHandleAppFwCallError(apiHandle, ALSACORE_API, ALSACORE_ADDCTL_VERB, returnedJ, &returnedStatus, &returnedInfo); + AFB_ApiError(apiHandle, + "Error %i during call to verb %s of %s api with status '%s' and info '%s'", + (int) returnedError, + ALSACORE_GETINFO_VERB, + ALSACORE_API, + returnedStatus ? returnedStatus : "not returned", + returnedInfo ? returnedInfo : "not returned"); + return -5; + } + + if(! wrap_json_unpack(returnedJ, "{s:{s:o}}", "request", "info", &returnedWarningJ)) { + AFB_ApiError(apiHandle, + "Warning raised during call to verb %s of %s api : '%s'", + ALSACORE_GETINFO_VERB, + ALSACORE_API, + json_object_get_string(returnedWarningJ)); + return -6; + } + else if(wrap_json_unpack(returnedJ, "{s:o}", "response", &responseJ)) { + AFB_ApiError(apiHandle, + "Can't get response of call to verb %s of %s api : %s", + ALSACORE_GETINFO_VERB, + ALSACORE_API, + json_object_get_string(returnedJ)); + return -7; + } + else if(wrap_json_unpack(responseJ, "{s:i}", "id", &alsaCtlToCreate->numid)) { + AFB_ApiError(apiHandle, + "Can't get create id from %s of %s api", + ALSACORE_GETINFO_VERB, + ALSACORE_API); + return -8; + } + else if(wrap_json_unpack(responseJ, "{s:o}", "ctl", NULL)) { + AFB_ApiWarning(apiHandle, "Control %s was already present but has been updated", alsaCtlToCreate->name); + } + + return 0; +} + +/******************************************************************************* + * HAL controllers alsacore controls request callback * + ******************************************************************************/ + +void HalCtlsActionOnAlsaCtl(AFB_ReqT request) +{ + char cardIdString[6]; + + AFB_ApiT apiHandle; + + CtlConfigT *ctrlConfig; + + struct SpecificHalData *currentCtlHalData; + struct CtlHalAlsaMap *currentAlsaCtl; + + json_object *requestJson; + + apiHandle = (AFB_ApiT) afb_request_get_dynapi(request); + if(! apiHandle) { + AFB_ReqFail(request, "api_handle", "Can't get current hal controller api handle"); + return; + } + + ctrlConfig = (CtlConfigT *) afb_dynapi_get_userdata(apiHandle); + if(! ctrlConfig) { + AFB_ReqFail(request, "hal_controller_config", "Can't get current hal controller config"); + return; + } + + currentCtlHalData = (struct SpecificHalData *) ctrlConfig->external; + if(! currentCtlHalData) { + AFB_ReqFail(request, "hal_controller_data", "Can't get current hal controller data"); + return; + } + + if(currentCtlHalData->status == HAL_STATUS_UNAVAILABLE) { + AFB_ReqFail(request, "hal_unavailable", "Seems that hal is not available"); + return; + } + + currentAlsaCtl = (struct CtlHalAlsaMap *) afb_request_get_vcbdata(request); + if(! currentAlsaCtl) { + AFB_ReqFail(request, "alsa_control_data", "Can't get current alsa control data"); + return; + } + + if(currentAlsaCtl->ctl.numid <= 0) { + AFB_ReqFail(request, "alsa_control_id", "Alsa control id is not valid"); + return; + } + + requestJson = AFB_ReqJson(request); + if(! requestJson) { + AFB_ReqFail(request, "request_json", "Can't get request json"); + return; + } + + switch(json_object_get_type(requestJson)) { + case json_type_object : + case json_type_array : + break; + + default: + AFB_ReqFailF(request, "request_json", "Request json is not valid '%s'", json_object_get_string(requestJson)); + return; + } + + snprintf(cardIdString, 6, "hw:%i", currentCtlHalData->sndCardId); + + // TODO JAI: add weighting passing values on currentAlsaCtl->value (and put them into valueJ json) + + // TODO JAI : test it + if(HalCtlsSetAlsaCtlValue(apiHandle, cardIdString, currentAlsaCtl->ctl.numid, requestJson)) { + AFB_ReqFailF(request, + "alsa_control_call_error", + "Error while trying to set value on alsa control %i, device '%s'", + currentAlsaCtl->ctl.numid, + cardIdString); + return; + } + + AFB_ReqSucess(request, NULL, "Action on alsa control correclty done"); } \ No newline at end of file diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.h b/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.h index bae8291..d2687eb 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.h +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.h @@ -21,10 +21,69 @@ #include #include -#define ALSACORE_API "alsacore" -#define ALSACORE_GETINFO_VERB "infoget" +#include + +#include + +#include + +#define ALSACORE_API "alsacore" +#define ALSACORE_SUBSCRIBE_VERB "subscribe" +#define ALSACORE_GETINFO_VERB "infoget" +#define ALSACORE_CTLGET_VERB "ctlget" +#define ALSACORE_CTLSET_VERB "ctlset" +#define ALSACORE_ADDCTL_VERB "addcustomctl" + +struct CtlHalAlsaDBScale { + int min; + int max; + int step; + int mute; +}; + +struct CtlHalAlsaCtlProperties { + snd_ctl_elem_type_t type; + int count; + int minval; + int maxval; + int step; + // TBD JAI : use them + const char **enums; + struct CtlHalAlsaDBScale *dbscale; +}; + +struct CtlHalAlsaCtl { + char *name; + int numid; + int value; + struct CtlHalAlsaCtlProperties alsaCtlProperties; + struct CtlHalAlsaCtlProperties *alsaCtlCreation; +}; + +struct CtlHalAlsaMap { + const char *uid; + char *info; + struct CtlHalAlsaCtl ctl; + json_object *actionJ; + CtlActionT *action; +}; + +struct CtlHalAlsaMapT { + struct CtlHalAlsaMap *ctls; + unsigned int ctlsCount; +}; + +// Alsa control types map from string function +snd_ctl_elem_type_t HalCtlsMapsAlsaTypeToEnum(const char *label); // HAL controllers alsacore calls funtions int HalCtlsGetCardIdByCardPath(AFB_ApiT apiHandle, char *devPath); +int HalCtlsSubscribeToAlsaCardEvent(AFB_ApiT apiHandle, char *cardId); +int HalCtlsGetAlsaCtlInfo(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaCtl *currentAlsaCtl); +int HalCtlsSetAlsaCtlValue(AFB_ApiT apiHandle, char *cardId, int ctlId, json_object *valuesJ); +int HalCtlsCreateAlsaCtl(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaCtl *alsaCtlToCreate); + +// HAL controllers alsacore controls request callback +void HalCtlsActionOnAlsaCtl(AFB_ReqT request); #endif /* _HAL_CTLS_ALSACORE_LINK_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c index cb91b4e..f0ef696 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c @@ -140,7 +140,7 @@ static int HalCtlsLoadOneApi(void *cbdata, AFB_ApiT apiHandle) err = CtlLoadSections(apiHandle, ctrlConfig, ctrlSections); // Declare an event manager for this Api - afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent); + afb_dynapi_on_event(apiHandle, HalCtlsDispatchApiEvent); // Init Api function (does not receive user closure ???) afb_dynapi_on_init(apiHandle, HalCtlsInitOneApi); 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 @@ -30,6 +30,86 @@ #include "4a-hal-controllers-mixer-handler.h" #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; } diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h index ba17997..e3eeeeb 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h @@ -24,6 +24,9 @@ #include +// HAL controller event handler function +void HalCtlsDispatchApiEvent(afb_dynapi *apiHandle, const char *evtLabel, json_object *eventJ); + // HAL controllers sections parsing functions int HalCtlsHalMixerConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *MixerJ); int HalCtlsHalMapConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *StreamControlsJ); diff --git a/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h b/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h index b472df6..64c5d8e 100644 --- a/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h +++ b/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h @@ -27,6 +27,8 @@ #include +#include "../4a-hal-controllers/4a-hal-controllers-alsacore-link.h" + #define ALSA_MAX_CARD 32 // Enum for sharing hal (controller or external) status @@ -55,7 +57,7 @@ struct CtlHalSpecificData { json_object *halMixerJ; struct CtlHalStreamsDataT ctlHalStreamsData; - // TODO JAI : add structure to hold halmap section data + struct CtlHalAlsaMapT *ctlHalAlsaMapT; AFB_ApiT apiHandle; CtlConfigT *ctrlConfig; -- cgit 1.2.3-korg