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 +++++++++++++++++++++ 1 file changed, 360 insertions(+) (limited to '4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c') 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 -- cgit 1.2.3-korg