diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2017-10-24 22:11:21 +0200 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2017-10-24 22:11:21 +0200 |
commit | 036268ddd8c62114faf9afd4da3c35ffa2b6ecba (patch) | |
tree | 72429524bb9e4be47b760915a674e6473e305026 /HAL-afb/HAL-interface | |
parent | 2fd0fa8c77dbaaf40ba0812e43b6637ff1d1d76e (diff) |
Initial working version as independent repo
Diffstat (limited to 'HAL-afb/HAL-interface')
-rw-r--r-- | HAL-afb/HAL-interface/CMakeLists.txt | 37 | ||||
-rw-r--r-- | HAL-afb/HAL-interface/hal-interface.c | 626 | ||||
-rw-r--r-- | HAL-afb/HAL-interface/hal-interface.h | 106 | ||||
-rw-r--r-- | HAL-afb/HAL-interface/hal-volramp.c | 185 | ||||
-rw-r--r-- | HAL-afb/HAL-interface/hal-volume.c | 150 |
5 files changed, 0 insertions, 1104 deletions
diff --git a/HAL-afb/HAL-interface/CMakeLists.txt b/HAL-afb/HAL-interface/CMakeLists.txt deleted file mode 100644 index bbe2e94..0000000 --- a/HAL-afb/HAL-interface/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017 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. -########################################################################### - - -# Add target to project dependency list -PROJECT_TARGET_ADD(hal-interface) - - # Define targets - ADD_LIBRARY(${TARGET_NAME} STATIC hal-volume.c hal-volramp.c hal-interface.c) - - # Library properties - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES OUTPUT_NAME halinterface) - - # Library dependencies (include updates automatically) - TARGET_LINK_LIBRARIES(${TARGET_NAME} - audio-common - ) - - # Define target includes - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} - ) diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c deleted file mode 100644 index 4a32d72..0000000 --- a/HAL-afb/HAL-interface/hal-interface.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * 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. - * - * reference: - * amixer contents; amixer controls; - * http://www.tldp.org/HOWTO/Alsa-sound-6.html - */ -#define _GNU_SOURCE // needed for vasprintf -#include <string.h> -#include "hal-interface.h" -#include <systemd/sd-event.h> - -alsaHalSndCardT *halSndCard; - - -// Force specific HAL to depend on ShareHalLib -PUBLIC char* SharedHalLibVersion = "1.0"; - -// Subscribe to AudioBinding events - -STATIC void halSubscribe(afb_req request) { - const char *devidJ = afb_req_value(request, "devid"); - if (devidJ == NULL) { - afb_req_fail_f(request, "devidJ-missing", "devidJ=hw:xxx missing"); - } -} - -// Map HAL ctlName to ctlLabel - -STATIC int halCtlStringToIndex(const char* label) { - alsaHalMapT *halCtls = halSndCard->ctls; - - for (int idx = 0; halCtls[idx].tag != EndHalCrlTag; idx++) { - if (halCtls[idx].label && !strcasecmp(halCtls[idx].label, label)) return idx; - } - - // not found - return -1; -} - -STATIC int halCtlTagToIndex(halCtlsTagT tag) { - alsaHalMapT *halCtls = halSndCard->ctls; - - for (int idx = 0; halCtls[idx].tag != EndHalCrlTag; idx++) { - if (halCtls[idx].tag == tag) return idx; - } - - // not found - return -1; -} - - -// Return ALL HAL snd controls - -PUBLIC void halListCtls(afb_req request) { - alsaHalMapT *halCtls = halSndCard->ctls; - json_object *ctlsHalJ = json_object_new_array(); - - for (int idx = 0; halCtls[idx].ctl.numid; idx++) { - json_object *ctlHalJ = json_object_new_object(); - - if (halCtls[idx].label) json_object_object_add(ctlHalJ, "label", json_object_new_string(halCtls[idx].label)); - else json_object_object_add(ctlHalJ, "label", json_object_new_string("HAL Label Not Set ")); - json_object_object_add(ctlHalJ, "tag", json_object_new_int(halCtls[idx].tag)); - json_object_object_add(ctlHalJ, "count", json_object_new_int(halCtls[idx].ctl.count)); - - json_object_array_add(ctlsHalJ, ctlHalJ); - } - - afb_req_success(request, ctlsHalJ, NULL); -} - -STATIC int halGetCtlIndex(afb_req request, json_object*ctlInJ) { - json_object *tmpJ; - int tag, index, done; - - // check 1st short command mode [tag1, tag2, ...] - enum json_type jtype = json_object_get_type(ctlInJ); - switch (jtype) { - case json_type_array: - tmpJ = json_object_array_get_idx(ctlInJ, 0); - tag = json_object_get_int(tmpJ); - index = halCtlTagToIndex(tag); - break; - - case json_type_int: - tag = json_object_get_int(ctlInJ); - index = halCtlTagToIndex(tag); - break; - - case json_type_object: - done = json_object_object_get_ex(ctlInJ, "tag", &tmpJ); - if (done) { - tag = json_object_get_int(tmpJ); - index = halCtlTagToIndex(tag); - } else { - const char *label; - done = json_object_object_get_ex(ctlInJ, "label", &tmpJ); - if (!done) goto OnErrorExit; - label = json_object_get_string(tmpJ); - index = halCtlStringToIndex(label); - } - break; - - default: - goto OnErrorExit; - } - - if (index < 0) goto OnErrorExit; - - // return corresponding lowlevel numid to querylist - return index; - -OnErrorExit: - afb_req_fail_f(request, "ctl-invalid", "No Label/Tag given ctl='%s'", json_object_get_string(ctlInJ)); - return -1; -} - -STATIC int halCallAlsaSetCtls(json_object *ctlsOutJ) { - json_object *responseJ, *queryJ; - int err; - - // Call now level CTL - queryJ = json_object_new_object(); - json_object_object_add(queryJ, "devid", json_object_new_string(halSndCard->devid)); - json_object_object_add(queryJ, "ctl", ctlsOutJ); - - err = afb_service_call_sync("alsacore", "ctlset", queryJ, &responseJ); - json_object_put(responseJ); // let's ignore response - - return err; -} - - -// retrieve a single HAL control from its tag. - -PUBLIC int halSetCtlByTag(halRampEnumT tag, int value) { - json_object *ctlJ = json_object_new_array(); - alsaHalMapT *halCtls = halSndCard->ctls; - int err, index; - - index = halCtlTagToIndex(tag); - if (index < 0) goto OnErrorExit; - - json_object_array_add(ctlJ, json_object_new_int(halCtls[index].ctl.numid)); - json_object_array_add(ctlJ, volumeNormalise(ACTION_SET, &halCtls[index].ctl, json_object_new_int(value))); - - err = halCallAlsaSetCtls(ctlJ); - - return err; - -OnErrorExit: - return -1; -} - - -// Translate high level control to low level and call lower layer - -PUBLIC void halSetCtls(afb_req request) { - alsaHalMapT *halCtls = halSndCard->ctls; - int err, done, index; - json_object *ctlsInJ, *ctlsOutJ, *valuesJ; - - // get query from request - ctlsInJ = afb_req_json(request); - - switch (json_object_get_type(ctlsInJ)) { - case json_type_object: - { - ctlsOutJ = json_object_new_object(); - - // control is in literal form {tag=xxx, label=xxx, value=xxxx} - index = halGetCtlIndex(request, ctlsInJ); - if (index < 0) goto OnErrorExit; - - done = json_object_object_get_ex(ctlsInJ, "val", &valuesJ); - if (!done) { - afb_req_fail_f(request, "ctl-invalid", "No val=[val1, ...] ctl='%s'", json_object_get_string(ctlsInJ)); - goto OnErrorExit; - } - - json_object_object_add(ctlsOutJ, "id", json_object_new_int(halCtls[index].ctl.numid)); - json_object_object_add(ctlsOutJ, "val", volumeNormalise(ACTION_SET, &halCtls[index].ctl, valuesJ)); - break; - } - - case json_type_array: - { - ctlsOutJ = json_object_new_array(); - - for (int idx = 0; idx < json_object_array_length(ctlsInJ); idx++) { - json_object *ctlInJ = json_object_array_get_idx(ctlsInJ, idx); - index = halGetCtlIndex(request, ctlInJ); - if (index < 0) goto OnErrorExit; - - done = json_object_object_get_ex(ctlInJ, "val", &valuesJ); - if (!done) { - afb_req_fail_f(request, "ctl-invalid", "No val=[val1, ...] ctl='%s'", json_object_get_string(ctlsInJ)); - goto OnErrorExit; - } - // let's create alsa low level set control request - json_object *ctlOutJ = json_object_new_object(); - json_object_object_add(ctlOutJ, "id", json_object_new_int(halCtls[index].ctl.numid)); - json_object_object_add(ctlOutJ, "val", volumeNormalise(ACTION_SET, &halCtls[index].ctl, valuesJ)); - - json_object_array_add(ctlsOutJ, ctlOutJ); - } - break; - } - - default: - afb_req_fail_f(request, "ctl-invalid", "Not a valid JSON ctl='%s'", json_object_get_string(ctlsInJ)); - goto OnErrorExit; - } - - err = halCallAlsaSetCtls(ctlsOutJ); - if (err) { - afb_req_fail_f(request, "subcall:alsacore/setctl", "%s", json_object_get_string(ctlsOutJ)); - goto OnErrorExit; - } - - afb_req_success(request, NULL, NULL); - return; - -OnErrorExit: - return; -}; - -// Remap low level controls into HAL hight level ones - -STATIC json_object *HalGetPrepareResponse(afb_req request, json_object *ctlsJ) { - alsaHalMapT *halCtls = halSndCard->ctls; - json_object *halResponseJ; - int length; - - switch (json_object_get_type(ctlsJ)) { - case json_type_array: - // responseJ is a JSON array - halResponseJ = json_object_new_array(); - length = json_object_array_length(ctlsJ); - break; - case json_type_object: - halResponseJ = NULL; - length = 1; - break; - default: - afb_req_fail_f(request, "ctls-notarray", "Invalid Controls return from alsa/getcontrol ctlsJ=%s", json_object_get_string(ctlsJ)); - goto OnErrorExit; - } - - // loop on array and store values into client context - for (int idx = 0; idx < length; idx++) { - json_object *sndCtlJ, *valJ, *numidJ; - int numid; - - // extract control from array if any - if (halResponseJ) sndCtlJ = json_object_array_get_idx(ctlsJ, idx); - else sndCtlJ = ctlsJ; - - if (!json_object_object_get_ex(sndCtlJ, "id", &numidJ) || !json_object_object_get_ex(sndCtlJ, "val", &valJ)) { - afb_req_fail_f(request, "ctl-invalid", "Invalid Control return from alsa/getcontrol ctl=%s", json_object_get_string(sndCtlJ)); - goto OnErrorExit; - } - - // HAL and Business logic use the same AlsaMixerHal.h direct conversion - numid = (halCtlsTagT) json_object_get_int(numidJ); - - for (int idx = 0; halCtls[idx].ctl.numid; idx++) { - if (halCtls[idx].ctl.numid == numid) { - // translate low level numid to HAL one and normalise values - 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", volumeNormalise(ACTION_GET, &halCtls[idx].ctl, valJ)); - - if (halResponseJ) json_object_array_add(halResponseJ, halCtlJ); - else halResponseJ = halCtlJ; - - break; - } - } - if (halCtls[idx].ctl.numid == 0) { - afb_req_fail_f(request, "ctl-invalid", "Invalid Control numid=%d from alsa/getcontrol ctlJ=%s", numid, json_object_get_string(sndCtlJ)); - goto OnErrorExit; - } - } - return halResponseJ; - -OnErrorExit: - return NULL; -} - -STATIC json_object *halCallAlsaGetCtls(json_object *ctlsOutJ) { - json_object *responseJ, *queryJ; - int err, done; - - // Call now level CTL - queryJ = json_object_new_object(); - json_object_object_add(queryJ, "devid", json_object_new_string(halSndCard->devid)); - json_object_object_add(queryJ, "ctl", ctlsOutJ); - - err = afb_service_call_sync("alsacore", "ctlget", queryJ, &responseJ); - if (err) goto OnErrorExit; - - // Let ignore info data if any and keep on response - done = json_object_object_get_ex(responseJ, "response", &responseJ); - if (!done) goto OnErrorExit; - - return responseJ; - -OnErrorExit: - return NULL; -} - -// retrieve a single HAL control from its tag. - -PUBLIC json_object *halGetCtlByTag(halRampEnumT tag) { - json_object *responseJ, *valJ; - alsaHalMapT *halCtls = halSndCard->ctls; - int done, index; - - index = halCtlTagToIndex(tag); - if (index < 0) goto OnErrorExit; - responseJ = halCallAlsaGetCtls(json_object_new_int(halCtls[index].ctl.numid)); - - done = json_object_object_get_ex(responseJ, "val", &valJ); - if (!done) goto OnErrorExit; - - return volumeNormalise(ACTION_GET, &halCtls[index].ctl, valJ); - -OnErrorExit: - return NULL; -} - - -// Translate high level control to low level and call lower layer - -PUBLIC void halGetCtls(afb_req request) { - int index; - alsaHalMapT *halCtls = halSndCard->ctls; - json_object *ctlsInJ, *ctlsOutJ, *responseJ; - - // get query from request - ctlsInJ = afb_req_json(request); - ctlsOutJ = json_object_new_array(); - - switch (json_object_get_type(ctlsInJ)) { - case json_type_object: - { - - index = halGetCtlIndex(request, ctlsInJ); - if (index < 0) goto OnErrorExit; - json_object_array_add(ctlsOutJ, json_object_new_int(halCtls[index].ctl.numid)); - break; - } - - case json_type_array: - { - - for (int idx = 0; idx < json_object_array_length(ctlsInJ); idx++) { - json_object *ctlInJ = json_object_array_get_idx(ctlsInJ, idx); - index = halGetCtlIndex(request, ctlInJ); - if (index < 0) goto OnErrorExit; - json_object_array_add(ctlsOutJ, json_object_new_int(halCtls[index].ctl.numid)); - } - break; - } - - default: - afb_req_fail_f(request, "ctl-invalid", "Not a valid JSON ctl='%s'", json_object_get_string(ctlsInJ)); - goto OnErrorExit; - } - - // Call now level CTL - responseJ = halCallAlsaGetCtls(ctlsOutJ); - if (!responseJ) { - afb_req_fail_f(request, "subcall:alsacore/getctl", "%s", json_object_get_string(responseJ)); - goto OnErrorExit; - } - - // map back low level response to HAL ctl with normalised values - json_object *halResponse = HalGetPrepareResponse(request, responseJ); - if (!halResponse) goto OnErrorExit; - - afb_req_success(request, halResponse, NULL); - return; - -OnErrorExit: - return; -}; - -STATIC int UpdateOneSndCtl(alsaHalCtlMapT *ctl, json_object *sndCtlJ) { - json_object *tmpJ, *ctlJ; - - json_object_object_get_ex(sndCtlJ, "name", &tmpJ); - ctl->name = (char*) json_object_get_string(tmpJ); - - json_object_object_get_ex(sndCtlJ, "id", &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); - - json_object_object_get_ex(ctlJ, "max", &tmpJ); - ctl->maxval = json_object_get_int(tmpJ); - - json_object_object_get_ex(ctlJ, "step", &tmpJ); - ctl->step = json_object_get_int(tmpJ); - - json_object_object_get_ex(ctlJ, "count", &tmpJ); - ctl->count = json_object_get_int(tmpJ); - - 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)) { - 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 - -PUBLIC int halServiceInit(const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard) { - int err; - json_object *queryurl, *responseJ, *devidJ, *ctlsJ, *tmpJ; - alsaHalMapT *halCtls = alsaHalSndCard->ctls; - - // if not volume normalisation CB provided use default one - if (!alsaHalSndCard->volumeCB) alsaHalSndCard->volumeCB = volumeNormalise; - halSndCard = alsaHalSndCard; - - err = afb_daemon_require_api("alsacore", 1); - if (err) { - AFB_ERROR("AlsaCore missing cannot use AlsaHAL"); - goto OnErrorExit; - } - - // register HAL with Alsa Low Level Binder - queryurl = json_object_new_object(); - json_object_object_add(queryurl, "prefix", json_object_new_string(apiPrefix)); - json_object_object_add(queryurl, "sndname", json_object_new_string(alsaHalSndCard->name)); - - err = afb_service_call_sync("alsacore", "halregister", queryurl, &responseJ); - json_object_put(queryurl); - if (err) { - AFB_NOTICE("Fail to register HAL to ALSA lowlevel binding Response='%s'", json_object_get_string(responseJ)); - goto OnErrorExit; - } - - // extract sound devidJ from HAL registration - if (!json_object_object_get_ex(responseJ, "response", &tmpJ) || !json_object_object_get_ex(tmpJ, "devid", &devidJ)) { - AFB_ERROR("Ooops: Internal error no devidJ return from HAL registration Response='%s'", json_object_get_string(responseJ)); - goto OnErrorExit; - } - - // save devid for future use - halSndCard->devid = strdup(json_object_get_string(devidJ)); - - // for each Non Alsa Control callback create a custom control - ctlsJ = json_object_new_array(); - for (int idx = 0; (halCtls[idx].ctl.name || halCtls[idx].ctl.numid); idx++) { - json_object *ctlJ; - - // Try to find best equivalent label for tag - if (halCtls[idx].tag >StartHalCrlTag && halCtls[idx].tag < EndHalCrlTag && halCtlsLabels[halCtls[idx].tag] != NULL) { - halCtls[idx].label = halCtlsLabels[halCtls[idx].tag]; - } else { - if (halCtls[idx].ctl.name) halCtls[idx].label=halCtls[idx].ctl.name; - else if (halCtls[idx].info) halCtls[idx].label=halCtls[idx].info; - else halCtls[idx].label="NoHalCttNameSet"; - } - - ctlJ = json_object_new_object(); - if (halCtls[idx].ctl.numid) json_object_object_add(ctlJ, "ctl", json_object_new_int(halCtls[idx].ctl.numid)); - if (halCtls[idx].ctl.name) json_object_object_add(ctlJ, "name", json_object_new_string(halCtls[idx].ctl.name)); - if (halCtls[idx].ctl.minval) json_object_object_add(ctlJ, "min", json_object_new_int(halCtls[idx].ctl.minval)); - if (halCtls[idx].ctl.maxval) json_object_object_add(ctlJ, "max", json_object_new_int(halCtls[idx].ctl.maxval)); - if (halCtls[idx].ctl.step) json_object_object_add(ctlJ, "step", json_object_new_int(halCtls[idx].ctl.step)); - if (halCtls[idx].ctl.type) json_object_object_add(ctlJ, "type", json_object_new_int(halCtls[idx].ctl.type)); - if (halCtls[idx].ctl.count) json_object_object_add(ctlJ, "count", json_object_new_int(halCtls[idx].ctl.count)); - if (halCtls[idx].ctl.value) json_object_object_add(ctlJ, "val", json_object_new_int(halCtls[idx].ctl.value)); - - if (halCtls[idx].ctl.dbscale) { - json_object *dbscaleJ = json_object_new_object(); - if (halCtls[idx].ctl.dbscale->max) json_object_object_add(dbscaleJ, "max", json_object_new_int(halCtls[idx].ctl.dbscale->max)); - if (halCtls[idx].ctl.dbscale->min) json_object_object_add(dbscaleJ, "min", json_object_new_int(halCtls[idx].ctl.dbscale->min)); - if (halCtls[idx].ctl.dbscale->step) json_object_object_add(dbscaleJ, "step", json_object_new_int(halCtls[idx].ctl.dbscale->step)); - if (halCtls[idx].ctl.dbscale->mute) json_object_object_add(dbscaleJ, "mute", json_object_new_int(halCtls[idx].ctl.dbscale->mute)); - json_object_object_add(ctlJ, "dbscale", dbscaleJ); - } - - if (halCtls[idx].ctl.enums) { - json_object *enumsJ = json_object_new_array(); - for (int jdx = 0; halCtls[idx].ctl.enums[jdx]; jdx++) { - json_object_array_add(enumsJ, json_object_new_string(halCtls[idx].ctl.enums[jdx])); - } - json_object_object_add(ctlJ, "enums", enumsJ); - } - json_object_array_add(ctlsJ, ctlJ); - } - - // Build new queryJ to add HAL custom control if any - if (json_object_array_length(ctlsJ) > 0) { - 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, "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)); - goto OnErrorExit; - } - } - - // Make sure response is valid - json_object_object_get_ex(responseJ, "response", &ctlsJ); - if (json_object_get_type(ctlsJ) != json_type_array) { - AFB_ERROR("Response Invalid JSON array ctls Response='%s'", json_object_get_string(responseJ)); - goto OnErrorExit; - } - - // update HAL data from JSON response - for (int idx = 0; idx < json_object_array_length(ctlsJ); idx++) { - json_object *ctlJ = json_object_array_get_idx(ctlsJ, idx); - err = UpdateOneSndCtl(&halCtls[idx].ctl, ctlJ); - if (err) { - AFB_ERROR("Fail found MAP Alsa Low level=%s", json_object_get_string(ctlJ)); - goto OnErrorExit; - } - } - - - // finally register for alsa lowlevel event - queryurl = json_object_new_object(); - json_object_object_add(queryurl, "devid", devidJ); - err = afb_service_call_sync("alsacore", "subscribe", queryurl, &responseJ); - if (err) { - AFB_ERROR("Fail subscribing to ALSA lowlevel events"); - goto OnErrorExit; - } - - return (0); - -OnErrorExit: - return (1); -}; - - -// This receive all event this binding subscribe to - -PUBLIC void halServiceEvent(const char *evtname, json_object *eventJ) { - int numid; - alsaHalMapT *halCtls = halSndCard->ctls; - json_object *numidJ, *valuesJ; - - AFB_DEBUG("halServiceEvent evtname=%s [msg=%s]", evtname, json_object_get_string(eventJ)); - - json_object_object_get_ex(eventJ, "id", &numidJ); - numid = json_object_get_int(numidJ); - if (!numid) { - AFB_ERROR("halServiceEvent noid: evtname=%s [msg=%s]", evtname, json_object_get_string(eventJ)); - return; - } - json_object_object_get_ex(eventJ, "val", &valuesJ); - - // search it corresponding numid in halCtls attach a callback - if (numid) { - for (int idx = 0; halCtls[idx].ctl.numid; idx++) { - if (halCtls[idx].ctl.numid == numid && halCtls[idx].cb.callback != NULL) { - halCtls[idx].cb.callback(halCtls[idx].tag, &halCtls[idx].ctl, halCtls[idx].cb.handle, valuesJ); - } - } - } -} - -// 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, .info = "ping test for API"}, - { .verb = "ctllist", .callback = halListCtls, .info = "List AGL normalised Sound Controls"}, - { .verb = "ctlget", .callback = halGetCtls, .info = "Get one/many sound controls"}, - { .verb = "ctlset", .callback = halSetCtls, .info = "Set one/many sound controls"}, - { .verb = "evtsub", .callback = halSubscribe, .info = "Subscribe to HAL events"}, - { .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 deleted file mode 100644 index c210f02..0000000 --- a/HAL-afb/HAL-interface/hal-interface.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * AlsaLibMapping -- provide low level interface with AUDIO 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. - */ - -#ifndef SHAREHALLIB_H -#define SHAREHALLIB_H - -#include <stdio.h> -#include <alsa/asoundlib.h> - -#include "audio-common.h" -#include <systemd/sd-event.h> - -typedef enum { - ACTION_SET, - ACTION_GET -} ActionSetGetT; - -// VolRamp Handle Store current status for a given VolRam CB set - -typedef struct { - halRampEnumT mode; - halCtlsTagT slave; - int delay; // delay between volset in us - int stepDown; // linear % - int stepUp; // linear % - int current; // current volume for slave ctl - int target; // target volume - sd_event_source *evtsrc; // event loop timer source -} halVolRampT; - -typedef struct { - int min; - int max; - int step; - int mute; -} alsaHalDBscaleT; - -typedef struct { - char* name; - int numid; - snd_ctl_elem_type_t type; - int count; - int minval; - int maxval; - int value; - int step; - const char **enums; - alsaHalDBscaleT *dbscale; -} alsaHalCtlMapT; - - -// avoid compiler warning [Jose does not like typedef :) ] -typedef struct afb_service alsaHalServiceT; - -typedef struct { - void (*callback)(halCtlsTagT tag, alsaHalCtlMapT *control, void* handle, json_object *valuesJ); - void* handle; -} alsaHalCbMapT; - -typedef struct { - halCtlsTagT tag; - const char *label; - alsaHalCtlMapT ctl; - alsaHalCbMapT cb; - char* info; -} alsaHalMapT; - -typedef struct { - const char *name; - const char *info; - alsaHalMapT *ctls; - const char *devid; - json_object* (*volumeCB)(ActionSetGetT action, const alsaHalCtlMapT *halCtls, json_object *valuesJ); -} alsaHalSndCardT; - -// hal-interface.c -extern afb_verb_v2 halServiceApi[]; -PUBLIC void halServiceEvent(const char *evtname, json_object *object); -PUBLIC int halServiceInit(const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard); -PUBLIC json_object *halGetCtlByTag(halRampEnumT tag); -PUBLIC int halSetCtlByTag(halRampEnumT tag, int value); - - -// hal-volramp.c -PUBLIC void volumeRamp(halCtlsTagT halTag, alsaHalCtlMapT *control, void* handle, json_object *valJ); - -// hal-volume.c -PUBLIC json_object *volumeNormalise(ActionSetGetT action, const alsaHalCtlMapT *halCtls, json_object *valuesJ); - - -#endif /* SHAREHALLIB_H */ - diff --git a/HAL-afb/HAL-interface/hal-volramp.c b/HAL-afb/HAL-interface/hal-volramp.c deleted file mode 100644 index 60e91d6..0000000 --- a/HAL-afb/HAL-interface/hal-volramp.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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. - * - */ - -#define _GNU_SOURCE // needed for vasprintf -#include "hal-interface.h" - -STATIC int RampTimerCB(sd_event_source* source, uint64_t timer, void* handle) { - halVolRampT *volRamp = (halVolRampT*) handle; - int err; - uint64_t usec; - - // RampDown - if (volRamp->current > volRamp->target) { - volRamp->current = volRamp->current - volRamp->stepDown; - if (volRamp->current < volRamp->target) volRamp->current = volRamp->target; - } - - // RampUp - if (volRamp->current < volRamp->target) { - volRamp->current = volRamp->current + volRamp->stepUp; - if (volRamp->current > volRamp->target) volRamp->current = volRamp->target; - } - - // request current Volume Level - err = halSetCtlByTag(volRamp->slave, volRamp->current); - if (err) goto OnErrorExit; - - // we reach target stop volram event - if (volRamp->current == volRamp->target) sd_event_source_unref(source); - else { - // otherwise validate timer for a new run - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); - err = sd_event_source_set_time(source, usec + volRamp->delay); - } - - return 0; - -OnErrorExit: - AFB_WARNING("RampTimerCB Fail to set HAL ctl tag=%d vol=%d", Master_Playback_Volume, volRamp->current); - sd_event_source_unref(source); // abandon VolRamp - return -1; -} - -STATIC void SetRampTimer(void *handle) { - halVolRampT *volRamp = (halVolRampT*) handle; - uint64_t usec; - - // set a timer with ~250us accuracy - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_add_time(afb_daemon_get_event_loop(), &volRamp->evtsrc, CLOCK_MONOTONIC, usec, 250, RampTimerCB, volRamp); -} - -STATIC int volumeDoRamp(halVolRampT *volRamp, int numid, json_object *volumeJ) { - json_object *responseJ; - - // request current Volume Level - responseJ = halGetCtlByTag(volRamp->slave); - if (!responseJ) { - AFB_WARNING("volumeDoRamp Fail to get HAL ctl tag=%d", Master_Playback_Volume); - goto OnErrorExit; - } - - // use 1st volume value as target for ramping - switch (json_object_get_type(volumeJ)) { - case json_type_array: - volRamp->target = json_object_get_int(json_object_array_get_idx(volumeJ, 0)); - break; - - case json_type_int: - volRamp->target = json_object_get_int(volumeJ); - break; - - default: - AFB_WARNING("volumeDoRamp Invalid volumeJ=%s", json_object_get_string(volumeJ)); - goto OnErrorExit; - } - - // use 1st volume value as current for ramping - switch (json_object_get_type(responseJ)) { - case json_type_array: - volRamp->current = json_object_get_int(json_object_array_get_idx(responseJ, 0)); - break; - - case json_type_int: - volRamp->current = json_object_get_int(responseJ); - break; - - default: - AFB_WARNING("volumeDoRamp Invalid reponseJ=%s", json_object_get_string(responseJ)); - goto OnErrorExit; - } - - SetRampTimer(volRamp); - - return 0; - -OnErrorExit: - return -1; -} - -PUBLIC void volumeRamp(halCtlsTagT halTag, alsaHalCtlMapT *ctl, void* handle, json_object *valJ) { - halVolRampT *volRamp = (halVolRampT*) handle; - json_object *tmpJ; - - if (json_object_get_type(valJ) != json_type_array || volRamp == NULL) goto OnErrorExit; - - switch (halTag) { - - // Only config use wellknown tag. Default is DoVolRamp - default: - tmpJ = json_object_array_get_idx(valJ, 0); - volumeDoRamp(volRamp, ctl->numid, tmpJ); - break; - - case Vol_Ramp_Set_Mode: - tmpJ = json_object_array_get_idx(valJ, 0); - volRamp->mode = json_object_get_int(tmpJ); - switch (volRamp->mode) { - - case RAMP_VOL_SMOOTH: - volRamp->delay = 100 * 1000; - volRamp->stepDown = 1; - volRamp->stepUp = 1; - break; - - case RAMP_VOL_NORMAL: - volRamp->delay = 100 * 1000; - volRamp->stepDown = 3; - volRamp->stepUp = 2; - break; - - case RAMP_VOL_EMERGENCY: - volRamp->delay = 50 * 1000; - volRamp->stepDown = 6; - volRamp->stepUp = 2; - break; - - default: - goto OnErrorExit; - } - break; - - case Vol_Ramp_Set_Slave: - tmpJ = json_object_array_get_idx(valJ, 0); - volRamp->slave = json_object_get_int(tmpJ); - break; - - case Vol_Ramp_Set_Delay: - tmpJ = json_object_array_get_idx(valJ, 0); - volRamp->delay = 1000 * json_object_get_int(tmpJ); - break; - - case Vol_Ramp_Set_Down: - tmpJ = json_object_array_get_idx(valJ, 0); - volRamp->stepDown = json_object_get_int(tmpJ); - break; - - case Vol_Ramp_Set_Up: - tmpJ = json_object_array_get_idx(valJ, 0); - volRamp->stepUp = json_object_get_int(tmpJ); - break; - } - - return; - -OnErrorExit: - AFB_WARNING("volumeRamp: Invalid Ctrl Event halCtlsTagT=%d numid=%d name=%s value=%s", halTag, ctl->numid, ctl->name, json_object_get_string(valJ)); - return; -} diff --git a/HAL-afb/HAL-interface/hal-volume.c b/HAL-afb/HAL-interface/hal-volume.c deleted file mode 100644 index 997ce98..0000000 --- a/HAL-afb/HAL-interface/hal-volume.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 - * snd_tlv_convert_from_dB - * nt snd_tlv_convert_to_dB - * snd_tlv_get_dB_range - */ - -#define _GNU_SOURCE // needed for vasprintf -#include <math.h> -#include "hal-interface.h" - -typedef enum { - NORMALIZE_NONE = 0, - NORMALIZE_DB_LINEAR, - NORMALIZE_DB_MATH, - NORMALIZE_LINEAR, -} 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 NORMALIZE_DB_LINEAR: - normalized = ((double) (value - dbscale->min) / (double) (dbscale->max - dbscale->min)); - break; - - case NORMALIZE_DB_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) / 20); - normalized = (normalized - min_norm) / (1 - min_norm); - } - - break; - - default: - normalized = 0; - } - - return (int) round(normalized * 100); -} - -// HAL normalise volume values to 0-100% - -PUBLIC json_object *volumeNormalise(ActionSetGetT action, const alsaHalCtlMapT *halCtls, json_object *valuesJ) { - enumRandeModeDB_T useNormalizeDB; - int length; - - // If Integer look for DBscale - if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) { - - // 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 = NORMALIZE_LINEAR; - - } else { // db_scale looks OK let's use it - if ((halCtls->dbscale->max - halCtls->dbscale->min) <= MAX_LINEAR_DB_SCALE * 100) useNormalizeDB = NORMALIZE_DB_LINEAR; - else useNormalizeDB = NORMALIZE_LINEAR; // Fulup not sure how to handle this useNormalizeDB=NORMALIZE_DB_MATH; - } - } else useNormalizeDB = NORMALIZE_NONE; - - - // loop on values to normalise - enum json_type jtype = json_object_get_type(valuesJ); - if (jtype == json_type_array) length = json_object_array_length(valuesJ); - else length = 1; - - json_object *normalisedJ = json_object_new_array(); - for (int idx = 0; idx < length; idx++) { - int value; - - if (jtype == json_type_array) { - json_object *valueJ = json_object_array_get_idx(valuesJ, idx); - value = json_object_get_int(valueJ); - } else { - value = json_object_get_int(valuesJ); - } - - // If Integer scale to 0/100 - if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) { - - switch (action) { - - case ACTION_GET: - switch (useNormalizeDB) { - case NORMALIZE_LINEAR: - value = 100 * (value - halCtls->minval) / (halCtls->maxval - halCtls->minval); - break; - case NORMALIZE_DB_MATH: //ToBeDone - value = dbNormalizeVal(useNormalizeDB, halCtls->dbscale, value); - break; - case NORMALIZE_NONE: - default: - value = value; - } - break; - - case ACTION_SET: - switch (useNormalizeDB) { - case NORMALIZE_LINEAR: - value = (value * (halCtls->maxval - halCtls->minval)) / 100; - break; - case NORMALIZE_DB_MATH: //ToBeDone - value = dbNormalizeVal(useNormalizeDB, halCtls->dbscale, value); - break; - case NORMALIZE_NONE: - default: - value = value; - } - break; - - default: - AFB_NOTICE("volumeNormalise: invalid action value=%d", (int) action); - goto ExitOnError; - } - } - - json_object_array_add(normalisedJ, json_object_new_int(value)); - } - - return (normalisedJ); - -ExitOnError: - return NULL; -} |