From 94a12b24d1712573607b78cd78f47e998a0323d4 Mon Sep 17 00:00:00 2001 From: fulup Date: Sun, 30 Jul 2017 21:11:00 +0200 Subject: First Dev version with Volume Ramping --- ALSA-afb/Alsa-AddCtl.c | 138 ++++++-- ALSA-afb/Alsa-RegEvt.c | 47 +-- ALSA-afb/Alsa-SetGet.c | 31 +- HAL-afb/HAL-interface/CMakeLists.txt | 2 +- HAL-afb/HAL-interface/hal-interface.c | 325 +++++++++++++------ HAL-afb/HAL-interface/hal-interface.h | 47 ++- HAL-afb/HAL-interface/hal-volmap.c | 147 --------- HAL-afb/HAL-interface/hal-volramp.c | 166 ++++++++++ HAL-afb/HAL-interface/hal-volume.c | 150 +++++++++ HAL-afb/HAL-plugin/HalPlugCtl.c | 2 +- HAL-afb/HDA-intel/IntelHdaHAL.c | 33 +- HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c | 45 ++- HAL-afb/Unicens-USB/UnicensHAL.c | 15 +- HAL-afb/Unicens-USB/UnicensVol.c | 4 +- Shared-Interface/audio-interface.h | 35 +- conf.d/app-templates | 2 +- conf.d/cmake/config.cmake | 2 +- htdocs/CMakeLists.txt | 4 +- htdocs/alsa-core.html | 14 +- nbproject/configurations.xml | 486 ++++++++-------------------- nbproject/project.xml | 8 +- 21 files changed, 959 insertions(+), 744 deletions(-) delete mode 100644 HAL-afb/HAL-interface/hal-volmap.c create mode 100644 HAL-afb/HAL-interface/hal-volramp.c create mode 100644 HAL-afb/HAL-interface/hal-volume.c 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 diff --git a/HAL-afb/HAL-interface/CMakeLists.txt b/HAL-afb/HAL-interface/CMakeLists.txt index c367c5c..d20a283 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-volmap.c hal-interface.c) + 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) diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c index f4fc8df..76cdbd8 100644 --- a/HAL-afb/HAL-interface/hal-interface.c +++ b/HAL-afb/HAL-interface/hal-interface.c @@ -21,24 +21,37 @@ #define _GNU_SOURCE // needed for vasprintf #include #include "hal-interface.h" +#include -static alsaHalMapT *halCtls; -static const char *halDevid; - - +alsaHalSndCardT *halSndCard; STATIC const char *halCtlsLabels[] = { - [StartHalCrlTag] = "NOT_USED", - [Master_Playback_Volume] = "Master_Playback_Volume", - [Master_OnOff_Switch] = "Master_OnOff_Switch", - [Master_Playback_Ramp] = "Master_Playback_Ramp", - [PCM_Playback_Volume] = "PCM_Playback_Volume", - [PCM_Playback_Switch] = "PCM_Playback_Switch", - [Capture_Volume] = "Capture_Volume", - - [EndHalCrlTag] = "NOT_USED" - + [Master_Playback_Volume] = "Master_Playback_Volume", + [Master_OnOff_Switch] = "Master_OnOff_Switch", + [Master_Playback_Ramp]= "Master_Playback_Ramp", + [PCM_Playback_Volume] = "PCM_Playback_Volume", + [PCM_Playback_Switch] = "PCM_Playback_Switch", + [Capture_Volume] = "Capture_Volume", + + [Vol_Ramp] = "Volume_Ramp", + [Vol_Ramp_Set_Mode] = "Volume_Ramp_Mode", + [Vol_Ramp_Set_Delay] = "Volume_Ramp_Delay", + [Vol_Ramp_Set_Down] = "Volume_Ramp_Down", + [Vol_Ramp_Set_Up] = "Volume_Ramp_Up", + + [EndHalCrlTag] = NULL +}; + +PUBLIC char *halVolRampModes[] = { + + [RAMP_VOL_NONE] = "None", + [RAMP_VOL_NORMAL] = "Normal", + [RAMP_VOL_SMOOTH] = "Smooth", + [RAMP_VOL_EMERGENCY] = "Emergency", + + [EndHalVolMod] = NULL, + }; // Force specific HAL to depend on ShareHalLib @@ -54,6 +67,7 @@ STATIC void halSubscribe(afb_req request) { // 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 (!strcmp (halCtls[idx].label, label)) return idx; @@ -64,6 +78,7 @@ STATIC int halCtlStringToIndex (const char* label) { } STATIC int halCtlTagToIndex (halCtlsEnumT tag) { + alsaHalMapT *halCtls= halSndCard->ctls; for (int idx = 0; halCtls[idx].tag != EndHalCrlTag; idx++) { if (halCtls[idx].tag == tag) return idx; @@ -76,10 +91,11 @@ STATIC int halCtlTagToIndex (halCtlsEnumT tag) { // Return ALL HAL snd controls PUBLIC void halListCtls(afb_req request) { - struct json_object *ctlsHalJ = json_object_new_array(); + alsaHalMapT *halCtls= halSndCard->ctls; + json_object *ctlsHalJ = json_object_new_array(); for (int idx = 0; halCtls[idx].ctl.numid; idx++) { - struct json_object *ctlHalJ = json_object_new_object(); + json_object *ctlHalJ = json_object_new_object(); json_object_object_add(ctlHalJ, "label", json_object_new_string(halCtls[idx].label)); json_object_object_add(ctlHalJ, "tag" , json_object_new_int(halCtls[idx].tag)); @@ -91,8 +107,8 @@ PUBLIC void halListCtls(afb_req request) { afb_req_success (request, ctlsHalJ, NULL); } -STATIC int halGetCtlIndex (afb_req request, struct json_object*ctlInJ) { - struct json_object *tmpJ; +STATIC int halGetCtlIndex (afb_req request, json_object*ctlInJ) { + json_object *tmpJ; int tag, index, done; // check 1st short command mode [tag1, tag2, ...] @@ -127,7 +143,6 @@ STATIC int halGetCtlIndex (afb_req request, struct json_object*ctlInJ) { goto OnErrorExit; } - if (index < 0) goto OnErrorExit; // return corresponding lowlevel numid to querylist @@ -139,10 +154,48 @@ STATIC int halGetCtlIndex (afb_req request, struct json_object*ctlInJ) { } +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", "setctl", 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; - struct json_object *ctlsInJ, *ctlsOutJ, *queryJ, *valuesJ, *responseJ; + json_object *ctlsInJ, *ctlsOutJ, *valuesJ; // get query from request ctlsInJ = afb_req_json(request); @@ -162,7 +215,7 @@ PUBLIC void halSetCtls(afb_req request) { } json_object_object_add (ctlsOutJ, "id", json_object_new_int(halCtls[index].ctl.numid)); - json_object_object_add (ctlsOutJ,"val", SetGetNormaliseVolumes (ACTION_SET, &halCtls[index].ctl, valuesJ)); + json_object_object_add (ctlsOutJ,"val", volumeNormalise (ACTION_SET, &halCtls[index].ctl, valuesJ)); break; } @@ -170,7 +223,7 @@ PUBLIC void halSetCtls(afb_req request) { ctlsOutJ = json_object_new_array(); for (int idx= 0; idx < json_object_array_length (ctlsInJ); idx++) { - struct json_object *ctlInJ = json_object_array_get_idx (ctlsInJ, idx); + json_object *ctlInJ = json_object_array_get_idx (ctlsInJ, idx); index= halGetCtlIndex (request, ctlInJ); if (index < 0) goto OnErrorExit; @@ -180,9 +233,9 @@ PUBLIC void halSetCtls(afb_req request) { goto OnErrorExit; } // let's create alsa low level set control request - struct json_object *ctlOutJ = json_object_new_object(); + 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", SetGetNormaliseVolumes (ACTION_SET, &halCtls[index].ctl, valuesJ)); + json_object_object_add (ctlOutJ, "val", volumeNormalise (ACTION_SET, &halCtls[index].ctl, valuesJ)); json_object_array_add (ctlsOutJ, ctlOutJ); } @@ -194,14 +247,9 @@ PUBLIC void halSetCtls(afb_req request) { goto OnErrorExit; } - // 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, "numid", ctlsOutJ); - - err= afb_service_call_sync("alsacore", "setctl", queryJ, &responseJ); + err = halCallAlsaSetCtls (ctlsOutJ); if (err) { - afb_req_fail_f(request, "subcall:alsacore/setctl", "%s", json_object_get_string(responseJ)); + afb_req_fail_f(request, "subcall:alsacore/setctl", "%s", json_object_get_string(ctlsOutJ)); goto OnErrorExit; } @@ -213,24 +261,35 @@ OnErrorExit: }; // Remap low level controls into HAL hight level ones -STATIC json_object *HalGetPrepareResponse(afb_req request, struct json_object *ctlsJ) { - struct json_object *halResponseJ; - - // make sure return controls have a valid type - if (json_object_get_type(ctlsJ) != json_type_array) { - afb_req_fail_f(request, "ctls-notarray", "Invalid Controls return from alsa/getcontrol ctlsJ=%s", json_object_get_string(ctlsJ)); - goto OnErrorExit; +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; } - // responseJ is a JSON array - halResponseJ = json_object_new_array(); - // loop on array and store values into client context - for (int idx = 0; idx < json_object_array_length(ctlsJ); idx++) { - struct json_object *sndCtlJ, *valJ, *numidJ; + for (int idx = 0; idx < length; idx++) { + json_object *sndCtlJ, *valJ, *numidJ; int numid; - sndCtlJ = json_object_array_get_idx(ctlsJ, idx); + // 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; @@ -240,14 +299,16 @@ STATIC json_object *HalGetPrepareResponse(afb_req request, struct json_object *c numid= (halCtlsEnumT) json_object_get_int(numidJ); for (int idx = 0; halCtls[idx].ctl.numid; idx++) { - if (halCtls[idx].ctl.numid == numid) { - + if (halCtls[idx].ctl.numid == numid) { // translate low level numid to HAL one and normalise values - struct json_object *halCtlJ = json_object_new_object(); + 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" , SetGetNormaliseVolumes(ACTION_GET, &halCtls[idx].ctl, valJ)); - json_object_array_add(halResponseJ, halCtlJ); + 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; } } @@ -262,10 +323,55 @@ STATIC json_object *HalGetPrepareResponse(afb_req request, struct json_object *c 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", "getctl", 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 err, index; - struct json_object *ctlsInJ, *ctlsOutJ, *queryJ, *responseJ; + int index; + alsaHalMapT *halCtls= halSndCard->ctls; + json_object *ctlsInJ, *ctlsOutJ, *responseJ; // get query from request ctlsInJ = afb_req_json(request); @@ -283,7 +389,7 @@ PUBLIC void halGetCtls(afb_req request) { case json_type_array: { for (int idx= 0; idx < json_object_array_length (ctlsInJ); idx++) { - struct json_object *ctlInJ = json_object_array_get_idx (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)); @@ -297,21 +403,14 @@ 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, "numid", ctlsOutJ); - - err= afb_service_call_sync("alsacore", "getctl", queryJ, &responseJ); - if (err) { + responseJ = halCallAlsaGetCtls (ctlsOutJ); + if (!responseJ) { afb_req_fail_f(request, "subcall:alsacore/getctl", "%s", json_object_get_string(responseJ)); goto OnErrorExit; } - // Let ignore info data if any and keep on response - json_object_object_get_ex (responseJ, "response", &responseJ); - // map back low level response to HAL ctl with normalised values - struct json_object *halResponse = HalGetPrepareResponse(request, responseJ); + json_object *halResponse = HalGetPrepareResponse(request, responseJ); if (!halResponse) goto OnErrorExit; afb_req_success (request, halResponse, NULL); @@ -321,35 +420,9 @@ OnErrorExit: return; }; -// This receive all event this binding subscribe to -PUBLIC void halServiceEvent(const char *evtname, struct json_object *eventJ) { - int numid; - struct json_object *numidJ, *valuesJ, *valJ; - - AFB_NOTICE("halServiceEvent evtname=%s [msg=%s]", evtname, json_object_get_string(eventJ)); - - json_object_object_get_ex (eventJ, "val" , &valuesJ); - if (!valuesJ) { - AFB_ERROR("halServiceEvent novalues: evtname=%s [msg=%s]", evtname, json_object_get_string(eventJ)); - return; - } - - json_object_object_get_ex (valuesJ, "numid" , &numidJ); - numid = json_object_get_int (numidJ); - - // 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) { - json_object_object_get_ex (valuesJ, "val" , &valJ); - halCtls[idx].cb.callback (&halCtls[idx].ctl, halCtls[idx].cb.handle, valJ); - } - } - } -} -STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) { - struct json_object *tmpJ, *ctlJ; +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); @@ -377,7 +450,7 @@ STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) { // process dbscale TLV if any if (json_object_object_get_ex (sndCtlJ, "tlv" , &tmpJ)) { - struct json_object *dbscaleJ; + 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); @@ -407,8 +480,12 @@ STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) { // this is call when after all bindings are loaded PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard) { int err; - struct json_object *queryurl, *responseJ, *devidJ, *ctlsJ, *tmpJ; - halCtls = alsaHalSndCard->ctls; // Get sndcard specific HAL control mapping + 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) { @@ -435,12 +512,12 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar } // save devid for future use - halDevid = strdup (json_object_get_string(devidJ)); + 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++) { - struct json_object *ctlJ; + json_object *ctlJ; // map HAL ctlTad with halCrlLabel to simplify set/get ctl operations using Labels halCtls[idx].label = halCtlsLabels[halCtls[idx].tag]; @@ -452,10 +529,29 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar 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, "value", 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); } else { ctlJ = json_object_new_object(); - if (halCtls[idx].ctl.numid) json_object_object_add(ctlJ, "numid" , json_object_new_int(halCtls[idx].ctl.numid)); + 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)); json_object_array_add(ctlsJ, ctlJ); } @@ -508,13 +604,40 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar 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}, - { .verb = "ctl-list", .callback = halListCtls}, - { .verb = "ctl-get", .callback = halGetCtls}, - { .verb = "ctl-set", .callback = halSetCtls}, - { .verb = "evt-sub", .callback = halSubscribe}, + { .verb = "ping", .callback = pingtest , .info="ping test for API"}, + { .verb = "ctl-list", .callback = halListCtls , .info="List AGL normalised Sound Controls"}, + { .verb = "ctl-get", .callback = halGetCtls , .info="Get one/many sound controls"}, + { .verb = "ctl-set", .callback = halSetCtls , .info="Set one/many sound controls"}, + { .verb = "evt-sub", .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 index c31c145..23944ad 100644 --- a/HAL-afb/HAL-interface/hal-interface.h +++ b/HAL-afb/HAL-interface/hal-interface.h @@ -22,12 +22,26 @@ #include #include "audio-interface.h" +#include + typedef enum { - ACTION_SET, - ACTION_GET + ACTION_SET, + ACTION_GET } ActionSetGetT; +// VolRamp Handle Store current status for a given VolRam CB set +typedef struct { + halRampEnumT mode; + halCtlsEnumT 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; @@ -42,7 +56,9 @@ typedef struct { int count; int minval; int maxval; + int value; int step; + char **enums; alsaHalDBscaleT *dbscale; } alsaHalCtlMapT; @@ -50,8 +66,8 @@ typedef struct { typedef struct afb_service alsaHalServiceT; typedef struct { - struct json_object* (*callback)(alsaHalCtlMapT *control, void* handle, struct json_object *valuesJ); - void* handle; + void (*callback)(halCtlsEnumT tag, alsaHalCtlMapT *control, void* handle, json_object *valuesJ); + void* handle; } alsaHalCbMapT; typedef struct { @@ -62,19 +78,28 @@ typedef struct { char* info; } alsaHalMapT; - -typedef const struct { - char *name; +typedef struct { + const char *name; const char *info; - alsaHalMapT *ctls; + 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, struct json_object *object); +extern char *halVolRampModes[]; +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 (halCtlsEnumT halTag,alsaHalCtlMapT *control, void* handle, json_object *valJ); -// hal-volmap.c -PUBLIC struct json_object *SetGetNormaliseVolumes(ActionSetGetT action, const alsaHalCtlMapT *halCtls, struct json_object *valuesJ); +// 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-volmap.c b/HAL-afb/HAL-interface/hal-volmap.c deleted file mode 100644 index 2b619fd..0000000 --- a/HAL-afb/HAL-interface/hal-volmap.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll - * - * 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 -#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 struct json_object *SetGetNormaliseVolumes(ActionSetGetT action, const alsaHalCtlMapT *halCtls, struct 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 ("SetGetNormaliseVolumes: invalid action value=%d", (int)action); - goto ExitOnError; - } - } - - 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-interface/hal-volramp.c b/HAL-afb/HAL-interface/hal-volramp.c new file mode 100644 index 0000000..6343a06 --- /dev/null +++ b/HAL-afb/HAL-interface/hal-volramp.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * 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; +} + +/* UCS2 Interface Timer Callback */ +STATIC void SetRampTimer(void *handle) { + halVolRampT *volRamp= (halVolRampT*)handle; + + uint64_t usec; + /* set a timer with 250ms 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 (halCtlsEnumT 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) { + case Vol_Ramp: + 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); + 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; + + default: + goto OnErrorExit; + } + + return; + + OnErrorExit: + AFB_WARNING ("Invalid Ctrl Event halCtlsEnumT=%d numid=%d name=%s value=%s", halTag, ctl->numid, ctl->name, json_object_get_string(valJ)); + return; +} + \ No newline at end of file diff --git a/HAL-afb/HAL-interface/hal-volume.c b/HAL-afb/HAL-interface/hal-volume.c new file mode 100644 index 0000000..593b74c --- /dev/null +++ b/HAL-afb/HAL-interface/hal-volume.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * 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 +#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; +} + \ No newline at end of file diff --git a/HAL-afb/HAL-plugin/HalPlugCtl.c b/HAL-afb/HAL-plugin/HalPlugCtl.c index 3755876..4f76595 100644 --- a/HAL-afb/HAL-plugin/HalPlugCtl.c +++ b/HAL-afb/HAL-plugin/HalPlugCtl.c @@ -321,7 +321,7 @@ SND_CTL_PLUGIN_DEFINE_FUNC(afbhal) { return -EINVAL; } - err=snd_config_search(ctlconfig, "numid", &itemConf); + err=snd_config_search(ctlconfig, "ctl", &itemConf); if (!err) { if (snd_config_get_integer(itemConf, (long*)&plughandle->ctls[plughandle->ctlsCount].ctlNumid) < 0) { SNDERR("Not Integer: ctl:%s numid should be a valid integer", ctlLabel); diff --git a/HAL-afb/HDA-intel/IntelHdaHAL.c b/HAL-afb/HDA-intel/IntelHdaHAL.c index 66f241f..f7aec59 100644 --- a/HAL-afb/HDA-intel/IntelHdaHAL.c +++ b/HAL-afb/HDA-intel/IntelHdaHAL.c @@ -25,26 +25,27 @@ #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { - struct json_object *reponseJ; - - AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); - - reponseJ=json_object_new_object(); - json_object_object_add (reponseJ, "Callback", json_object_new_string("Hello From HAL")); - - return reponseJ; -} + +// Default Values for MasterVolume Ramping +STATIC halVolRampT volRampMaster= { + .mode = RAMP_VOL_NORMAL, + .slave = Master_Playback_Volume, + .delay = 100*1000, // ramping delay in us + .stepDown=1, + .stepUp =1, +}; // Map HAL hight sndctl with Alsa numid and optionally with a custom callback for non Alsa supported functionalities. STATIC alsaHalMapT alsaHalMap[]= { - { .tag=Master_Playback_Volume, .ctl={.numid=04 } }, - { .tag=PCM_Playback_Volume , .ctl={.numid=06 } }, - { .tag=PCM_Playback_Switch , .ctl={.numid=05 } }, - { .tag=Capture_Volume , .ctl={.numid=12 } }, - { .tag=Master_OnOff_Switch , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_BOOLEAN, .count=1, .name="Power-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, - { .tag=Master_Playback_Ramp , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=2, .name="Volume-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, + { .tag=Master_Playback_Volume, . ctl={ .name="Master Playback Volume" } }, + { .tag=PCM_Playback_Volume , .ctl={ .name="PCM Playback Volume" } }, + { .tag=PCM_Playback_Switch , .ctl={ .name="Master Playback Switch" } }, + { .tag=Capture_Volume , .ctl={ .name="Capture Volume" } }, + { .tag=Vol_Ramp , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="ramp volume linearly according to current ramp setting", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=100, .step=1, .name="Hal-VolRamp"} + }, + { .tag=EndHalCrlTag} /* marker for end of the array */ } ; diff --git a/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c b/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c index 10ef204..dd4499e 100644 --- a/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c +++ b/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c @@ -26,25 +26,41 @@ #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { - struct json_object *reponseJ; - - AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); - - reponseJ=json_object_new_object(); - json_object_object_add (reponseJ, "Callback", json_object_new_string("Hello From HAL")); - - return reponseJ; -} +// Default Values for MasterVolume Ramping +STATIC halVolRampT volRampMaster= { + .mode = RAMP_VOL_NORMAL, + .slave = Master_Playback_Volume, + .delay = 100*1000, // ramping delay in us + .stepDown=1, + .stepUp =1, +}; // Map HAL hight sndctl with Alsa numid and optionally with a custom callback for non Alsa supported functionalities. STATIC alsaHalMapT alsaHalMap[]= { - { .tag=Master_Playback_Volume, . ctl={.numid=04 } }, - { .tag=PCM_Playback_Volume , .ctl={.numid=06 } }, + { .tag=Master_Playback_Volume, . ctl={.name="Master Playback Volume" } }, + { .tag=PCM_Playback_Volume , .ctl={.name="Master 1 (Monitor) Playback Volume" } }, { .tag=PCM_Playback_Switch , .ctl={.numid=05 } }, { .tag=Capture_Volume , .ctl={.numid=12 } }, - { .tag=Master_OnOff_Switch , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_BOOLEAN, .count=1, .name="AGL-Power-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, - { .tag=Master_Playback_Ramp , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=2, .name="AGL-Volume-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, + + { .tag=Vol_Ramp_Set_Mode , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="select volramp speed", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_ENUMERATED, .count=1, .value=RAMP_VOL_NORMAL, .name="Hal-VolRamp-Mode", .enums=halVolRampModes} + }, + { .tag=Vol_Ramp_Set_Slave , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="set slave volume master numid", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .value=Master_Playback_Volume, .name="Hal-VolRamp-Slave", .enums=halVolRampModes} + }, + { .tag=Vol_Ramp_Set_Delay , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="set ramp delay [default 250ms]", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=1000, .step=100, .value=250, .name="Hal-VolRamp-Step-Down"} + }, + { .tag=Vol_Ramp_Set_Down , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="set linear step down ramp [default 10]", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=100, .step=1, .value=10, .name="Hal-VolRamp-Step-Down"} + }, + { .tag=Vol_Ramp_Set_Up , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="set linear step up ramp [default 10]", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=100, .step=1, .value=10, .name="Hal-VolRamp-Step-Up"} + }, + { .tag=Vol_Ramp , .cb={.callback=volumeRamp, .handle=&volRampMaster}, .info="ramp volume linearly according to current ramp setting", + .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=1, .minval=0, .maxval=100, .step=1, .name="Hal-VolRamp"} + }, + { .tag=EndHalCrlTag} /* marker for end of the array */ } ; @@ -53,6 +69,7 @@ STATIC alsaHalSndCardT alsaHalSndCard = { .name = "Scarlett 18i8 USB", // WARNING: name MUST match with 'aplay -l' .info = "Hardware Abstraction Layer for Scarlett Focusrite USB professional music sound card", .ctls = alsaHalMap, + .volumeCB = NULL, // use default volume normalisation function }; diff --git a/HAL-afb/Unicens-USB/UnicensHAL.c b/HAL-afb/Unicens-USB/UnicensHAL.c index 66f241f..9a42afd 100644 --- a/HAL-afb/Unicens-USB/UnicensHAL.c +++ b/HAL-afb/Unicens-USB/UnicensHAL.c @@ -25,16 +25,7 @@ #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { - struct json_object *reponseJ; - - AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); - - reponseJ=json_object_new_object(); - json_object_object_add (reponseJ, "Callback", json_object_new_string("Hello From HAL")); - - return reponseJ; -} + // Map HAL hight sndctl with Alsa numid and optionally with a custom callback for non Alsa supported functionalities. STATIC alsaHalMapT alsaHalMap[]= { @@ -42,8 +33,6 @@ STATIC alsaHalMapT alsaHalMap[]= { { .tag=PCM_Playback_Volume , .ctl={.numid=06 } }, { .tag=PCM_Playback_Switch , .ctl={.numid=05 } }, { .tag=Capture_Volume , .ctl={.numid=12 } }, - { .tag=Master_OnOff_Switch , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_BOOLEAN, .count=1, .name="Power-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, - { .tag=Master_Playback_Ramp , .ctl={.numid=0, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=2, .name="Volume-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}}, { .tag=EndHalCrlTag} /* marker for end of the array */ } ; @@ -66,7 +55,7 @@ STATIC int sndServiceInit () { // API prefix should be unique for each snd card PUBLIC const struct afb_binding_v2 afbBindingV2 = { - .api = "intel-hda", + .api = "unicens-usb", .init = sndServiceInit, .verbs = halServiceApi, .onevent = halServiceEvent, diff --git a/HAL-afb/Unicens-USB/UnicensVol.c b/HAL-afb/Unicens-USB/UnicensVol.c index ab9787d..cf4f497 100644 --- a/HAL-afb/Unicens-USB/UnicensVol.c +++ b/HAL-afb/Unicens-USB/UnicensVol.c @@ -25,8 +25,8 @@ #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { - struct json_object *reponseJ; +STATIC json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, json_object *valJ) { + json_object *reponseJ; AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); diff --git a/Shared-Interface/audio-interface.h b/Shared-Interface/audio-interface.h index 01c71cd..453a9c4 100644 --- a/Shared-Interface/audio-interface.h +++ b/Shared-Interface/audio-interface.h @@ -60,19 +60,36 @@ typedef enum { } halAclEnumT; typedef enum { - StartHalCrlTag=0, - - // HighLevel Audio Control List, - Master_Playback_Volume =1, - Master_Playback_Ramp =2, - PCM_Playback_Volume =3, - PCM_Playback_Switch =4, - Capture_Volume =5, - Master_OnOff_Switch =6, + StartHalCrlTag=0, + // volume RAMP + Vol_Ramp, + Vol_Ramp_Set_Mode, + Vol_Ramp_Set_Delay, + Vol_Ramp_Set_Down, + Vol_Ramp_Set_Up, + Vol_Ramp_Set_Slave, + + // HighLevel Audio Control List, + Master_Playback_Volume, + Master_Playback_Ramp, + PCM_Playback_Volume, + PCM_Playback_Switch, + Capture_Volume, + Master_OnOff_Switch, + EndHalCrlTag // used to compute number of ctls } halCtlsEnumT; +typedef enum { + RAMP_VOL_NONE = 0, + RAMP_VOL_NORMAL = 1, + RAMP_VOL_SMOOTH = 2, + RAMP_VOL_EMERGENCY = 3, + + EndHalVolMod + +} halRampEnumT; PUBLIC void pingtest(struct afb_req request); diff --git a/conf.d/app-templates b/conf.d/app-templates index 8f3bc0b..dee5836 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 8f3bc0b6f25a5560a308078342a8ed3cc6dba13f +Subproject commit dee58363ddb98f8e63239035f1a8f1ab151c5e96 diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index e7801c8..116ed2a 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -18,7 +18,7 @@ # Project Info # ------------------ -set(PROJECT_NAME unicens-agent) +set(PROJECT_NAME audio-bindings) set(PROJECT_VERSION "0.1") set(PROJECT_PRETTY_NAME "Audio Agent") set(PROJECT_DESCRIPTION "Expose Alsa through AGL AppFw") diff --git a/htdocs/CMakeLists.txt b/htdocs/CMakeLists.txt index 0026b8c..60f6cf8 100644 --- a/htdocs/CMakeLists.txt +++ b/htdocs/CMakeLists.txt @@ -23,7 +23,7 @@ ################################################## PROJECT_TARGET_ADD(www_test) - file(GLOB SOURCE_FILES "*.html" "*.js" "*.jpg") + file(GLOB SOURCE_FILES "*.html" "*.js" "*.jpg" "*.css") add_custom_target(${TARGET_NAME} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} @@ -43,5 +43,5 @@ PROJECT_TARGET_ADD(www_test) ) # use only under native Linux when using "make install" - install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DESTINATION . FILES_MATCHING PATTERN "*.html" PATTERN "*.js" PATTERN "*.jpg") + install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DESTINATION .) diff --git a/htdocs/alsa-core.html b/htdocs/alsa-core.html index dafd43f..e946bdb 100644 --- a/htdocs/alsa-core.html +++ b/htdocs/alsa-core.html @@ -31,16 +31,16 @@
  1. -
  2. -
  3. +
  4. +

  5. -
  6. -
  7. -
  8. -
  9. -
  10. +
  11. +
  12. +
  13. +
  14. +

  15. diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 938c355..a54b713 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -15,8 +15,8 @@ hal-interface.c - hal-volmap.c - hal-volmap.h + hal-volramp.c + hal-volume.c HalPlugCb.c @@ -74,7 +74,7 @@ Build/Makefile - + GNU|GNU false @@ -105,16 +105,23 @@ - + - ../../../opt/include/afb - ALSA-afb + ../../../opt/include ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c Shared-Interface - ../../../opt/include build/ALSA-afb + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + MAX_LINEAR_DB_SCALE=24 + MAX_SND_CARD=16 + TLV_BYTE_SIZE=256 + alsa_lowlevel_EXPORTS + @@ -131,7 +138,6 @@ ../../../opt/include/afb ALSA-afb - ../../../opt/include/alsa /usr/include/json-c Shared-Interface ../../../opt/include @@ -140,23 +146,15 @@ - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + ../../../opt/include/afb + ALSA-afb /usr/include/json-c Shared-Interface + ../../../opt/include build/ALSA-afb - - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_LINEAR_DB_SCALE=24 - MAX_SND_CARD=16 - TLV_BYTE_SIZE=256 - alsa_lowlevel_EXPORTS - @@ -164,10 +162,8 @@ ../../../opt/include/afb ALSA-afb - ../../../opt/include/alsa /usr/include/json-c Shared-Interface - ../../../opt/include build/ALSA-afb @@ -188,7 +184,18 @@ - + + + + Shared-Interface + build/HAL-afb/HAL-interface + + + + build/HAL-afb/HAL-interface @@ -198,7 +205,6 @@ - ../../../opt/include build/HAL-afb/HAL-plugin @@ -206,7 +212,6 @@ - ../../../opt/include build/HAL-afb/HAL-plugin @@ -214,19 +219,20 @@ + ../../../opt/include/alsa build/HAL-afb/HAL-plugin - + - + @@ -335,7 +341,6 @@ HAL-afb/HAL-interface - ../../../opt/include/alsa /usr/include/json-c @@ -344,39 +349,50 @@ HAL-afb/HAL-plugin - ../../../opt/include/alsa - HAL-afb/HDA-intel + ../../../opt/include ../../../opt/include/alsa - Shared-Interface + /usr/include/p11-kit-1 + /usr/include/json-c HAL-afb/HAL-interface - ../../../opt/include + Shared-Interface build/HAL-afb/HDA-intel + + MAX_LINEAR_DB_SCALE=24 + TLV_BYTE_SIZE=256 + hal_intel_hda_EXPORTS + - HAL-afb/Scarlett-Focusrite + ../../../opt/include ../../../opt/include/alsa - Shared-Interface + /usr/include/p11-kit-1 + /usr/include/json-c HAL-afb/HAL-interface - ../../../opt/include + Shared-Interface build/HAL-afb/Scarlett-Focusrite + + MAX_LINEAR_DB_SCALE=24 + TLV_BYTE_SIZE=256 + hal_scalett_usb_EXPORTS + HAL-afb/Unicens-USB - ../../../opt/include/alsa + /usr/include/json-c @@ -399,7 +415,7 @@ - + GNU|GNU false @@ -407,9 +423,11 @@ - - - + + + + true @@ -417,7 +435,7 @@ build - ${MAKE} -f Makefile install + ${MAKE} -f Makefile remote-target-populate ${MAKE} -f Makefile clean build/CMakeFiles/feature_tests.bin @@ -428,45 +446,47 @@ - + - ../../../opt/include/alsa /usr/include/json-c + Shared-Interface + ../../../opt/include build/ALSA-afb - + build/ALSA-afb - + - ../../../opt/include/alsa /usr/include/json-c + Shared-Interface + ../../../opt/include build/ALSA-afb - + - ../../../opt/include/alsa /usr/include/json-c + Shared-Interface + ../../../opt/include build/ALSA-afb - + - ../../../opt/include/alsa /usr/include/json-c - ../../../opt/include + Shared-Interface build/ALSA-afb @@ -479,317 +499,96 @@ ex="false" tool="0" flavor2="3"> - - - - - - - - - - - HAL-afb/HAL-plugin - ../../../opt/include/alsa - ../../../opt/include - build/HAL-afb/HAL-plugin - - - - - - - HAL-afb/HAL-plugin - ../../../opt/include/alsa - ../../../opt/include - build/HAL-afb/HAL-plugin - - - - - + ../../../opt/include/afb - HAL-afb/HAL-plugin - ../../../opt/include/alsa - build/HAL-afb/HAL-plugin - - - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_SND_CARD=16 - - - - - - - - - - - - - - - Shared-Interface - ../../../opt/include - build/HighLevel-afb - - - - - - + HAL-afb/HAL-interface /usr/include/json-c Shared-Interface ../../../opt/include - build/HighLevel-afb + build/HAL-afb/HAL-interface - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ../../../opt/include/afb - ALSA-afb - - - - - + tool="0" + flavor2="3"> + - /usr/include/alsa ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c - build/Common + HAL-afb/HAL-interface + Shared-Interface + build/HAL-afb/HAL-interface - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_SND_CARD=16 + MAX_LINEAR_DB_SCALE=24 + TLV_BYTE_SIZE=256 - - - + + + ../../../opt/include/afb - - - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_SND_CARD=16 - - - - - - HAL-afb/HAL-interface - ../../../opt/include/alsa /usr/include/json-c - Shared-Interface - ../../../opt/include build/HAL-afb/HAL-interface - - - - - HAL-afb/HDA-intel - ../../../opt/include/alsa - Shared-Interface - HAL-afb/HAL-interface - ../../../opt/include - build/HAL-afb/HDA-intel - - - - - - - HAL-afb/Scarlett-Focusrite - ../../../opt/include/alsa - Shared-Interface - HAL-afb/HAL-interface - ../../../opt/include - build/HAL-afb/Scarlett-Focusrite - - - - - - - ../../../opt/include/afb - HighLevel-afb - - - - - - - ../../../opt/include/afb - Shared-Interface - /usr/include/json-c - build/Shared-Interface - - - - - - - GNU|GNU - false - false - - - - - - - - - true - - - - build - ${MAKE} -f Makefile install - ${MAKE} -f Makefile clean - build/CMakeFiles/feature_tests.bin - - - build - cmake .. - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c build/HAL-afb/HAL-plugin - - PIC - cb_sample_EXPORTS - - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c build/HAL-afb/HAL-plugin - - PIC - ctl_afbhal_EXPORTS - - HAL-afb/HAL-plugin ../../../opt/include/alsa build/HAL-afb/HAL-plugin - + - + + + + + + + Shared-Interface + HAL-afb/HAL-interface + ../../../opt/include + build/HAL-afb/Unicens-USB + + + + + + + HAL-afb/HAL-interface + build/HAL-afb/Unicens-USB + @@ -846,25 +645,15 @@ - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c - Shared-Interface - build/ALSA-afb + ../../../opt/include/afb + ALSA-afb - - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_SND_CARD=16 - alsa_lowlevel_EXPORTS - @@ -894,49 +683,43 @@ - + - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c - HAL-afb/HAL-interface - Shared-Interface - build/HAL-afb/HAL-interface + HAL-afb/HAL-plugin - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + HAL-afb/HDA-intel /usr/include/json-c - HAL-afb/HAL-interface Shared-Interface + HAL-afb/HAL-interface + ../../../opt/include build/HAL-afb/HDA-intel - - hal_intel_hda_EXPORTS - - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 + HAL-afb/Scarlett-Focusrite /usr/include/json-c - HAL-afb/HAL-interface Shared-Interface + HAL-afb/HAL-interface + ../../../opt/include build/HAL-afb/Scarlett-Focusrite - - hal_scalett_usb_EXPORTS - + + + + + + HAL-afb/Unicens-USB + /usr/include/json-c + @@ -950,18 +733,11 @@ - ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c + ../../../opt/include/afb Shared-Interface + /usr/include/json-c build/Shared-Interface - - CONTROL_CDEV_RX="/dev/inic-usb-crx" - CONTROL_CDEV_TX="/dev/inic-usb-ctx" - MAX_SND_CARD=16 - diff --git a/nbproject/project.xml b/nbproject/project.xml index 442a905..3e443c4 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -14,15 +14,11 @@ - Amixer-Dhw_4 + Localhost 0 - Amixer-CTL - 0 - - - Amixer-Set + Laptop 0 -- cgit 1.2.3-korg