summaryrefslogtreecommitdiffstats
path: root/HAL-afb
diff options
context:
space:
mode:
authorfulup <fulup.arfoll@iot.bzh>2017-07-23 01:23:37 +0200
committerfulup <fulup.arfoll@iot.bzh>2017-07-23 01:23:37 +0200
commita7a6ae4be87ee9178905ab784d84a4c0a8303f9b (patch)
treee5aa96fba9c7ed59f60dd1641fc30c2eeb512e50 /HAL-afb
parent044828c43097362973c82088a7afee760eab06ec (diff)
Added TLV->DBscale into HAL control
1st Working version of HAL ctl-get with TLV Cleanup HTML5 test pages WIP Only
Diffstat (limited to 'HAL-afb')
-rw-r--r--HAL-afb/HAL-interface/CMakeLists.txt2
-rw-r--r--HAL-afb/HAL-interface/hal-interface.c194
-rw-r--r--HAL-afb/HAL-interface/hal-interface.h17
-rw-r--r--HAL-afb/HAL-interface/hal-volmap.c96
-rw-r--r--HAL-afb/HAL-plugin/HalPlugCtl.c2
5 files changed, 203 insertions, 108 deletions
diff --git a/HAL-afb/HAL-interface/CMakeLists.txt b/HAL-afb/HAL-interface/CMakeLists.txt
index d4dba4b..c367c5c 100644
--- a/HAL-afb/HAL-interface/CMakeLists.txt
+++ b/HAL-afb/HAL-interface/CMakeLists.txt
@@ -21,7 +21,7 @@
PROJECT_TARGET_ADD(hal-interface)
# Define targets
- ADD_LIBRARY(${TARGET_NAME} STATIC hal-interface.c)
+ ADD_LIBRARY(${TARGET_NAME} STATIC hal-volmap.c hal-interface.c)
# Library properties
SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME halinterface)
diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c
index dd00d1c..1f39a81 100644
--- a/HAL-afb/HAL-interface/hal-interface.c
+++ b/HAL-afb/HAL-interface/hal-interface.c
@@ -19,16 +19,7 @@
* http://www.tldp.org/HOWTO/Alsa-sound-6.html
*/
#define _GNU_SOURCE // needed for vasprintf
-#include <stdio.h>
#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <math.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
#include "hal-interface.h"
static alsaHalMapT *halCtls;
@@ -61,72 +52,30 @@ STATIC void halSubscribe(afb_req request) {
}
}
-// HAL normalise volume values to 0-100%
-STATIC struct json_object *UnNormaliseValue(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ) {
- int length;
- // assert response as the right length
- length = json_object_array_length(valuesJ);
- if (length != halCtls->count) {
- AFB_WARNING ("NormaliseValue invalid ctl='%s' values count=%d len=%d", halCtls->name, halCtls->count, length);
- return NULL;
- }
-
- json_object *normalisedJ= json_object_new_array();
- for (int idx=0; idx <length; idx++) {
- json_object *valueJ = json_object_array_get_idx (valuesJ, idx);
- int value = json_object_get_int(valueJ);
-
- // cleanup and normalise value
- if (value > halCtls->maxval) value= halCtls->maxval;
- if (value < halCtls->minval) value= halCtls->minval;
-
- // If Integer scale to 0/100
- if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) {
- value = (value * 100) / (halCtls->maxval - halCtls->minval);
- }
-
- json_object_array_add(normalisedJ, json_object_new_int(value));
+
+// Map HAL ctlName to ctlLabel
+STATIC int halCtlStringToIndex (const char* label) {
+
+ for (int idx = 0; halCtls[idx].ctl.numid; idx++) {
+ if (!strcmp (halCtls[idx].label, label)) return idx;
}
- return (normalisedJ);
+ // not found
+ return -1;
}
+STATIC int halCtlTagToIndex (halCtlsEnumT tag) {
-
-// HAL normalise volume values to 0-100%
-STATIC struct json_object *NormaliseValue(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ) {
- int length;
-
- // assert response as the right length
- length = json_object_array_length(valuesJ);
- if (length != halCtls->count) {
- AFB_WARNING ("NormaliseValue invalid ctl=%s values count=%d len=%d", halCtls->name, halCtls->count, length);
- return NULL;
- }
-
- json_object *normalisedJ= json_object_new_array();
- for (int idx=0; idx <length; idx++) {
- json_object *valueJ = json_object_array_get_idx (valuesJ, idx);
- int value = json_object_get_int(valueJ);
-
- // cleanup and normalise value
- if (value > halCtls->maxval) value= halCtls->maxval;
- if (value < halCtls->minval) value= halCtls->minval;
-
- // If Integer scale to 0/100
- if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) {
- value = (value * 100) / (halCtls->maxval - halCtls->minval);
- }
-
- json_object_array_add(normalisedJ, json_object_new_int(value));
+ for (int idx = 0; halCtls[idx].ctl.numid; idx++) {
+ if (halCtls[idx].tag == tag) return idx;
}
- return (normalisedJ);
+ // not found
+ return -1;
}
-
// Return ALL HAL snd controls
PUBLIC void halListCtls(afb_req request) {
struct json_object *ctlsHalJ = json_object_new_array();
@@ -144,26 +93,6 @@ PUBLIC void halListCtls(afb_req request) {
afb_req_success (request, ctlsHalJ, NULL);
}
-// Map HAL ctlName to ctlLabel
-STATIC int halCtlStringToIndex (const char* label) {
-
- for (int idx = 0; halCtls[idx].ctl.numid; idx++) {
- if (!strcmp (halCtls[idx].label, label)) return idx;
- }
-
- // not found
- return -1;
-}
-
-STATIC int halCtlTagToIndex (halCtlsEnumT tag) {
-
- for (int idx = 0; halCtls[idx].ctl.numid; idx++) {
- if (halCtls[idx].tag == tag) return idx;
- }
-
- // not found
- return -1;
-}
STATIC int halGetCtlIndex (afb_req request, struct json_object*ctlInJ) {
struct json_object *tmpJ;
@@ -200,6 +129,43 @@ STATIC int halGetCtlIndex (afb_req request, struct json_object*ctlInJ) {
return -1;
}
+// HAL normalise volume values to 0-100%
+STATIC struct json_object *UnNormaliseValue(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ) {
+ int length;
+
+ // assert response as the right length
+ length = json_object_array_length(valuesJ);
+ if (length != halCtls->count) {
+ AFB_WARNING ("UnNormaliseValue invalid ctl='%s' values count=%d len=%d", halCtls->name, halCtls->count, length);
+ return NULL;
+ }
+
+ json_object *normalisedJ= json_object_new_array();
+ for (int idx=0; idx < halCtls->count; idx++) {
+ int value;
+
+ // use last value in array when number of values does not match with actual ctl count
+ if (idx < length) {
+ json_object *valueJ = json_object_array_get_idx (valuesJ, idx);
+ value = json_object_get_int(valueJ);
+
+ // cleanup and normalise value
+ if (value > halCtls->maxval) value= halCtls->maxval;
+ if (value < halCtls->minval) value= halCtls->minval;
+
+ // If Integer move from 0-100% to effective value
+ if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) {
+ value = (value * (halCtls->maxval-halCtls->minval))/100;
+ }
+ }
+
+ // add unnormalised value into response
+ json_object_array_add(normalisedJ, json_object_new_int(value));
+ }
+
+ return (normalisedJ);
+}
+
// Translate high level control to low level and call lower layer
PUBLIC void halSetCtls(afb_req request) {
@@ -212,11 +178,11 @@ PUBLIC void halSetCtls(afb_req request) {
switch (json_object_get_type(ctlsInJ)) {
case json_type_object: {
- // control is in literal form {tag=xxx, label=xxx, val=xxxx}
+ // control is in literal form {tag=xxx, label=xxx, value=xxxx}
index = halGetCtlIndex (request, ctlsInJ);
if (index <=0) goto OnErrorExit;
- err= json_object_object_get_ex (ctlsInJ, "val" , &valuesJ);
+ err= json_object_object_get_ex (ctlsInJ, "value" , &valuesJ);
if (err) {
afb_req_fail_f(request, "ctl-invalid", "No val=[val1, ...] ctl='%s'", json_object_get_string(ctlsInJ));
goto OnErrorExit;
@@ -234,7 +200,7 @@ PUBLIC void halSetCtls(afb_req request) {
index= halGetCtlIndex (request, ctlInJ);
if (index<=0) goto OnErrorExit;
- err= json_object_object_get_ex (ctlInJ, "val" , &valuesJ);
+ err= json_object_object_get_ex (ctlInJ, "value" , &valuesJ);
if (err) {
afb_req_fail_f(request, "ctl-invalid", "No val=[val1, ...] ctl='%s'", json_object_get_string(ctlsInJ));
goto OnErrorExit;
@@ -257,7 +223,7 @@ PUBLIC void halSetCtls(afb_req request) {
// Call now level CTL
queryJ = json_object_new_object();
json_object_object_add(queryJ, "devid", json_object_new_string (halDevid));
- json_object_object_add(queryJ, "numids", ctlsOutJ);
+ json_object_object_add(queryJ, "numid", ctlsOutJ);
err= afb_service_call_sync("alsacore", "setctls", queryJ, &responseJ);
if (err) {
@@ -313,7 +279,7 @@ STATIC json_object *CtlGetPrepareResponse(afb_req request, struct json_object *c
struct json_object *halCtlJ = json_object_new_object();
json_object_object_add(halCtlJ, "label", json_object_new_string(halCtls[idx].label)); // idx+1 == HAL/NUMID
json_object_object_add(halCtlJ, "tag" , json_object_new_int(halCtls[idx].tag)); // idx+1 == HAL/NUMID
- json_object_object_add(halCtlJ, "val" , NormaliseValue(&halCtls[idx].ctl, valJ));
+ json_object_object_add(halCtlJ, "val" , GetNormaliseVolume(&halCtls[idx].ctl, valJ));
json_object_array_add(halResponseJ, halCtlJ);
break;
}
@@ -366,9 +332,9 @@ PUBLIC void halGetCtls(afb_req request) {
// Call now level CTL
queryJ = json_object_new_object();
json_object_object_add(queryJ, "devid", json_object_new_string (halDevid));
- json_object_object_add(queryJ, "numids", ctlsOutJ);
+ json_object_object_add(queryJ, "numid", ctlsOutJ);
- err= afb_service_call_sync("alsacore", "getctls", queryJ, &responseJ);
+ err= afb_service_call_sync("alsacore", "getctl", queryJ, &responseJ);
if (err) {
afb_req_fail_f(request, "subcall:alsacore/getctl", "%s", json_object_get_string(responseJ));
goto OnErrorExit;
@@ -418,17 +384,14 @@ PUBLIC void halServiceEvent(const char *evtname, struct json_object *eventJ) {
STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) {
struct json_object *tmpJ, *ctlJ;
- AFB_NOTICE ("*** %s, ", json_object_get_string(sndCtlJ));
-
- // make sure we face a valid Alsa Low level ctl
- if (!json_object_object_get_ex (sndCtlJ, "ctrl" , &ctlJ)) return -1;
-
json_object_object_get_ex (sndCtlJ, "name" , &tmpJ);
ctl->name = (char*)json_object_get_string(tmpJ);
json_object_object_get_ex (sndCtlJ, "numid" , &tmpJ);
ctl->numid = json_object_get_int(tmpJ);
+ // make sure we face a valid Alsa Low level ctl
+ if (!json_object_object_get_ex (sndCtlJ, "ctl" , &ctlJ)) goto OnErrorExit;
json_object_object_get_ex (ctlJ, "min" , &tmpJ);
ctl->minval = json_object_get_int(tmpJ);
@@ -445,7 +408,33 @@ STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) {
json_object_object_get_ex (ctlJ, "type" , &tmpJ);
ctl->type = (snd_ctl_elem_type_t)json_object_get_int(tmpJ);
+ // process dbscale TLV if any
+ if (json_object_object_get_ex (sndCtlJ, "tlv" , &tmpJ)) {
+ struct json_object *dbscaleJ;
+
+ if (!json_object_object_get_ex (tmpJ, "dbscale" , &dbscaleJ)) {
+ AFB_WARNING("TLV found but not DBscale attached ctl name=%s numid=%d", ctl->name, ctl->numid);
+ } else {
+ ctl->dbscale = malloc (sizeof (alsaHalDBscaleT));
+
+ json_object_object_get_ex (dbscaleJ, "min" , &tmpJ);
+ ctl->dbscale->min = (snd_ctl_elem_type_t)json_object_get_int(tmpJ);
+
+ json_object_object_get_ex (dbscaleJ, "max" , &tmpJ);
+ ctl->dbscale->max = (snd_ctl_elem_type_t)json_object_get_int(tmpJ);
+
+ json_object_object_get_ex (dbscaleJ, "step" , &tmpJ);
+ ctl->dbscale->step = (snd_ctl_elem_type_t)json_object_get_int(tmpJ);
+
+ json_object_object_get_ex (dbscaleJ, "mute" , &tmpJ);
+ ctl->dbscale->mute = (snd_ctl_elem_type_t)json_object_get_int(tmpJ);
+ }
+ }
+
return 0;
+
+ OnErrorExit:
+ return -1;
}
// this is call when after all bindings are loaded
@@ -510,7 +499,8 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar
queryurl = json_object_new_object();
json_object_get(devidJ); // make sure devidJ does not get free by 1st call.
json_object_object_add(queryurl, "devid",devidJ);
- json_object_object_add(queryurl, "ctls",ctlsJ);
+ json_object_object_add(queryurl, "ctl",ctlsJ);
+ json_object_object_add(queryurl, "mode",json_object_new_int(QUERY_COMPACT));
err= afb_service_call_sync ("alsacore", "addcustomctl", queryurl, &responseJ);
if (err) {
AFB_ERROR ("Fail creating HAL Custom ALSA ctls Response='%s'", json_object_get_string(responseJ));
@@ -553,10 +543,10 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar
// Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT
PUBLIC afb_verb_v2 halServiceApi[] = {
- /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */
- { .verb = "ping", .callback = pingtest},
- { .verb = "listctls", .callback = halListCtls},
- { .verb = "getctls", .callback = halGetCtls},
- { .verb = "subscribe", .callback = halSubscribe},
+ /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */
+ { .verb = "ping", .callback = pingtest},
+ { .verb = "ctl-list", .callback = halListCtls},
+ { .verb = "ctl-get", .callback = halGetCtls},
+ { .verb = "evt-sub", .callback = halSubscribe},
{ .verb = NULL} /* marker for end of the array */
};
diff --git a/HAL-afb/HAL-interface/hal-interface.h b/HAL-afb/HAL-interface/hal-interface.h
index 2cd3586..afe480e 100644
--- a/HAL-afb/HAL-interface/hal-interface.h
+++ b/HAL-afb/HAL-interface/hal-interface.h
@@ -24,15 +24,21 @@
#include "audio-interface.h"
typedef struct {
+ int min;
+ int max;
+ int step;
+ int mute;
+} alsaHalDBscaleT;
+
+typedef struct {
char* name;
int numid;
- int values;
+ snd_ctl_elem_type_t type;
+ int count;
int minval;
int maxval;
int step;
- int count;
- snd_ctl_elem_type_t type;
- halAclEnumT acl;
+ alsaHalDBscaleT *dbscale;
} alsaHalCtlMapT;
// avoid compiler warning [Jose does not like typedef :) ]
@@ -62,6 +68,9 @@ extern afb_verb_v2 halServiceApi[];
PUBLIC void halServiceEvent(const char *evtname, struct json_object *object);
PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard);
+// hal-volmap.c
+PUBLIC struct json_object *GetNormaliseVolume(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ);
+
#endif /* SHAREHALLIB_H */
diff --git a/HAL-afb/HAL-interface/hal-volmap.c b/HAL-afb/HAL-interface/hal-volmap.c
new file mode 100644
index 0000000..de99974
--- /dev/null
+++ b/HAL-afb/HAL-interface/hal-volmap.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 "IoT.bzh"
+ * Author 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.
+ *
+ * references:
+ * alsa-util/amixer.c + alsa-lib/simple.c
+ */
+
+#define _GNU_SOURCE // needed for vasprintf
+#include <math.h>
+#include "hal-interface.h"
+
+
+typedef enum {
+ DB_NORMALIZE_LINEAR,
+ DB_NORMALIZE_MATH,
+} enumRandeModeDB_T;
+
+// Return Value express from 0-100%
+STATIC int dbNormalizeVal (enumRandeModeDB_T normaliseMode, const alsaHalDBscaleT *dbscale, int value) {
+ double normalized, min_norm;
+
+ // To get real DB from TLV DB values should be divided by 100
+ switch (normaliseMode) {
+ case DB_NORMALIZE_LINEAR:
+ normalized = ((double)(value-dbscale->min)/(double)(dbscale->max-dbscale->min))*100;
+ break;
+
+ case DB_NORMALIZE_MATH:
+ normalized = exp10((double)(value - dbscale->max) / 6000.0);
+ if (dbscale->min != SND_CTL_TLV_DB_GAIN_MUTE) {
+ min_norm = exp10((double)(dbscale->min - dbscale->max) / 6000.0);
+ normalized = (normalized - min_norm) / (1 - min_norm);
+ }
+ break;
+
+ default:
+ normalized=0;
+ }
+
+ return (int)round(normalized*100);
+}
+
+// HAL normalise volume values to 0-100%
+PUBLIC struct json_object *GetNormaliseVolume(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ) {
+ int useNormalizeDB;
+
+ // If not valid db_scale let's use raw_scale
+ if (!halCtls->dbscale || (halCtls->dbscale->min >= halCtls->dbscale->max)) {
+
+ // dbscale is invalid let's try raw range
+ if (halCtls->minval >= halCtls->maxval) goto ExitOnError;
+
+ // Use Raw Scale Model
+ useNormalizeDB= 0;
+
+ } else { // db_scale looks OK let's use it
+ if ((halCtls->dbscale->max - halCtls->dbscale->min) <= MAX_LINEAR_DB_SCALE * 100) useNormalizeDB= DB_NORMALIZE_LINEAR;
+ else useNormalizeDB = DB_NORMALIZE_MATH;
+
+ }
+
+ // loop on values to normalise
+ int length = json_object_array_length(valuesJ);
+ json_object *normalisedJ= json_object_new_array();
+ for (int idx=0; idx <length; idx++) {
+ json_object *valueJ = json_object_array_get_idx (valuesJ, idx);
+ int value = json_object_get_int(valueJ);
+
+ // If Integer scale to 0/100
+ if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) {
+ if (useNormalizeDB) value = dbNormalizeVal (useNormalizeDB, halCtls->dbscale, value);
+ else value = 100* (value - halCtls->minval) / (halCtls->maxval - halCtls->minval);
+ }
+
+ json_object_array_add(normalisedJ, json_object_new_int(value));
+ }
+
+ return (normalisedJ);
+
+ ExitOnError:
+ return NULL;
+}
+ \ No newline at end of file
diff --git a/HAL-afb/HAL-plugin/HalPlugCtl.c b/HAL-afb/HAL-plugin/HalPlugCtl.c
index 181d4f8..3755876 100644
--- a/HAL-afb/HAL-plugin/HalPlugCtl.c
+++ b/HAL-afb/HAL-plugin/HalPlugCtl.c
@@ -291,7 +291,7 @@ SND_CTL_PLUGIN_DEFINE_FUNC(afbhal) {
continue;
}
- if (strcmp(id, "ctls") == 0) {
+ if (strcmp(id, "ctl") == 0) {
const char *ctlConf;
snd_config_type_t ctype;
snd_config_iterator_t currentCtl, follow;