From db4d63597b22b63eb73b5c0558476652ed4988bb Mon Sep 17 00:00:00 2001 From: fulup Date: Sun, 9 Jul 2017 19:59:24 +0200 Subject: initial version of HAL (registration + getctls) Work in progress --- ALSA-afb/Alsa-AddCtl.c | 252 +++++++-------- ALSA-afb/Alsa-ApiHat.c | 3 +- ALSA-afb/Alsa-ApiHat.h | 1 + ALSA-afb/Alsa-RegEvt.c | 55 ++-- ALSA-afb/Alsa-SetGet.c | 16 +- ALSA-afb/Alsa-Ucm.c | 14 +- HAL-afb/HAL-interface/hal-interface.c | 471 ++++++++++++++++++---------- HAL-afb/HAL-interface/hal-interface.h | 11 +- HAL-afb/HAL-plugin/CMakeLists.txt | 2 +- HAL-afb/HDA-intel/IntelHdaHAL.c | 31 +- HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c | 34 +- Shared-Interface/audio-interface.h | 2 + htdocs/AudioBinding.js | 5 +- htdocs/alsa-core.html | 1 + htdocs/alsa-hal.html | 34 ++ htdocs/index.html | 1 + nbproject/configurations.xml | 212 ++++++------- nbproject/project.xml | 2 +- 18 files changed, 658 insertions(+), 489 deletions(-) create mode 100644 htdocs/alsa-hal.html diff --git a/ALSA-afb/Alsa-AddCtl.c b/ALSA-afb/Alsa-AddCtl.c index 5754c15..25e2a31 100644 --- a/ALSA-afb/Alsa-AddCtl.c +++ b/ALSA-afb/Alsa-AddCtl.c @@ -22,154 +22,92 @@ #define _GNU_SOURCE // needed for vasprintf #include +#include #include -#include "Alsa-ApiHat.h" - #include -typedef struct _snd_ctl_ops { - int (*close)(snd_ctl_t *handle); - int (*nonblock)(snd_ctl_t *handle, int nonblock); - int (*async)(snd_ctl_t *handle, int sig, pid_t pid); - int (*subscribe_events)(snd_ctl_t *handle, int subscribe); - int (*card_info)(snd_ctl_t *handle, snd_ctl_card_info_t *info); - int (*element_list)(snd_ctl_t *handle, snd_ctl_elem_list_t *list); - int (*element_info)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); - int (*element_add)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); - int (*element_replace)(snd_ctl_t *handle, snd_ctl_elem_info_t *info); - int (*element_remove)(snd_ctl_t *handle, snd_ctl_elem_id_t *id); - int (*element_read)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); - int (*element_write)(snd_ctl_t *handle, snd_ctl_elem_value_t *control); - int (*element_lock)(snd_ctl_t *handle, snd_ctl_elem_id_t *lock); - int (*element_unlock)(snd_ctl_t *handle, snd_ctl_elem_id_t *unlock); - int (*element_tlv)(snd_ctl_t *handle, int op_flag, unsigned int numid, - unsigned int *tlv, unsigned int tlv_size); - int (*hwdep_next_device)(snd_ctl_t *handle, int *device); - int (*hwdep_info)(snd_ctl_t *handle, snd_hwdep_info_t * info); - int (*pcm_next_device)(snd_ctl_t *handle, int *device); - int (*pcm_info)(snd_ctl_t *handle, snd_pcm_info_t * info); - int (*pcm_prefer_subdevice)(snd_ctl_t *handle, int subdev); - int (*rawmidi_next_device)(snd_ctl_t *handle, int *device); - int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info); - int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev); - int (*set_power_state)(snd_ctl_t *handle, unsigned int state); - int (*get_power_state)(snd_ctl_t *handle, unsigned int *state); - int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event); - int (*poll_descriptors_count)(snd_ctl_t *handle); - int (*poll_descriptors)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space); - int (*poll_revents)(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); -} snd_ctl_ops_t; - -typedef struct private_snd_ctl { - void *open_func; - char *name; - snd_ctl_type_t type; - const snd_ctl_ops_t *ops; - void *private_data; - int nonblock; - int poll_fd; - void *async_handlers; -} private_snd_ctl_t; - -typedef struct { - int card; - int fd; - unsigned int protocol; -} snd_ctl_hw_t; +#include "Alsa-ApiHat.h" -static int snd_ctl_hw_elem_replace(snd_ctl_t *ctlDev, snd_ctl_elem_info_t *info, snd_ctl_elem_id_t *elemId) { - size_t len=snd_ctl_elem_info_sizeof(); - private_snd_ctl_t *handle= (private_snd_ctl_t*) ctlDev; - snd_ctl_hw_t *hw = handle->private_data; - - NOTICE ("count=%d ITEMNAME=%s writable=%d owner=%d", snd_ctl_elem_info_get_count(info), snd_ctl_elem_info_get_name(info) - , snd_ctl_elem_info_is_writable(info), snd_ctl_elem_info_get_owner(info)); - snd_ctl_elem_lock(ctlDev, elemId); - - int err= handle->ops->element_replace (ctlDev, info); - NOTICE ("count=%d ITEMNAME=%s writable=%d isowner=%d islocked=%d innactiv=%d", snd_ctl_elem_info_get_count(info), snd_ctl_elem_info_get_name(info) - , snd_ctl_elem_info_is_writable(info), snd_ctl_elem_info_is_owner(info), snd_ctl_elem_info_is_locked(info), snd_ctl_elem_info_is_inactive(info)); - return err; +// 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 SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0); + unsigned int *tlv= malloc(sizeof(range)); + if (tlv == NULL) return NULL; + memcpy(tlv, range, sizeof(range)); + return tlv; } - -STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) { - int err, ctlExist; - json_object *jTmp; +STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) { + int err, ctlNumid; + json_object *tmpJ; + ctlRequestT ctlRequest; const char *ctlName; - int ctlNumid, ctlMax, ctlMin, ctlStep, ctlCount, ctlSubDev, ctlSndDev; + int ctlMax, ctlMin, ctlStep, ctlCount, ctlSubDev, ctlSndDev; snd_ctl_elem_type_t ctlType; - snd_ctl_elem_id_t *elemId; snd_ctl_elem_info_t *elemInfo; + snd_ctl_elem_id_t *elemId; snd_ctl_elem_value_t *elemValue; + const unsigned int *elemTlv=NULL; // parse json ctl object - json_object_object_get_ex (ctlJ, "name" , &jTmp); - if (!jTmp) { - afb_req_fail_f (request, "ctl-invalid", "crl=%s name missing", json_object_get_string(ctlJ)); + json_object_object_get_ex (ctlJ, "name" , &tmpJ); + ctlName = json_object_get_string(tmpJ); + + json_object_object_get_ex (ctlJ, "numid" , &tmpJ); + ctlNumid = json_object_get_int(tmpJ); + + if (!ctlNumid && !ctlName) { + afb_req_fail_f (request, "ctl-invalid", "crl=%s name or numid missing", json_object_get_string(ctlJ)); goto OnErrorExit; - } - ctlName = json_object_get_string(jTmp); + } + + // Assert that this ctls is not used + snd_ctl_elem_info_alloca(&elemInfo); + if (ctlName) snd_ctl_elem_info_set_name (elemInfo, ctlName); + if (ctlNumid)snd_ctl_elem_info_set_numid(elemInfo, ctlNumid); + snd_ctl_elem_info_set_interface (elemInfo, SND_CTL_ELEM_IFACE_MIXER); + err = snd_ctl_elem_info(ctlDev, elemInfo); + if (!err) { + AFB_NOTICE ("ctlName=%s numid=%d already exit", snd_ctl_elem_info_get_name(elemInfo), snd_ctl_elem_info_get_numid(elemInfo)); + snd_ctl_elem_id_alloca(&elemId); + snd_ctl_elem_info_get_id(elemInfo, elemId); + goto OnSucessExit; + } - // default value when not present => 0 - json_object_object_get_ex (ctlJ, "numid" , &jTmp); - ctlNumid = json_object_get_int(jTmp); - // default for json_object_get_int is zero - json_object_object_get_ex (ctlJ, "min" , &jTmp); - ctlMin = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "min" , &tmpJ); + ctlMin = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "max" , &jTmp); - if (!jTmp) ctlMax=1; - else ctlMax = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "max" , &tmpJ); + if (!tmpJ) ctlMax=1; + else ctlMax = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "step" , &jTmp); - if (!jTmp) ctlStep=1; - else ctlStep = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "step" , &tmpJ); + if (!tmpJ) ctlStep=1; + else ctlStep = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "count" , &jTmp); - if (!jTmp) ctlCount=2; - else ctlCount = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "count" , &tmpJ); + if (!tmpJ) ctlCount=2; + else ctlCount = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "snddev" , &jTmp); - ctlSndDev = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "snddev" , &tmpJ); + ctlSndDev = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "subdev" , &jTmp); - ctlSubDev = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "subdev" , &tmpJ); + ctlSubDev = json_object_get_int(tmpJ); - json_object_object_get_ex (ctlJ, "type" , &jTmp); - if (!jTmp) ctlType=SND_CTL_ELEM_TYPE_BOOLEAN; - else ctlType = json_object_get_int(jTmp); + json_object_object_get_ex (ctlJ, "type" , &tmpJ); + if (!tmpJ) ctlType=SND_CTL_ELEM_TYPE_BOOLEAN; + else ctlType = json_object_get_int(tmpJ); // Add requested ID into elemInfo - snd_ctl_elem_info_alloca(&elemInfo); - snd_ctl_elem_id_alloca(&elemId); - snd_ctl_elem_id_set_numid (elemId, ctlNumid); - snd_ctl_elem_id_set_name (elemId, ctlName); - snd_ctl_elem_id_set_interface(elemId, SND_CTL_ELEM_IFACE_HWDEP); - snd_ctl_elem_id_set_device(elemId, ctlSndDev); - snd_ctl_elem_id_set_subdevice(elemId, ctlSubDev); - - // Assert that this ctls is not used - snd_ctl_elem_info_set_id (elemInfo, elemId); - ctlExist= !snd_ctl_elem_info(ctlDev, elemInfo); - if (ctlExist) { - NOTICE ("1:ctl exist ctlName=%s NUMID=%d NAME=%s", ctlName, snd_ctl_elem_info_get_numid(elemInfo), snd_ctl_elem_info_get_name(elemInfo)); - snd_ctl_elem_id_set_name (elemId, ctlName); - snd_ctl_elem_info_set_name (elemInfo, ctlName); - err= snd_ctl_hw_elem_replace (ctlDev, elemInfo, elemId); - if (err) { - NOTICE ("Fail changing ctlname error=%s", snd_strerror(err)); - } - NOTICE ("2:ctl exist ctlName=%s NUMID=%d NAME=%s", ctlName, snd_ctl_elem_info_get_numid(elemInfo), snd_ctl_elem_info_get_name(elemInfo)); - } + snd_ctl_elem_info_set_device(elemInfo, ctlSndDev); + snd_ctl_elem_info_set_subdevice(elemInfo, ctlSubDev); - // try to normalise ctl name + // prepare value set snd_ctl_elem_value_alloca(&elemValue); - snd_ctl_elem_id_set_name (elemId, ctlName); - snd_ctl_elem_value_set_id(elemValue, elemId); - - if (!ctlExist) switch (ctlType) { + + switch (ctlType) { case SND_CTL_ELEM_TYPE_BOOLEAN: err = snd_ctl_add_boolean_elem_set(ctlDev, elemInfo, 1, ctlCount); if (err) { @@ -177,45 +115,79 @@ STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) goto OnErrorExit; } + elemTlv = allocate_bool_elem_set_tlv(); + // Provide FALSE as default value for (int idx=0; idx < ctlCount; idx ++) { - snd_ctl_elem_value_set_boolean (elemValue, idx, 0); - } + snd_ctl_elem_value_set_boolean (elemValue, idx, 1); + } break; case SND_CTL_ELEM_TYPE_INTEGER: + err = snd_ctl_add_integer_elem_set (ctlDev, elemInfo, 1, ctlCount, ctlMin, ctlMax, ctlStep); + 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; + } + + // Provide 0 as default value + for (int idx=0; idx < ctlCount; idx ++) { + snd_ctl_elem_value_set_integer (elemValue, idx, 0); + } break; case SND_CTL_ELEM_TYPE_INTEGER64: + err = snd_ctl_add_integer64_elem_set (ctlDev, elemInfo, 1, ctlCount, ctlMin, ctlMax, ctlStep); + 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; + } + + // Provide 0 as default value + for (int idx=0; idx < ctlCount; idx ++) { + snd_ctl_elem_value_set_integer64 (elemValue, idx, 0); + } break; - case SND_CTL_ELEM_TYPE_ENUMERATED: - break; - + case SND_CTL_ELEM_TYPE_ENUMERATED: case SND_CTL_ELEM_TYPE_BYTES: - break; - default: afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_get_string(ctlJ)); goto OnErrorExit; } + // write default values in newly created control + snd_ctl_elem_id_alloca(&elemId); + snd_ctl_elem_info_get_id(elemInfo, elemId); + snd_ctl_elem_value_set_id(elemValue, elemId); err = snd_ctl_elem_write (ctlDev, elemValue); if (err < 0) { - afb_req_fail_f (request, "ctl-write-fail", "crl=%s fail to write data data", json_object_get_string(ctlJ)); + afb_req_fail_f (request, "ctl-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 0; + // write a default null TLV (if usefull should be implemented for every ctl type) + if (elemTlv) { + err=snd_ctl_elem_tlv_write (ctlDev, elemId, elemTlv); + if (err < 0) { + 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: + alsaGetSingleCtl (ctlDev, elemId, &ctlRequest, 0); + if (ctlRequest.used < 0) goto OnErrorExit; + return ctlRequest.jValues; OnErrorExit: - return -1; + return NULL; } PUBLIC void alsaAddCustomCtls(afb_req request) { int err; - json_object *ctlsJ; + json_object *ctlsJ, *ctlsValues, *ctlValues; enum json_type; snd_ctl_t *ctlDev=NULL; const char *devid; @@ -242,13 +214,16 @@ PUBLIC void alsaAddCustomCtls(afb_req request) { switch (json_object_get_type(ctlsJ)) { case json_type_object: - addOneSndCtl(request, ctlDev, ctlsJ); + ctlsValues= addOneSndCtl(request, ctlDev, ctlsJ); + break; case json_type_array: + ctlsValues= json_object_new_array(); for (int idx= 0; idx < json_object_array_length (ctlsJ); idx++) { json_object *ctlJ = json_object_array_get_idx (ctlsJ, idx); - addOneSndCtl(request, ctlDev, ctlJ) ; + ctlValues= addOneSndCtl(request, ctlDev, ctlJ) ; + if (ctlValues) json_object_array_add (ctlsValues, ctlValues); } break; @@ -256,6 +231,9 @@ PUBLIC void alsaAddCustomCtls(afb_req request) { afb_req_fail_f (request, "ctls-invalid","ctls=%s not valid JSON array", json_object_get_string(ctlsJ)); goto OnErrorExit; } + + // get ctl as a json response + afb_req_success(request, ctlsValues, NULL); OnErrorExit: if (ctlDev) snd_ctl_close(ctlDev); diff --git a/ALSA-afb/Alsa-ApiHat.c b/ALSA-afb/Alsa-ApiHat.c index 588e91b..5256fb4 100644 --- a/ALSA-afb/Alsa-ApiHat.c +++ b/ALSA-afb/Alsa-ApiHat.c @@ -39,7 +39,8 @@ static const struct afb_verb_v2 api_verbs[] = { { .verb= "setctls", .callback= alsaSetCtls}, { .verb= "subscribe", .callback= alsaEvtSubcribe}, { .verb= "getcardid", .callback= alsaGetCardId}, - { .verb= "registerHal", .callback= alsaRegisterHal}, + { .verb= "halregister", .callback= alsaRegisterHal}, + { .verb= "hallist", .callback= alsaActiveHal}, { .verb= "ucmquery", .callback= alsaUseCaseQuery}, { .verb= "ucmset", .callback= alsaUseCaseSet}, { .verb= "ucmget", .callback= alsaUseCaseGet}, diff --git a/ALSA-afb/Alsa-ApiHat.h b/ALSA-afb/Alsa-ApiHat.h index bd8518f..46f18de 100644 --- a/ALSA-afb/Alsa-ApiHat.h +++ b/ALSA-afb/Alsa-ApiHat.h @@ -68,6 +68,7 @@ PUBLIC void alsaAddCustomCtls(struct afb_req request); PUBLIC void alsaEvtSubcribe (struct afb_req request); PUBLIC void alsaGetCardId (struct afb_req request); PUBLIC void alsaRegisterHal (struct afb_req request); +PUBLIC void alsaActiveHal (struct afb_req request); #endif /* ALSALIBMAPPING_H */ diff --git a/ALSA-afb/Alsa-RegEvt.c b/ALSA-afb/Alsa-RegEvt.c index e06cf87..61885f7 100644 --- a/ALSA-afb/Alsa-RegEvt.c +++ b/ALSA-afb/Alsa-RegEvt.c @@ -104,7 +104,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* return 0; OnErrorExit: - WARNING ("sndCtlEventCB: ignored unsupported event type"); + AFB_WARNING ("sndCtlEventCB: ignored unsupported event type"); return (0); } @@ -112,7 +112,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* PUBLIC void alsaEvtSubcribe (afb_req request) { static sndHandleT sndHandles[MAX_SND_CARD]; evtHandleT *evtHandle; - snd_ctl_t *ctlDev; + snd_ctl_t *ctlDev=NULL; int err, idx, cardId, idxFree=-1; snd_ctl_card_info_t *cardinfo; queryValuesT queryValues; @@ -125,7 +125,6 @@ PUBLIC void alsaEvtSubcribe (afb_req request) { // open control interface for devid err = snd_ctl_open(&ctlDev, queryValues.devid, SND_CTL_READONLY); if (err < 0) { - ctlDev=NULL; afb_req_fail_f (request, "devid-unknown", "SndCard devid=%s Not Found err=%s", queryValues.devid, snd_strerror(err)); goto OnErrorExit; } @@ -212,7 +211,7 @@ PUBLIC void alsaGetCardId (afb_req request) { char devid [10]; const char *devname, *shortname, *longname; int card, err, index, idx; - json_object *respJson; + json_object *responseJ; snd_ctl_t *ctlDev; snd_ctl_card_info_t *cardinfo; @@ -252,26 +251,44 @@ PUBLIC void alsaGetCardId (afb_req request) { } // proxy ctlevent as a binder event - respJson = json_object_new_object(); - json_object_object_add(respJson, "index" ,json_object_new_int (index)); - json_object_object_add(respJson, "devid" ,json_object_new_string (devid)); - json_object_object_add(respJson, "shortname" ,json_object_new_string (shortname)); - json_object_object_add(respJson, "longname" ,json_object_new_string (longname)); + responseJ = json_object_new_object(); + json_object_object_add(responseJ, "index" ,json_object_new_int (index)); + json_object_object_add(responseJ, "devid" ,json_object_new_string (devid)); + json_object_object_add(responseJ, "shortname" ,json_object_new_string (shortname)); + json_object_object_add(responseJ, "longname" ,json_object_new_string (longname)); // search for a HAL binder card mapping name to api prefix - for (idx=0; idx < MAX_SND_CARD; idx++) { - if (!strcmp (cardRegistry[idx]->shortname, shortname)) break; + for (idx=0; (idx < MAX_SND_CARD && cardRegistry[idx]); idx++) { + if (!strcmp (cardRegistry[idx]->shortname, shortname)) { + json_object_object_add(responseJ, "halapi",json_object_new_string (cardRegistry[idx]->apiprefix)); + break; + } } - // if a match if found, then we have an HAL for this board let's return its value - if (idx < MAX_SND_CARD) json_object_object_add(respJson, "halapi",json_object_new_string (cardRegistry[idx]->apiprefix)); - - afb_req_success(request, respJson, NULL); + + afb_req_success(request, responseJ, NULL); return; OnErrorExit: return; } +// Return list of active resgistrated HAL with corresponding sndcard +PUBLIC void alsaActiveHal (afb_req request) { + json_object *responseJ = json_object_new_array(); + + for (int idx=0; idx < MAX_SND_CARD; idx++) { + if (!cardRegistry[idx]) break; + + json_object *haldevJ = json_object_new_object(); + json_object_object_add(haldevJ, "api", json_object_new_string(cardRegistry[idx]->apiprefix)); + json_object_object_add(haldevJ, "devid", json_object_new_string(cardRegistry[idx]->shortname)); + json_object_array_add (responseJ, haldevJ); + } + + afb_req_success(request, responseJ, NULL); +} + + // Register loaded HAL with board Name and API prefix PUBLIC void alsaRegisterHal (afb_req request) { static int index=0; @@ -293,14 +310,16 @@ PUBLIC void alsaRegisterHal (afb_req request) { afb_req_fail_f (request, "alsahal-toomany", "Fail to register sndname=[%s]", shortname); goto OnErrorExit; } - + + // alsaGetCardId should be check to register only valid card cardRegistry[index]= malloc (sizeof(cardRegistry)); cardRegistry[index]->apiprefix=strdup(apiPrefix); cardRegistry[index]->shortname=strdup(shortname); index++;cardRegistry[index]=NULL; - - // If OK return sound card Alsa ID+Info + alsaGetCardId(request); + + // If OK return sound card Alsa ID+Info return; OnErrorExit: diff --git a/ALSA-afb/Alsa-SetGet.c b/ALSA-afb/Alsa-SetGet.c index 9d0ec43..56dc32f 100644 --- a/ALSA-afb/Alsa-SetGet.c +++ b/ALSA-afb/Alsa-SetGet.c @@ -350,14 +350,14 @@ STATIC json_object* alsaCardProbe (const char *rqtSndId) { int err; if ((err = snd_ctl_open(&handle, rqtSndId, 0)) < 0) { - INFO ("SndCard [%s] Not Found", rqtSndId); + AFB_INFO ("SndCard [%s] Not Found", rqtSndId); return NULL; } snd_ctl_card_info_alloca(&cardinfo); if ((err = snd_ctl_card_info(handle, cardinfo)) < 0) { snd_ctl_close(handle); - WARNING ("SndCard [%s] info error: %s", rqtSndId, snd_strerror(err)); + AFB_WARNING ("SndCard [%s] info error: %s", rqtSndId, snd_strerror(err)); return NULL; } @@ -375,7 +375,7 @@ STATIC json_object* alsaCardProbe (const char *rqtSndId) { json_object_object_add (ctlDev, "driver" , json_object_new_string(driver)); info = strdup(snd_ctl_card_info_get_longname (cardinfo)); json_object_object_add (ctlDev, "info" , json_object_new_string (info)); - INFO ("AJG: Soundcard Devid=%-5s devid=%-7s Name=%s\n", rqtSndId, devid, info); + AFB_INFO ("AJG: Soundcard Devid=%-5s devid=%-7s Name=%s\n", rqtSndId, devid, info); } // free card handle and return info @@ -461,7 +461,6 @@ PUBLIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe goto OnErrorExit; } - snd_ctl_elem_info_get_id(elemInfo, elemId); // map ctlInfo to ctlId elemInfo is updated !!! if (!snd_ctl_elem_info_is_writable(elemInfo)) { AFB_NOTICE( "Not Writable ALSA NUMID=%d Values=[%s]", ctlRequest->numId, json_object_get_string(ctlRequest->jValues)); goto OnErrorExit; @@ -533,23 +532,22 @@ PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe // set info event ID and get value snd_ctl_elem_info_alloca(&elemInfo); - snd_ctl_elem_info_set_id(elemInfo, elemId); // map ctlInfo to ctlId elemInfo is updated !!! + snd_ctl_elem_info_set_id(elemInfo, elemId); if (snd_ctl_elem_info(ctlDev, elemInfo) < 0) goto OnErrorExit; count = snd_ctl_elem_info_get_count (elemInfo); if (count == 0) goto OnErrorExit; - snd_ctl_elem_info_get_id(elemInfo, elemId); // map ctlInfo to ctlId elemInfo is updated !!! if (!snd_ctl_elem_info_is_readable(elemInfo)) goto OnErrorExit; elemType = snd_ctl_elem_info_get_type(elemInfo); snd_ctl_elem_value_alloca(&elemData); - snd_ctl_elem_value_set_id(elemData, elemId); // map ctlInfo to ctlId elemInfo is updated !!! + snd_ctl_elem_value_set_id(elemData, elemId); if (snd_ctl_elem_read(ctlDev, elemData) < 0) goto OnErrorExit; int numid= snd_ctl_elem_info_get_numid(elemInfo); ctlRequest->jValues= json_object_new_object(); - json_object_object_add (ctlRequest->jValues,"id" , json_object_new_int(numid)); + json_object_object_add (ctlRequest->jValues,"numid" , json_object_new_int(numid)); if (quiet < 2) json_object_object_add (ctlRequest->jValues,"name" , json_object_new_string(snd_ctl_elem_id_get_name (elemId))); if (quiet < 1) json_object_object_add (ctlRequest->jValues,"iface" , json_object_new_string(snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(elemId)))); if (quiet < 3) json_object_object_add (ctlRequest->jValues,"actif", json_object_new_boolean(!snd_ctl_elem_info_is_inactive(elemInfo))); @@ -594,7 +592,7 @@ PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe if (!quiet) { // in simple mode do not print usable values json_object *jsonClassCtl = json_object_new_object(); - json_object_object_add (jsonClassCtl,"type" , json_object_new_string(snd_ctl_elem_type_name(elemType))); + json_object_object_add (jsonClassCtl,"type" , json_object_new_int(elemType)); json_object_object_add (jsonClassCtl,"count", json_object_new_int(count)); switch (elemType) { diff --git a/ALSA-afb/Alsa-Ucm.c b/ALSA-afb/Alsa-Ucm.c index bc492b3..b2039be 100644 --- a/ALSA-afb/Alsa-Ucm.c +++ b/ALSA-afb/Alsa-Ucm.c @@ -275,17 +275,17 @@ PUBLIC void alsaUseCaseGet (struct afb_req request) { enum json_type jtype= json_object_get_type(jLabels); switch (jtype) { - json_object *jTmp; + json_object *tmpJ; case json_type_array: labelCount = json_object_array_length (jLabels); break; case json_type_string: - jTmp = json_object_new_array (); + tmpJ = json_object_new_array (); labelCount = 1; - json_object_array_add (jTmp, jLabels); - jLabels=jTmp; + json_object_array_add (tmpJ, jLabels); + jLabels=tmpJ; break; default: @@ -308,9 +308,9 @@ PUBLIC void alsaUseCaseGet (struct afb_req request) { // use info section to notified not found values label if (json_object_array_length (jWarnings) > 0) { - json_object *jTmp = json_object_new_object (); - json_object_object_add (jTmp, "no-context", jWarnings); - warnings= json_object_get_string (jTmp); + json_object *tmpJ = json_object_new_object (); + json_object_object_add (tmpJ, "no-context", jWarnings); + warnings= json_object_get_string (tmpJ); } afb_req_success (request, jResponse, warnings); diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c index 035278b..19fe191 100644 --- a/HAL-afb/HAL-interface/hal-interface.c +++ b/HAL-afb/HAL-interface/hal-interface.c @@ -31,203 +31,313 @@ #include "hal-interface.h" -typedef struct { - int index; - int numid; -} shareHallMap_T; +static alsaHalMapT *halCtls; +static const char *halDevid; + + + +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", -static shareHallMap_T *shareHallMap; -static alsaHalMapT *halCtls; + [EndHalCrlTag] = "NOT_USED" + +}; // Force specific HAL to depend on ShareHalLib PUBLIC char* SharedHalLibVersion="1.0"; - + // Subscribe to AudioBinding events STATIC void halSubscribe(afb_req request) { - const char *devid = afb_req_value(request, "devid"); - if (devid == NULL) { - afb_req_fail_f(request, "devid-missing", "devid=hw:xxx missing"); + const char *devidJ = afb_req_value(request, "devid"); + if (devidJ == NULL) { + afb_req_fail_f(request, "devidJ-missing", "devidJ=hw:xxx missing"); } } -// Call when all bindings are loaded and ready to accept request -STATIC void halGetVol(afb_req request) { - // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card - afb_req_success(request, NULL, NULL); - return; +// HAL normalise volume values to 0-100% +STATIC struct json_object *NormaliseValue(const alsaHalCtlMapT *halCtls, struct json_object *valuesJ) { + int length; + // assert response as the right length + length = json_object_array_length(valuesJ); + if (length != halCtls->count) { + AFB_WARNING ("NormaliseValue invalid ctl=%s values count=%d len=%d", halCtls->name, halCtls->count, length); + return NULL; + } + + json_object *normalisedJ= json_object_new_array(); + for (int idx=0; idx halCtls->maxval) value= halCtls->maxval; + if (value < halCtls->minval) value= halCtls->minval; + + // If Integer scale to 0/100 + if (halCtls->type == SND_CTL_ELEM_TYPE_INTEGER) { + value = (value * 100) / (halCtls->maxval - halCtls->minval); + } + + json_object_array_add(normalisedJ, json_object_new_int(value)); + } + + return (normalisedJ); } -STATIC void halSetVol(afb_req request) { - const char *arg; - const char *pcm; +// Remap low level controls into HAL hight level ones +STATIC json_object *CtlGetPrepareResponse(afb_req request, struct json_object *ctlsJ) { + struct json_object *halResponseJ; - arg = afb_req_value(request, "vol"); - if (arg == NULL) { - afb_req_fail_f(request, "argument-missing", "vol=[0,100] missing"); + // 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; } + + // responseJ is a JSON array + halResponseJ = json_object_new_array(); - pcm = afb_req_value(request, "pcm"); - if (pcm == NULL) pcm = "Master"; - - // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card - afb_req_success(request, NULL, NULL); - return; - -OnErrorExit: - return; + // 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; + int numid; + sndCtlJ = json_object_array_get_idx(ctlsJ, idx); + if (!json_object_object_get_ex(sndCtlJ, "numid", &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= (halCtlsEnumT) 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 + struct json_object *halCtlJ = json_object_new_object(); + json_object_object_add(halCtlJ, "label", json_object_new_string(halCtls[idx].label)); // idx+1 == HAL/NUMID + json_object_object_add(halCtlJ, "tag" , json_object_new_int(halCtls[idx].tag)); // idx+1 == HAL/NUMID + json_object_object_add(halCtlJ, "val" , NormaliseValue(&halCtls[idx].ctl, valJ)); + json_object_array_add(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; } -// AudioLogic expect volume values to be 0-100% - -STATIC int NormaliseValue(const alsaHalCtlMapT *halCtls, int valuein) { - int valueout; - - if (valuein > halCtls->maxval) valuein= halCtls->maxval; - if (valuein < halCtls->minval) valuein= halCtls->minval; - - // volume are ajusted to 100% any else is ignored - switch (halCtls->group) { - case OUTVOL: - case PCMVOL: - case INVOL: - valueout = (valuein * 100) / (halCtls->maxval - halCtls->minval); - break; - default: - valueout = valuein; +// Return ALL HAL snd controls +PUBLIC void halListCtls(afb_req request) { + struct 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_object_add(ctlHalJ, "label", json_object_new_string(halCtls[idx].label)); + 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); } - return (valueout); + + afb_req_success (request, ctlsHalJ, NULL); } -// receive controls for LowLevel remap them to hight level before returning them +// Map HAL ctlName to ctlLabel +STATIC int halCtlStringToIndex (const char* label) { -STATIC void halGetControlCB(void *handle, int iserror, struct json_object *result) { - struct json_object *response; - - // retrieve request and check for errors - afb_req request = afb_req_unstore(handle); - if (!cbCheckResponse(request, iserror, result)) goto OnExit; - - // Get response from object - json_object_object_get_ex(result, "response", &response); - if (!response) { - afb_req_fail_f(request, "response-notfound", "No Controls return from alsa/getcontrol result=[%s]", json_object_get_string(result)); - goto OnExit; + for (int idx = 0; halCtls[idx].ctl.numid; idx++) { + if (!strcmp (halCtls[idx].label, label)) return idx; } + + // not found + return -1; +} - // extract sounds controls information from received Object - struct json_object *ctls; - json_object_object_get_ex(result, "ctls", &ctls); - if (!ctls) { - afb_req_fail_f(request, "ctls-notfound", "No Controls return from alsa/getcontrol response=[%s]", json_object_get_string(response)); - goto OnExit; - } +STATIC int halCtlTagToIndex (halCtlsEnumT tag) { - // make sure return controls have a valid type - if (json_object_get_type(ctls) != json_type_array) { - afb_req_fail_f(request, "ctls-notarray", "Invalid Controls return from alsa/getcontrol response=[%s]", json_object_get_string(response)); - goto OnExit; + for (int idx = 0; halCtls[idx].ctl.numid; idx++) { + if (halCtls[idx].tag == tag) return idx; } + + // not found + return -1; +} - // loop on array and store values into client context - for (int idx = 0; idx < json_object_array_length(ctls); idx++) { - struct json_object *ctl; - int rawvalue, numid; - - ctl = json_object_array_get_idx(ctls, idx); - if (json_object_array_length(ctl) != 2) { - afb_req_fail_f(request, "ctl-invalid", "Invalid Control return from alsa/getcontrol ctl=[%s]", json_object_get_string(ctl)); - goto OnExit; - } - - // As HAL and Business logic use the same AlsaMixerHal.h direct conversion is not an issue - numid = (halCtlsEnumT) json_object_get_int(json_object_array_get_idx(ctl, 0)); - rawvalue = json_object_get_int(json_object_array_get_idx(ctl, 1)); - - for (int idx = 0; halCtls[idx].alsa.numid != 0; idx++) { - if (halCtls[idx].alsa.numid == numid) { - struct json_object *ctlAndValue = json_object_new_array(); - json_object_array_add(ctlAndValue, json_object_new_int(idx)); // idx == high level control - json_object_array_add(ctlAndValue, json_object_new_int(NormaliseValue(&halCtls[idx].alsa, rawvalue))); - break; - } - } - if (shareHallMap[idx].numid == 0) { +STATIC int halGetOneCtls (afb_req request, struct json_object*ctlInJ) { + struct json_object *tmpJ; + int tag, index; - afb_req_fail_f(request, "ctl-invalid", "Invalid Control numid from alsa/getcontrol ctl=[%s]", json_object_get_string(ctl)); - goto OnExit; - } + // check 1st short command mode [tag1, tag2, ...] + tag = json_object_get_type (ctlInJ); + + if (!tag) { + json_object_object_get_ex (ctlInJ, "tag" , &tmpJ); + tag = json_object_get_int(tmpJ); + } + + if (tag) { + index = halCtlTagToIndex((halCtlsEnumT) tag); + } else { + // tag was not provided let's try label + const char *label; + + json_object_object_get_ex (ctlInJ, "label" , &tmpJ); + label = json_object_get_string(tmpJ); + index = halCtlStringToIndex(label); } - OnExit: - return; -} - + if (index < 0) { + afb_req_fail_f(request, "ctl-invalid", "No Label/Tag given ctl=[%s]", json_object_get_string(ctlInJ)); + goto OnErrorExit; + } + + // return corresponding lowlevel numid to querylist + return halCtls[index].ctl.numid; + + OnErrorExit: + return -1; +} // Translate high level control to low level and call lower layer -STATIC void halGetCtls(afb_req request) { - - struct json_object *queryin, *queryout, *ctlsin, *devid; - struct json_object *ctlsout = json_object_new_array(); +PUBLIC void halGetCtls(afb_req request) { + int err, numid; + struct json_object *ctlsInJ, *ctlsOutJ, *queryJ, *responseJ; // get query from request - queryin = afb_req_json(request); - - // check devid was given - if (!json_object_object_get_ex (queryin, "devid", &devid)) { - afb_req_fail_f(request, "devid-notfound", "No DevID given query=[%s]", json_object_get_string(queryin)); - goto OnExit; - } - - // loop on requested controls - if (!json_object_object_get_ex(queryin, "ctls", &ctlsin) || json_object_array_length(ctlsin) <= 0) { - afb_req_fail_f(request, "ctlsin-notfound", "No Controls given query=[%s]", json_object_get_string(queryin)); - goto OnExit; - } + ctlsInJ = afb_req_json(request); + ctlsOutJ = json_object_new_array(); + + switch (json_object_get_type(ctlsInJ)) { + case json_type_object: { - // loop on controls - for (int idx = 0; idx < json_object_array_length(ctlsin); idx++) { - struct json_object *ctl; - halCtlsEnumT control; - - // each control should be halCtlsEnumT - ctl = json_object_array_get_idx(ctlsin, idx); - control = (halCtlsEnumT) json_object_get_int(ctl); - if (control >= EndHalCrlTag || control <= StartHalCrlTag) { - afb_req_fail_f(request, "ctl-invalid", "Invalid Control devid=%s ctl=[%s] should be [%d-%d]" - , json_object_get_string(devid), json_object_get_string(ctl), StartHalCrlTag, EndHalCrlTag); - goto OnExit; + numid = halGetOneCtls (request, ctlsInJ); + if (numid <=0) goto OnErrorExit; + json_object_array_add (ctlsOutJ, json_object_new_int(numid)); + break; } - - // add corresponding lowlevel numid to querylist - json_object_array_add(ctlsout, json_object_new_int(shareHallMap[control].numid)); + + 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); + numid= halGetOneCtls (request, ctlInJ); + if (numid<=0) goto OnErrorExit; + json_object_array_add (ctlsOutJ, json_object_new_int(numid)); + } + break; + } + + default: + afb_req_fail_f(request, "ctl-invalid", "Not a valid JSON ctl=[%s]", json_object_get_string(ctlsInJ)); + goto OnErrorExit; } - // register HAL with Alsa Low Level Binder devid=hw:0&numid=1&quiet=0 - queryout = json_object_new_object(); - json_object_object_add(queryout, "devid", devid); - json_object_object_add(queryout, "ctls", ctlsout); + // Call now level CTL + queryJ = json_object_new_object(); + json_object_object_add(queryJ, "devid", json_object_new_string (halDevid)); + json_object_object_add(queryJ, "numids", ctlsOutJ); - // Fulup afb_service_call("alsacore", "getctl", queryout, halGetControlCB, handle); + err= afb_service_call_sync("alsacore", "getctls", queryJ, &responseJ); + if (err) { + 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 = CtlGetPrepareResponse(request, responseJ); + if (!halResponse) goto OnErrorExit; + + afb_req_success (request, halResponse, NULL); + return; -OnExit: - // Under normal situation success/failure is set from callback +OnErrorExit: return; }; - // This receive all event this binding subscribe to -PUBLIC void halServiceEvent(const char *evtname, struct json_object *object) { +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, "values" , &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); + } + } + } +} - AFB_NOTICE("afbBindingV1ServiceEvent evtname=%s [msg=%s]", evtname, json_object_get_string(object)); +STATIC int UpdateOneSndCtl (alsaHalCtlMapT *ctl, struct json_object *sndCtlJ) { + struct json_object *tmpJ, *ctlJ; + + AFB_NOTICE ("*** %s, ", json_object_get_string(sndCtlJ)); + + // make sure we face a valid Alsa Low level ctl + if (!json_object_object_get_ex (sndCtlJ, "ctrl" , &ctlJ)) return -1; + + json_object_object_get_ex (sndCtlJ, "name" , &tmpJ); + ctl->name = (char*)json_object_get_string(tmpJ); + + json_object_object_get_ex (sndCtlJ, "numid" , &tmpJ); + ctl->numid = json_object_get_int(tmpJ); + + + 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); + + return 0; } // this is call when after all bindings are loaded PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard) { - int ok, err; + int err; struct json_object *queryurl, *responseJ, *devidJ, *ctlsJ, *tmpJ; halCtls = alsaHalSndCard->ctls; // Get sndcard specific HAL control mapping @@ -236,39 +346,48 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar 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)); - ok= afb_service_call_sync ("alsacore", "registerHal", queryurl, &responseJ); + err= afb_service_call_sync ("alsacore", "halregister", queryurl, &responseJ); json_object_put(queryurl); - if (!ok) { - NOTICE ("Fail to register HAL to ALSA lowlevel binding Response=[%s]", json_object_get_string(responseJ)); + if (err) { + AFB_NOTICE ("Fail to register HAL to ALSA lowlevel binding Response=[%s]", json_object_get_string(responseJ)); goto OnErrorExit; } - // extract sound devid from HAL registration + // 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 devid return from HAL registration Response=[%s]", json_object_get_string(responseJ)); + 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 + halDevid = 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].alsa.numid != 0; idx++) { + for (int idx= 0; (halCtls[idx].ctl.name||halCtls[idx].ctl.numid); idx++) { struct json_object *ctlJ; - if (halCtls[idx].alsa.numid != 0 || halCtls[idx].cb.callback != NULL) { + + // map HAL ctlTad with halCrlLabel to simplify set/get ctl operations using Labels + halCtls[idx].label = halCtlsLabels[halCtls[idx].tag]; + + if (halCtls[idx].cb.callback != NULL) { + ctlJ = json_object_new_object(); + 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)); + json_object_array_add(ctlsJ, ctlJ); + } else { ctlJ = json_object_new_object(); - if (halCtls[idx].alsa.name) json_object_object_add(ctlJ, "name" , json_object_new_string(halCtls[idx].alsa.name)); - if (halCtls[idx].alsa.numid) json_object_object_add(ctlJ, "numid" , json_object_new_int(halCtls[idx].alsa.numid)); - if (halCtls[idx].alsa.minval) json_object_object_add(ctlJ, "minval", json_object_new_int(halCtls[idx].alsa.minval)); - if (halCtls[idx].alsa.maxval) json_object_object_add(ctlJ, "maxval", json_object_new_int(halCtls[idx].alsa.maxval)); - if (halCtls[idx].alsa.step) json_object_object_add(ctlJ, "step" , json_object_new_int(halCtls[idx].alsa.step)); - if (halCtls[idx].alsa.type) json_object_object_add(ctlJ, "type" , json_object_new_int(halCtls[idx].alsa.type)); + if (halCtls[idx].ctl.numid) json_object_object_add(ctlJ, "numid" , 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); } } @@ -276,16 +395,37 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar // 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, "ctls",ctlsJ); - ok= afb_service_call_sync ("alsacore", "addcustomctl", queryurl, &responseJ); - if (!ok) { + 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"); @@ -302,9 +442,8 @@ PUBLIC int halServiceInit (const char *apiPrefix, alsaHalSndCardT *alsaHalSndCar PUBLIC afb_verb_v2 halServiceApi[] = { /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ { .verb = "ping", .callback = pingtest}, + { .verb = "listctls", .callback = halListCtls}, { .verb = "getctls", .callback = halGetCtls}, - { .verb = "setvol", .callback = halSetVol}, - { .verb = "getvol", .callback = halGetVol}, { .verb = "subscribe", .callback = halSubscribe}, { .verb = NULL} /* marker for end of the array */ }; diff --git a/HAL-afb/HAL-interface/hal-interface.h b/HAL-afb/HAL-interface/hal-interface.h index 16da901..2cd3586 100644 --- a/HAL-afb/HAL-interface/hal-interface.h +++ b/HAL-afb/HAL-interface/hal-interface.h @@ -24,14 +24,13 @@ #include "audio-interface.h" typedef struct { - halCtlsEnumT control; char* name; int numid; - halGroupEnumT group; int values; int minval; int maxval; int step; + int count; snd_ctl_elem_type_t type; halAclEnumT acl; } alsaHalCtlMapT; @@ -40,19 +39,21 @@ typedef struct { typedef struct afb_service alsaHalServiceT; typedef struct { - struct json_object* (*callback)(alsaHalCtlMapT *control, void* handle); + struct json_object* (*callback)(alsaHalCtlMapT *control, void* handle, struct json_object *valuesJ); void* handle; } alsaHalCbMapT; typedef struct { - alsaHalCtlMapT alsa; + halCtlsEnumT tag; + const char *label; + alsaHalCtlMapT ctl; alsaHalCbMapT cb; char* info; } alsaHalMapT; typedef const struct { - const char *name; + char *name; const char *info; alsaHalMapT *ctls; } alsaHalSndCardT; diff --git a/HAL-afb/HAL-plugin/CMakeLists.txt b/HAL-afb/HAL-plugin/CMakeLists.txt index 5923935..93642b2 100644 --- a/HAL-afb/HAL-plugin/CMakeLists.txt +++ b/HAL-afb/HAL-plugin/CMakeLists.txt @@ -16,7 +16,7 @@ # limitations under the License. ########################################################################### -# Needed to remove undefined snd_dlsym_start in plugin share object +# Activate ALSA dynamic build build mode get resolve "snd_dlsym_start" add_compile_options(-DPIC) # Add target to project dependency list diff --git a/HAL-afb/HDA-intel/IntelHdaHAL.c b/HAL-afb/HDA-intel/IntelHdaHAL.c index f394fd6..66f241f 100644 --- a/HAL-afb/HDA-intel/IntelHdaHAL.c +++ b/HAL-afb/HDA-intel/IntelHdaHAL.c @@ -25,28 +25,27 @@ #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle) { - static int powerStatus=0; +STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { + struct json_object *reponseJ; - if (! powerStatus) { - powerStatus = 1; - AFB_DEBUG ("Power Set to On"); - } else { - powerStatus = 0; - AFB_DEBUG ("Power Set to Off"); - } + AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); - return NULL; + 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[]= { - { .alsa={.control=Master_Playback_Volume,.numid=16, .name="Master-Vol" , .values=1,.minval=0,.maxval= 87 ,.step=0}, .info= "Master Playback Volume" }, - { .alsa={.control=PCM_Playback_Volume ,.numid=27, .name="Play-Vol" , .values=2,.minval=0,.maxval= 255,.step=0}, .info= "PCM Playback Volume" }, - { .alsa={.control=PCM_Playback_Switch ,.numid=17, .name="Play-Switch" , .values=1,.minval=0,.maxval= 1 ,.step=0}, .info= "Master Playback Switch" }, - { .alsa={.control=Capture_Volume ,.numid=12, .name="Capt-vol" , .values=2,.minval=0,.maxval= 31 ,.step=0}, .info= "Capture Volume" }, - { .alsa={.control=Master_OnOff_Switch ,.numid=99, .name="Power-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}, .info= "OnOff Global Switch"}, - { .alsa={.numid=0}, .cb={.callback=NULL, .handle=NULL}} /* marker for end of the array */ + { .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=EndHalCrlTag} /* marker for end of the array */ } ; // HAL sound card mapping info diff --git a/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c b/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c index 3b9ee4c..99db443 100644 --- a/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c +++ b/HAL-afb/Scarlett-Focusrite/ScarlettUsbHAL.c @@ -17,36 +17,34 @@ * * To find out which control your sound card uses * aplay -l # Check sndcard name name in between [] - * amixer -D hw:xx controls # get supported controls - * amixer -D "hw:4" cget numid=xx # get control settings + * amixer -D hw:USB controls # get supported controls + * amixer -Dhw:USB cget name=Power-Switch * */ #define _GNU_SOURCE #include "hal-interface.h" #include "audio-interface.h" -STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle) { - static int powerStatus=0; +STATIC struct json_object* MasterOnOff (alsaHalCtlMapT *control, void* handle, struct json_object *valJ) { + struct json_object *reponseJ; - if (! powerStatus) { - powerStatus = 1; - AFB_DEBUG ("Power Set to On"); - } else { - powerStatus = 0; - AFB_DEBUG ("Power Set to Off"); - } + AFB_INFO ("Power Set value=%s", json_object_get_string(valJ)); - return NULL; + 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[]= { - { .alsa={.control=Master_Playback_Volume,.numid=04, .name="Matrix 03 Mix A Playback Volume" , .values=1,.minval=0,.maxval= 87 ,.step=0}, .info= "Master Playback Volume" }, - { .alsa={.control=PCM_Playback_Volume ,.numid=06, .name="play-vol" , .values=2,.minval=0,.maxval= 255,.step=0}, .info= "PCM Playback Volume" }, - { .alsa={.control=PCM_Playback_Switch ,.numid=05, .name="play-switch" , .values=1,.minval=0,.maxval= 1 ,.step=0}, .info= "Master Playback Switch" }, - { .alsa={.control=Capture_Volume ,.numid=12, .name="capt-vol" , .values=2,.minval=0,.maxval= 31 ,.step=0}, .info= "Capture Volume" }, - { .alsa={.control=Master_OnOff_Switch, .name="Power-Switch"}, .cb={.callback=MasterOnOff, .handle=NULL}, .info= "OnOff Global Switch"}, - { .alsa={.numid=0}, .cb={.callback=NULL, .handle=NULL}} /* marker for end of the array */ + { .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="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=EndHalCrlTag} /* marker for end of the array */ } ; // HAL sound card mapping info diff --git a/Shared-Interface/audio-interface.h b/Shared-Interface/audio-interface.h index 4fbda4b..8cbea6f 100644 --- a/Shared-Interface/audio-interface.h +++ b/Shared-Interface/audio-interface.h @@ -58,6 +58,7 @@ typedef enum { // HighLevel Audio Control List Master_Playback_Volume, Master_OnOff_Switch, + Master_Playback_Ramp, PCM_Playback_Volume, PCM_Playback_Switch, Capture_Volume, @@ -65,6 +66,7 @@ typedef enum { EndHalCrlTag // used to compute number of ctls } halCtlsEnumT; + PUBLIC int cbCheckResponse(struct afb_req request, int iserror, struct json_object *result) ; PUBLIC void pingtest(struct afb_req request); diff --git a/htdocs/AudioBinding.js b/htdocs/AudioBinding.js index e830861..9771726 100644 --- a/htdocs/AudioBinding.js +++ b/htdocs/AudioBinding.js @@ -16,7 +16,10 @@ // default soundcard is "PCH" var devid=getParameterByName("devid"); - if (!devid) devid="hw:0"; + if (!devid) devid="hw:1"; + + var haldev=getParameterByName("haldev"); + if (!haldev) haldev="scarlett-usb"; var sndname=getParameterByName("sndname"); if (!sndname) sndname="PCH"; diff --git a/htdocs/alsa-core.html b/htdocs/alsa-core.html index 6483180..7fff3d8 100644 --- a/htdocs/alsa-core.html +++ b/htdocs/alsa-core.html @@ -20,6 +20,7 @@
  • +

  • diff --git a/htdocs/alsa-hal.html b/htdocs/alsa-hal.html new file mode 100644 index 0000000..15c1661 --- /dev/null +++ b/htdocs/alsa-hal.html @@ -0,0 +1,34 @@ + + + Basic Audio Hardware Abstraction Layer Test + + + + + references +
      +
    1. http://localhost:1234/alsa-core.html?haldev=scarlett-usb
    2. +
    + + +

    Hello world test

    + +
    +
      +
    1. + +
    2. +
      +
    3. +
    4. +
    5. +
      +
    + + diff --git a/htdocs/index.html b/htdocs/index.html index 330ef4d..2d2b4ae 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -5,4 +5,5 @@

    audio-bindings test

    1. AlsaCore Low Level Binding +
    2. AlsaHAL Hardware Abstraction Layer
    3. AudioLogic High level business API diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 0e58cd5..c02fba8 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -9,20 +9,6 @@ Alsa-SetGet.c Alsa-Ucm.c - - - - - CMakeCCompilerId.c - - - CMakeCXXCompilerId.cpp - - - feature_tests.c - feature_tests.cxx - - AudioCommonLib.c @@ -82,17 +68,18 @@ Build/Makefile - + GNU|GNU false false - - + + + true @@ -111,24 +98,37 @@ - + + ../../../opt/include ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c + Shared-Interface build/ALSA-afb + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + MAX_SND_CARD=16 + alsa_lowlevel_EXPORTS + - + + ../../../opt/include/afb + ALSA-afb build/ALSA-afb - + + ../../../opt/include/afb + ALSA-afb ../../../opt/include/alsa /usr/include/json-c build/ALSA-afb @@ -136,8 +136,10 @@ - + + ../../../opt/include/afb + ALSA-afb ../../../opt/include/alsa /usr/include/json-c build/ALSA-afb @@ -145,8 +147,10 @@ - + + ../../../opt/include/afb + ALSA-afb ../../../opt/include/alsa /usr/include/json-c ../../../opt/include @@ -155,66 +159,48 @@ - + - + - - + + ../../../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/afb ../../../opt/include - ../../../opt/include/alsa - /usr/include/p11-kit-1 - /usr/include/json-c build/HAL-afb/HAL-plugin - - PIC - ctl_afbhal_EXPORTS - - ../../../opt/include/afb - HAL-afb/HAL-plugin - ../../../opt/include/alsa build/HAL-afb/HAL-plugin - + - + @@ -271,17 +257,9 @@ - + - - - - ../../../opt/include/afb - ALSA-afb - - - @@ -312,18 +290,29 @@ - HAL-afb/HAL-interface + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c + HAL-afb/HAL-interface Shared-Interface - ../../../opt/include build/HAL-afb/HAL-interface + + + + HAL-afb/HAL-plugin + ../../../opt/include/alsa + + + HAL-afb/HDA-intel + ../../../opt/include/alsa Shared-Interface HAL-afb/HAL-interface ../../../opt/include @@ -335,6 +324,7 @@ HAL-afb/Scarlett-Focusrite + ../../../opt/include/alsa Shared-Interface HAL-afb/HAL-interface ../../../opt/include @@ -648,7 +638,6 @@ - true @@ -667,47 +656,23 @@ - - - ../../../opt/include/alsa - /usr/include/json-c - build/ALSA-afb - + - - - build/ALSA-afb - + - - - ../../../opt/include/alsa - /usr/include/json-c - build/ALSA-afb - + - - - ../../../opt/include/alsa - /usr/include/json-c - build/ALSA-afb - + - - - ../../../opt/include/alsa - /usr/include/json-c - ../../../opt/include - build/ALSA-afb - + @@ -718,7 +683,7 @@ ex="false" tool="0" flavor2="3"> - + @@ -737,20 +702,23 @@ - + - ../../../opt/include/afb - HAL-afb/HAL-plugin - ../../../opt/include/alsa ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c build/HAL-afb/HAL-plugin + + PIC + ctl_afbhal_EXPORTS + - ../../../opt/include/afb HAL-afb/HAL-plugin ../../../opt/include/alsa build/HAL-afb/HAL-plugin @@ -758,14 +726,14 @@ - + - + @@ -822,15 +790,25 @@ - + - ../../../opt/include/afb - ALSA-afb + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 + /usr/include/json-c + Shared-Interface + build/ALSA-afb + + CONTROL_CDEV_RX="/dev/inic-usb-crx" + CONTROL_CDEV_TX="/dev/inic-usb-ctx" + MAX_SND_CARD=16 + alsa_lowlevel_EXPORTS + @@ -863,11 +841,12 @@ - HAL-afb/HAL-interface + ../../../opt/include ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c + HAL-afb/HAL-interface Shared-Interface - ../../../opt/include build/HAL-afb/HAL-interface @@ -875,25 +854,33 @@ - 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 + + 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 + + hal_scalett_usb_EXPORTS + @@ -907,11 +894,18 @@ - ../../../opt/include/afb - Shared-Interface + ../../../opt/include + ../../../opt/include/alsa + /usr/include/p11-kit-1 /usr/include/json-c + Shared-Interface 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 b9aee19..442a905 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -14,7 +14,7 @@ - Default + Amixer-Dhw_4 0 -- cgit 1.2.3-korg