summaryrefslogtreecommitdiffstats
path: root/4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c
diff options
context:
space:
mode:
Diffstat (limited to '4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c')
-rw-r--r--4a-hal/4a-hal-controllers/4a-hal-controllers-alsacore-link.c360
1 files changed, 360 insertions, 0 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