summaryrefslogtreecommitdiffstats
path: root/4a-hal
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
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')
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c360
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.h63
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c2
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c297
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h3
-rw-r--r--4a-hal/4a-hal-utilities/4a-hal-utilities-data.h4
6 files changed, 722 insertions, 7 deletions
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,12 +21,55 @@
#include <string.h>
#include <stdbool.h>
+#include <wrap-json.h>
+
+#include <alsa/asoundlib.h>
+
+#include <ctl-plugin.h>
+
#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", &currentAlsaCtl->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 <stdio.h>
#include <stdbool.h>
-#define ALSACORE_API "alsacore"
-#define ALSACORE_GETINFO_VERB "infoget"
+#include <wrap-json.h>
+
+#include <alsa/asoundlib.h>
+
+#include <ctl-plugin.h>
+
+#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
@@ -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;
}
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 <ctl-config.h>
+// 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 <ctl-config.h>
+#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;