diff options
Diffstat (limited to 'ALSA-afb')
-rw-r--r-- | ALSA-afb/Alsa-AddCtl.c | 180 | ||||
-rw-r--r-- | ALSA-afb/Alsa-ApiHat.c | 1 | ||||
-rw-r--r-- | ALSA-afb/Alsa-ApiHat.h | 1 | ||||
-rw-r--r-- | ALSA-afb/Alsa-SetGet.c | 2 | ||||
-rw-r--r-- | ALSA-afb/CMakeLists.txt | 2 |
5 files changed, 184 insertions, 2 deletions
diff --git a/ALSA-afb/Alsa-AddCtl.c b/ALSA-afb/Alsa-AddCtl.c new file mode 100644 index 0000000..e30ebea --- /dev/null +++ b/ALSA-afb/Alsa-AddCtl.c @@ -0,0 +1,180 @@ +/* + * AlsaUseCase -- provide low level interface with ALSA lib (extracted from alsa-json-gateway code) + * Copyright (C) 2015,2016,2017, Fulup Ar Foll fulup@iot.bzh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + +*/ +#define _GNU_SOURCE // needed for vasprintf + +#include <alsa/asoundlib.h> +#include <systemd/sd-event.h> +#include "Alsa-ApiHat.h" + +STATIC int addOneSndCtl(struct afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) { + snd_ctl_elem_info_t *cinfo; + int err; + int i; + unsigned int def_val; + json_object *jName, *jNumid, *jTmp; + const char *ctlName; + int ctlNumid, ctlMax, ctlMin, ctlStep, ctlCount, ctlSubDev; + snd_ctl_elem_type_t ctlType; + snd_ctl_elem_info_t *elemInfo; + + // parse json ctl object + json_object_object_get_ex (ctlJ, "name" , &jName); + json_object_object_get_ex (ctlJ, "numid", &jNumid); + if (!jName || !jNumid) { + afb_req_fail_f (request, "ctl-invalid", "crl=%s name/numid missing", json_object_to_json_string(ctlJ)); + goto OnErrorExit; + } + + ctlName = json_object_to_json_string(jName); + ctlNumid = json_object_get_int(jNumid); + + // default for json_object_get_int is zero + json_object_object_get_ex (ctlJ, "min" , &jTmp); + ctlMin = json_object_get_int(jTmp); + + json_object_object_get_ex (ctlJ, "max" , &jTmp); + if (!jTmp) ctlMax=1; + else ctlMax = json_object_get_int(jTmp); + + json_object_object_get_ex (ctlJ, "step" , &jTmp); + if (!jTmp) ctlStep=1; + else ctlStep = json_object_get_int(jTmp); + + json_object_object_get_ex (ctlJ, "count" , &jTmp); + if (!jTmp) ctlCount=2; + else ctlCount = json_object_get_int(jTmp); + + json_object_object_get_ex (ctlJ, "subdev" , &jTmp); + ctlSubDev = json_object_get_int(jTmp); + + json_object_object_get_ex (ctlJ, "type" , &jTmp); + if (!jTmp) ctlType=SND_CTL_ELEM_TYPE_INTEGER; + else ctlType = json_object_get_int(jTmp); + + // set info event ID and get value + snd_ctl_elem_info_alloca(&elemInfo); + snd_ctl_elem_info_set_name (elemInfo, ctlName); // map ctlInfo to ctlId elemInfo is updated !!! + snd_ctl_elem_info_set_numid(elemInfo, ctlNumid); // map ctlInfo to ctlId elemInfo is updated !!! + + if (snd_ctl_elem_info(ctlDev, elemInfo) >= 0) { + afb_req_fail_f (request, "ctl-already-exist", "crl=%s name/numid not unique", json_object_to_json_string(ctlJ)); + goto OnErrorExit; + } + + snd_ctl_elem_info_set_subdevice(elemInfo, ctlSubDev); + + switch (ctlType) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + err = snd_ctl_add_boolean_elem_set(ctlDev, cinfo, 1, ctlCount); + if (err) { + afb_req_fail_f (request, "ctl-invalid-bool", "crl=%s invalid boolean data", json_object_to_json_string(ctlJ)); + goto OnErrorExit; + } + break; + + case SND_CTL_ELEM_TYPE_INTEGER: + break; + + case SND_CTL_ELEM_TYPE_INTEGER64: + break; + + case SND_CTL_ELEM_TYPE_ENUMERATED: + break; + + case SND_CTL_ELEM_TYPE_BYTES: + break; + + default: + afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_to_json_string(ctlJ)); + goto OnErrorExit; + } + + + snd_ctl_elem_write(ctlDev, &ctlElem); + + return 0; + + OnErrorExit: + return -1; +} + +// Subscribe to every Alsa CtlEvent send by a given board +PUBLIC void alsaAddCustomCtl (struct afb_req request) { + snd_ctl_t *ctlDev; + int err; + const char *devid, *ctls; + json_object *ctlsJ; + + devid = afb_req_value(request, "devid"); + if (!devid) { + afb_req_fail_f (request, "missing-devid", "devid=xxx missing"); + goto OnErrorExit; + } + + // open control interface for devid + err = snd_ctl_open(&ctlDev, devid, 0); + if (err < 0) { + ctlDev=NULL; + afb_req_fail_f (request, "devid-unknown", "SndCard devid=%s Not Found err=%s", queryValues.devid, snd_strerror(err)); + goto OnErrorExit; + } + + ctls = afb_req_value(request, "ctls"); + if (!ctls) { + afb_req_fail_f (request, "missing-ctls", "ctls=[{name:xxx, numdid=xx, ...}] missing"); + goto OnErrorExit; + } + + ctlsJ = json_tokener_parse(ctls); + if (!ctlsJ) { + afb_req_fail_f (request, "ctls-notjson","ctls=%s not a valid json entry", ctls); + goto OnErrorExit; + }; + + enum json_type jtype= json_object_get_type(ctlsJ); + switch (jtype) { + int error; + json_object *ctlJ; + + case json_type_array: + int count = json_object_array_length (ctlsJ); + for (int idx=0; idx < count; idx ++) { + ctlJ = json_object_array_get_idx (ctlsJ, idx); + error = alsaAddCtrl (request, ctlDev, ctlsJ); + if (error) goto OnErrorExit; + } + break; + + case json_type_object: + error = alsaAddCtrl (request, ctlDev, ctlsJ); + if (error) goto OnErrorExit; + break; + + default: + afb_req_fail_f (request, "ctls-notarray","ctls=%s not valid JSON control object", ctls); + goto OnErrorExit; + } + + snd_ctl_close(ctlDev); + return; + + OnErrorExit: + if (ctlDev) snd_ctl_close(ctlDev); + return; +} + diff --git a/ALSA-afb/Alsa-ApiHat.c b/ALSA-afb/Alsa-ApiHat.c index 261b54d..9520ce7 100644 --- a/ALSA-afb/Alsa-ApiHat.c +++ b/ALSA-afb/Alsa-ApiHat.c @@ -47,6 +47,7 @@ static const struct afb_verb_desc_v1 binding_verbs[] = { { .name= "ucmget", .session= AFB_SESSION_NONE, .callback= alsaUseCaseGet, .info= "Use Case Get" }, { .name= "ucmreset", .session= AFB_SESSION_NONE, .callback= alsaUseCaseReset,.info= "Use Case Reset to Default" }, { .name= "ucmclose", .session= AFB_SESSION_NONE, .callback= alsaUseCaseClose,.info= "Use Case Close Manager" }, + { .name= "addctl", .session= AFB_SESSION_NONE, .callback= alsaAddCustomCtl ,.info= "Add User Custom Sound Control" }, { .name= NULL } /* marker for end of the array */ }; diff --git a/ALSA-afb/Alsa-ApiHat.h b/ALSA-afb/Alsa-ApiHat.h index c0fd51f..44ef26f 100644 --- a/ALSA-afb/Alsa-ApiHat.h +++ b/ALSA-afb/Alsa-ApiHat.h @@ -53,6 +53,7 @@ PUBLIC void alsaUseCaseSet(struct afb_req request); PUBLIC void alsaUseCaseGet(struct afb_req request); PUBLIC void alsaUseCaseClose(struct afb_req request); PUBLIC void alsaUseCaseReset(struct afb_req request); +PUBLIC void alsaAddCustomCtl(struct afb_req request); diff --git a/ALSA-afb/Alsa-SetGet.c b/ALSA-afb/Alsa-SetGet.c index abf1a6a..025846f 100644 --- a/ALSA-afb/Alsa-SetGet.c +++ b/ALSA-afb/Alsa-SetGet.c @@ -896,7 +896,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { if (err) goto OnErrorExit; - // open control interface for devid + // open control interface for devid err = snd_ctl_open(&ctlDev, queryValues.devid, SND_CTL_READONLY); if (err < 0) { ctlDev=NULL; diff --git a/ALSA-afb/CMakeLists.txt b/ALSA-afb/CMakeLists.txt index 8ba1a78..5c62149 100644 --- a/ALSA-afb/CMakeLists.txt +++ b/ALSA-afb/CMakeLists.txt @@ -20,7 +20,7 @@ PROJECT_TARGET_ADD(alsa-lowlevel) # Define project Targets - ADD_LIBRARY(alsa-lowlevel MODULE Alsa-ApiHat.c Alsa-SetGet.c Alsa-Ucm.c) + ADD_LIBRARY(alsa-lowlevel MODULE Alsa-ApiHat.c Alsa-SetGet.c Alsa-Ucm.c Alsa-AddCtl.c) # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(alsa-lowlevel PROPERTIES |