aboutsummaryrefslogtreecommitdiffstats
path: root/ALSA-afb
diff options
context:
space:
mode:
Diffstat (limited to 'ALSA-afb')
-rw-r--r--ALSA-afb/Alsa-AddCtl.c138
-rw-r--r--ALSA-afb/Alsa-RegEvt.c47
-rw-r--r--ALSA-afb/Alsa-SetGet.c31
3 files changed, 159 insertions, 57 deletions
diff --git a/ALSA-afb/Alsa-AddCtl.c b/ALSA-afb/Alsa-AddCtl.c
index b7e3d90..7a68ab5 100644
--- a/ALSA-afb/Alsa-AddCtl.c
+++ b/ALSA-afb/Alsa-AddCtl.c
@@ -29,7 +29,7 @@
#include "Alsa-ApiHat.h"
// Performs like a toggle switch for attenuation, because they're bool (ref:user-ctl-element-set.c)
-static const unsigned int *allocate_bool_elem_set_tlv (void) {
+static const unsigned int *allocate_bool_fake_tlv (void) {
static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0);
unsigned int *tlv= malloc(sizeof(range));
if (tlv == NULL) return NULL;
@@ -37,8 +37,30 @@ static const unsigned int *allocate_bool_elem_set_tlv (void) {
return tlv;
}
+static const unsigned int *allocate_int_dbscale_tlv (int min, int step, int mute) {
+ // SNDRV_CTL_TLVD_DECLARE_DB_SCALE(range, min, step, mute);
+ size_t tlvSize = sizeof(4*sizeof(int*));
+ unsigned int *tlv= malloc(tlvSize);
+ tlv[0]=SNDRV_CTL_TLVT_DB_LINEAR;
+ tlv[1]=(int)tlvSize;
+ tlv[2]=min*100;
+ tlv[3] = ((step*100) & SNDRV_CTL_TLVD_DB_SCALE_MASK) | ((mute*100) ? SNDRV_CTL_TLVD_DB_SCALE_MUTE : 0);
+ return tlv;
+}
+
+static const unsigned int *allocate_int_linear_tlv (int max, int min) {
+ // SNDRV_CTL_TLVD_DECLARE_DB_LINEAR (range, min, max);
+ size_t tlvSize = sizeof(4*sizeof(int*));
+ unsigned int *tlv= malloc(tlvSize);
+ tlv[0]=SNDRV_CTL_TLVT_DB_SCALE;
+ tlv[1]=(int)tlvSize;
+ tlv[2]=-min*100;
+ tlv[3]=max*100;
+ return tlv;
+}
+
STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ, halQueryMode queryMode) {
- int err, ctlNumid;
+ int err, ctlNumid, ctlValue;
json_object *tmpJ;
const char *ctlName;
ctlRequestT ctlRequest;
@@ -53,7 +75,7 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
json_object_object_get_ex (ctlJ, "name" , &tmpJ);
ctlName = json_object_get_string(tmpJ);
- json_object_object_get_ex (ctlJ, "numid" , &tmpJ);
+ json_object_object_get_ex (ctlJ, "ctl" , &tmpJ);
ctlNumid = json_object_get_int(tmpJ);
if (!ctlNumid && !ctlName) {
@@ -70,17 +92,30 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
if (!err) {
snd_ctl_elem_id_alloca(&elemId);
snd_ctl_elem_info_get_id(elemInfo, elemId);
- if (ctlNumid) goto OnSucessExit; // hardware control nothing todo
+ if (snd_ctl_elem_info_get_numid(elemInfo)) goto OnSucessExit; // hardware control nothing todo
else { // user created kcontrol should be removable
err = snd_ctl_elem_remove(ctlDev, elemId);
- AFB_NOTICE ("ctlName=%s numid=%d fail to reset", snd_ctl_elem_info_get_name(elemInfo), snd_ctl_elem_info_get_numid(elemInfo));
- goto OnErrorExit;
+ if (err < 0) {
+ afb_req_fail_f (request, "ctl-reset-fail", "ctlName=%s numid=%d fail to reset", snd_ctl_elem_info_get_name(elemInfo), snd_ctl_elem_info_get_numid(elemInfo));
+ goto OnErrorExit;
+ } else elemInfo=NULL; // we remove control elemInfo is not valid anymore
}
}
+
+ // Control was deleted need to refresh elemInfo
+ if (!elemInfo) {
+ snd_ctl_elem_info_alloca(&elemInfo);
+ if (ctlName) snd_ctl_elem_info_set_name (elemInfo, ctlName);
+ snd_ctl_elem_info_set_interface (elemInfo, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_info(ctlDev, elemInfo);
+ }
// default for json_object_get_int is zero
json_object_object_get_ex (ctlJ, "min" , &tmpJ);
ctlMin = json_object_get_int(tmpJ);
+
+ json_object_object_get_ex (ctlJ, "value" , &tmpJ);
+ ctlValue = json_object_get_int(tmpJ);
json_object_object_get_ex (ctlJ, "max" , &tmpJ);
if (!tmpJ) ctlMax=1;
@@ -91,7 +126,7 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
else ctlStep = json_object_get_int(tmpJ);
json_object_object_get_ex (ctlJ, "count" , &tmpJ);
- if (!tmpJ) ctlCount=2;
+ if (!tmpJ) ctlCount=1;
else ctlCount = json_object_get_int(tmpJ);
json_object_object_get_ex (ctlJ, "snddev" , &tmpJ);
@@ -113,17 +148,17 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
switch (ctlType) {
case SND_CTL_ELEM_TYPE_BOOLEAN:
- err = snd_ctl_add_boolean_elem_set(ctlDev, elemInfo, 1, ctlCount);
+ err = snd_ctl_add_boolean_elem_set(ctlDev, elemInfo, ctlCount, ctlCount);
if (err) {
afb_req_fail_f (request, "ctl-invalid-bool", "devid=%s crl=%s invalid boolean data", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
goto OnErrorExit;
}
- elemTlv = allocate_bool_elem_set_tlv();
+ elemTlv = allocate_bool_fake_tlv();
// Provide FALSE as default value
for (int idx=0; idx < ctlCount; idx ++) {
- snd_ctl_elem_value_set_boolean (elemValue, idx, 1);
+ snd_ctl_elem_value_set_boolean (elemValue, idx, ctlValue);
}
break;
@@ -136,27 +171,79 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
// Provide 0 as default value
for (int idx=0; idx < ctlCount; idx ++) {
- snd_ctl_elem_value_set_integer (elemValue, idx, 0);
- }
+ snd_ctl_elem_value_set_integer (elemValue, idx, ctlValue);
+ }
+
+ // Fulup needed to be tested with some dB expert !!!
+ json_object *dbscaleJ;
+ if (json_object_object_get_ex (ctlJ, "dbscale" , &dbscaleJ)) {
+ if (json_object_get_type(dbscaleJ) != json_type_object) {
+ afb_req_fail_f (request, "ctl-invalid-dbscale", "devid=%s crl=%s invalid json in integer control", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
+ goto OnErrorExit;
+
+ json_object_object_get_ex (ctlJ, "min" , &tmpJ);
+ int min = json_object_get_int(tmpJ);
+ if (min >= 0) {
+ afb_req_fail_f (request, "ctl-invalid-dbscale", "devid=%s crl=%s min should be a negative number", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
+ goto OnErrorExit;
+ }
+
+ // default value 0=mute
+ json_object_object_get_ex (ctlJ, "max" , &tmpJ);
+ int max = json_object_get_int(tmpJ);
+
+ // default value 1dB
+ json_object_object_get_ex (ctlJ, "step" , &tmpJ);
+ int step = json_object_get_int(tmpJ);
+ if (step <= 0) step=1;
+
+ elemTlv = allocate_int_dbscale_tlv (min, max, step);
+
+ }
+ } else {
+ // provide a fake linear TLV
+ elemTlv = allocate_int_linear_tlv (ctlMin, ctlMax);
+ }
break;
- case SND_CTL_ELEM_TYPE_INTEGER64:
- err = snd_ctl_add_integer64_elem_set (ctlDev, elemInfo, 1, ctlCount, ctlMin, ctlMax, ctlStep);
+
+ case SND_CTL_ELEM_TYPE_ENUMERATED: {
+ json_object *enumsJ;
+ json_object_object_get_ex (ctlJ, "enums" , &enumsJ);
+ if (json_object_get_type(enumsJ) != json_type_array) {
+ afb_req_fail_f (request, "ctl-missing-enums", "devid=%s crl=%s mandatory enum=xxx missing in enumerated control", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
+ goto OnErrorExit;
+ }
+
+ int length = json_object_array_length(enumsJ);
+ const char **enumlabels = malloc(length*sizeof(char*));
+
+ for (int jdx=0; jdx < length; jdx++) {
+ tmpJ = json_object_array_get_idx(enumsJ, jdx);
+ enumlabels[jdx] = json_object_get_string(tmpJ);
+ }
+
+ err = snd_ctl_add_enumerated_elem_set (ctlDev, elemInfo, 1, ctlCount, length, enumlabels);
if (err) {
- afb_req_fail_f (request, "ctl-invalid-bool", "devid=%s crl=%s invalid boolean data", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
+ afb_req_fail_f (request, "ctl-invalid-bool", "devid=%s crl=%s invalid enumerated control", snd_ctl_name(ctlDev), json_object_get_string(ctlJ));
goto OnErrorExit;
}
-
+
// Provide 0 as default value
for (int idx=0; idx < ctlCount; idx ++) {
- snd_ctl_elem_value_set_integer64 (elemValue, idx, 0);
+ snd_ctl_elem_value_set_enumerated (elemValue, idx, ctlValue);
}
- break;
+
+ elemTlv = allocate_bool_fake_tlv();
- case SND_CTL_ELEM_TYPE_ENUMERATED:
+ break;
+ }
+
+ // Long Term Waiting ToDoList
+ case SND_CTL_ELEM_TYPE_INTEGER64:
case SND_CTL_ELEM_TYPE_BYTES:
default:
- afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_get_string(ctlJ));
+ afb_req_fail_f (request, "ctl-invalid-type", "crl=%s unsupported/unknown element type", json_object_get_string(ctlJ));
goto OnErrorExit;
}
@@ -177,7 +264,7 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_obje
afb_req_fail_f (request, "TLV-write-fail", "crl=%s numid=%d fail to write data error=%s", json_object_get_string(ctlJ), snd_ctl_elem_info_get_numid(elemInfo), snd_strerror(err));
goto OnErrorExit;
}
- }
+ }
// return newly created as a JSON object
OnSucessExit:
@@ -225,9 +312,9 @@ PUBLIC void alsaAddCustomCtls(afb_req request) {
switch (json_object_get_type(ctlsJ)) {
case json_type_object:
- ctlsValues= addOneSndCtl(request, ctlDev, ctlsJ, queryMode);
-
- break;
+ ctlsValues= addOneSndCtl(request, ctlDev, ctlsJ, queryMode);
+ if (!ctlsValues) goto OnErrorExit;
+ break;
case json_type_array:
ctlsValues= json_object_new_array();
@@ -235,6 +322,7 @@ PUBLIC void alsaAddCustomCtls(afb_req request) {
json_object *ctlJ = json_object_array_get_idx (ctlsJ, idx);
ctlValues= addOneSndCtl(request, ctlDev, ctlJ, queryMode) ;
if (ctlValues) json_object_array_add (ctlsValues, ctlValues);
+ else goto OnErrorExit;
}
break;
@@ -247,6 +335,6 @@ PUBLIC void alsaAddCustomCtls(afb_req request) {
afb_req_success(request, ctlsValues, NULL);
OnErrorExit:
- if (ctlDev) snd_ctl_close(ctlDev);
+ if (ctlDev) snd_ctl_close(ctlDev);
return;
} \ No newline at end of file
diff --git a/ALSA-afb/Alsa-RegEvt.c b/ALSA-afb/Alsa-RegEvt.c
index df6570a..add3944 100644
--- a/ALSA-afb/Alsa-RegEvt.c
+++ b/ALSA-afb/Alsa-RegEvt.c
@@ -71,7 +71,7 @@ OnErrorExit:
// This routine is called when ALSA event are fired
STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* userData) {
- int err;
+ int err, ctlNumid;
evtHandleT *evtHandle = (evtHandleT*)userData;
snd_ctl_event_t *eventId;
json_object *ctlEventJ;
@@ -79,12 +79,12 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void*
int iface;
int device;
int subdev;
- const char*devname;
+ const char*ctlName;
ctlRequestT ctlRequest;
snd_ctl_elem_id_t *elemId;
if ((revents & EPOLLHUP) != 0) {
- AFB_NOTICE( "SndCtl hanghup [car disconnected]");
+ AFB_NOTICE("SndCtl hanghup [car disconnected]");
goto ExitOnSucess;
}
@@ -108,21 +108,30 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void*
err = alsaGetSingleCtl (evtHandle->ctlDev, elemId, &ctlRequest, evtHandle->mode);
if (err) goto OnErrorExit;
+
+ // If CTL as a value use it as container for response
+ if (ctlRequest.valuesJ) ctlEventJ= ctlRequest.valuesJ;
+ else {
+ ctlEventJ = json_object_new_object();
+ ctlNumid = snd_ctl_event_elem_get_numid(eventId);
+ json_object_object_add(ctlEventJ, "id",json_object_new_int (ctlNumid));
+ }
- iface = snd_ctl_event_elem_get_interface(eventId);
- device = snd_ctl_event_elem_get_device(eventId);
- subdev = snd_ctl_event_elem_get_subdevice(eventId);
- devname= snd_ctl_event_elem_get_name(eventId);
-
- // proxy ctlevent as a binder event
- ctlEventJ = json_object_new_object();
- json_object_object_add(ctlEventJ, "device" ,json_object_new_int (device));
- json_object_object_add(ctlEventJ, "subdev" ,json_object_new_int (subdev));
- if (evtHandle->mode < 2) {
- json_object_object_add(ctlEventJ, "iface" ,json_object_new_int (iface));
- json_object_object_add(ctlEventJ, "devname",json_object_new_string (devname));
+ if (evtHandle->mode >= QUERY_COMPACT) {
+ ctlName = snd_ctl_event_elem_get_name(eventId);
+ json_object_object_add(ctlEventJ, "name",json_object_new_string (ctlName));
+ }
+
+ if (evtHandle->mode >= QUERY_VERBOSE) {
+ iface = snd_ctl_event_elem_get_interface(eventId);
+ device = snd_ctl_event_elem_get_device(eventId);
+ subdev = snd_ctl_event_elem_get_subdevice(eventId);
+ json_object_object_add(ctlEventJ, "ifc" ,json_object_new_int (iface));
+ json_object_object_add(ctlEventJ, "dev" ,json_object_new_int (device));
+ json_object_object_add(ctlEventJ, "sub" ,json_object_new_int (subdev));
}
- if (ctlRequest.valuesJ) (json_object_object_add(ctlEventJ, "value" ,ctlRequest.valuesJ));
+
+
AFB_DEBUG( "sndCtlEventCB=%s", json_object_get_string(ctlEventJ));
afb_event_push(evtHandle->afbevt, ctlEventJ);
}
@@ -234,7 +243,7 @@ PUBLIC void alsaEvtSubcribe (afb_req request) {
// Subscribe to every Alsa CtlEvent send by a given board
STATIC json_object *alsaProbeCardId (afb_req request) {
char devid [10];
- const char *devname, *shortname, *longname;
+ const char *ctlName, *shortname, *longname;
int card, err, index, idx;
json_object *responseJ;
snd_ctl_t *ctlDev;
@@ -260,12 +269,12 @@ STATIC json_object *alsaProbeCardId (afb_req request) {
// extract sound card information
snd_ctl_card_info(ctlDev, cardinfo);
index = snd_ctl_card_info_get_card(cardinfo);
- devname = snd_ctl_card_info_get_id(cardinfo);
+ ctlName = snd_ctl_card_info_get_id(cardinfo);
shortname= snd_ctl_card_info_get_name(cardinfo);
longname = snd_ctl_card_info_get_longname(cardinfo);
// check if short|long name match
- if (!strcmp (sndname, devname)) break;
+ if (!strcmp (sndname, ctlName)) break;
if (!strcmp (sndname, shortname)) break;
if (!strcmp (sndname, longname)) break;
}
diff --git a/ALSA-afb/Alsa-SetGet.c b/ALSA-afb/Alsa-SetGet.c
index 50b62ce..5a41ec1 100644
--- a/ALSA-afb/Alsa-SetGet.c
+++ b/ALSA-afb/Alsa-SetGet.c
@@ -618,7 +618,7 @@ PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe
if (snd_ctl_elem_info_is_tlv_readable(elemInfo)) {
unsigned int *tlv = alloca(TLV_BYTE_SIZE);
if ((err = snd_ctl_elem_tlv_read(ctlDev, elemId, tlv, 4096)) < 0) {
- fprintf (stderr, "Control %s element TLV read error\n", snd_strerror(err));
+ AFB_NOTICE ("Control numid=%d err=%s element TLV read error\n", numid, snd_strerror(err));
goto OnErrorExit;
} else {
json_object_object_add (ctlRequest->valuesJ,"tlv", decodeTlv (tlv, TLV_BYTE_SIZE, queryMode));
@@ -642,15 +642,14 @@ STATIC void alsaSetGetCtls (ActionSetGetT action, afb_req request) {
unsigned int ctlCount;
snd_ctl_t *ctlDev;
snd_ctl_elem_list_t *ctlList;
- json_object *sndctls=json_object_new_array();;
queryValuesT queryValues;
- json_object *queryJ, *numidsJ;
+ json_object *queryJ, *numidsJ, *sndctls;
queryJ = alsaCheckQuery (request, &queryValues);
if (!queryJ) goto OnErrorExit;
// Prase Numids + optional values
- done= json_object_object_get_ex (queryJ, "numid" , &numidsJ);
+ done= json_object_object_get_ex (queryJ, "ctl" , &numidsJ);
if (!done) queryValues.count=0;
else {
enum json_type jtype= json_object_get_type(numidsJ);
@@ -701,6 +700,10 @@ STATIC void alsaSetGetCtls (ActionSetGetT action, afb_req request) {
ctlRequest= alloca (sizeof(ctlRequestT)*(queryValues.count));
NumidsListParse (action, &queryValues, ctlRequest);
}
+
+ // if more than one crl requested prepare an array for response
+ if (queryValues.count!= 1 && action==ACTION_GET) sndctls=json_object_new_array();
+ else sndctls=NULL;
// Loop on all ctlDev controls
for (int ctlIndex=0; ctlIndex < ctlCount; ctlIndex++) {
@@ -745,7 +748,11 @@ STATIC void alsaSetGetCtls (ActionSetGetT action, afb_req request) {
}
if (err) status++;
else {
- if (action == ACTION_GET) json_object_array_add (sndctls, ctlRequest[jdx].valuesJ);
+ // Do not embed response in an array when only one ctl was requested
+ if (action == ACTION_GET) {
+ if (queryValues.count > 1) json_object_array_add (sndctls, ctlRequest[jdx].valuesJ);
+ else sndctls = ctlRequest[jdx].valuesJ;
+ }
}
}
}
@@ -755,16 +762,14 @@ STATIC void alsaSetGetCtls (ActionSetGetT action, afb_req request) {
for (int jdx=0; jdx < queryValues.count; jdx++) {
if (ctlRequest[jdx].used <= 0) {
json_object *failctl = json_object_new_object();
- json_object_object_add (failctl, "numid", ctlRequest[jdx].jToken);
- if (ctlRequest[jdx].valuesJ) json_object_object_add(failctl, "value", ctlRequest[jdx].valuesJ);
-
- AFB_NOTICE ("*** jToken=%s value=%s", json_object_get_string(ctlRequest[jdx].jToken), json_object_get_string(ctlRequest[jdx].valuesJ));
-
- if (ctlRequest[jdx].numId == -1) json_object_object_add (failctl, "error", json_object_new_string ("Numid Invalid"));
+ if (ctlRequest[jdx].numId == -1) json_object_object_add (failctl, "warning", json_object_new_string ("Numid Invalid"));
else {
- if (ctlRequest[jdx].used == 0) json_object_object_add (failctl, "error", json_object_new_string ("Numid Does Not Exist"));
- if (ctlRequest[jdx].used == -1) json_object_object_add (failctl, "error", json_object_new_string ("Value invalid"));
+ if (ctlRequest[jdx].used == 0) json_object_object_add (failctl, "warning", json_object_new_string ("Numid Does Not Exist"));
+ if (ctlRequest[jdx].used == -1) json_object_object_add (failctl, "warning", json_object_new_string ("Value Refused"));
}
+
+ json_object_object_add (failctl, "ctl", ctlRequest[jdx].jToken);
+
json_object_array_add (warningsJ, failctl);
}
/* WARNING!!!! Check with Jose why following put free valuesJ