From c326a053cdf8a4a9ce0fb02448293b45083d553c Mon Sep 17 00:00:00 2001 From: fulup Date: Sat, 1 Jul 2017 00:22:00 +0200 Subject: Ongoing work --- ALSA-afb/Alsa-AddCtl.c | 54 +++++++- ALSA-afb/Alsa-ApiHat.c | 8 +- ALSA-afb/Alsa-ApiHat.h | 23 +++- ALSA-afb/Alsa-RegEvt.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++ ALSA-afb/Alsa-SetGet.c | 318 ++---------------------------------------------- ALSA-afb/Alsa-Ucm.c | 12 +- ALSA-afb/CMakeLists.txt | 2 +- 7 files changed, 399 insertions(+), 327 deletions(-) create mode 100644 ALSA-afb/Alsa-RegEvt.c (limited to 'ALSA-afb') diff --git a/ALSA-afb/Alsa-AddCtl.c b/ALSA-afb/Alsa-AddCtl.c index 7593f2d..2edec5f 100644 --- a/ALSA-afb/Alsa-AddCtl.c +++ b/ALSA-afb/Alsa-AddCtl.c @@ -67,7 +67,7 @@ STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) // set info event ID and get value snd_ctl_elem_info_alloca(&elemInfo); snd_ctl_elem_info_set_name (elemInfo, ctlName); // map ctlInfo to ctlId elemInfo is updated !!! - snd_ctl_elem_info_set_numid(elemInfo, ctlNumid); // map ctlInfo to ctlId elemInfo is updated !!! + snd_ctl_elem_info_set_numid(elemInfo, ctlNumid); // map ctlInfo to ctlId elemInfo is updated !!! if (snd_ctl_elem_info(ctlDev, elemInfo) >= 0) { afb_req_fail_f (request, "ctl-already-exist", "crl=%s name/numid not unique", json_object_to_json_string(ctlJ)); @@ -101,10 +101,58 @@ STATIC int addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_object *ctlJ) afb_req_fail_f (request, "ctl-invalid-type", "crl=%s invalid/unknown type", json_object_to_json_string(ctlJ)); goto OnErrorExit; } - - + return 0; OnErrorExit: return -1; } + +PUBLIC void alsaAddCustomCtls(afb_req request) { + int err; + json_object *ctlsJ; + enum json_type; + snd_ctl_t *ctlDev=NULL; + const char *devid; + + devid = afb_req_value(request, "devid"); + if (devid == NULL) { + afb_req_fail_f (request, "devid-missing", "devid MUST be defined for alsaAddCustomCtls"); + goto OnErrorExit; + } + + // open control interface for devid + err = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY); + if (err < 0) { + afb_req_fail_f (request, "devid-unknown", "SndCard devid=[%s] Not Found err=%s", devid, snd_strerror(err)); + goto OnErrorExit; + } + + // extract sound controls and parse json + ctlsJ = json_tokener_parse (afb_req_value(request, "ctls")); + if (!ctlsJ) { + afb_req_fail_f (request, "ctls-missing", "ctls MUST be defined as a JSON array for alsaAddCustomCtls"); + goto OnErrorExit; + } + + switch (json_object_get_type(ctlsJ)) { + case json_type_object: + addOneSndCtl(request, ctlDev, ctlsJ); + break; + + case json_type_array: + for (int idx= 1; idx < json_object_array_length (ctlsJ); idx++) { + json_object *ctlJ = json_object_array_get_idx (ctlsJ, idx); + addOneSndCtl(request, ctlDev, ctlJ) ; + } + break; + + default: + afb_req_fail_f (request, "ctls-invalid","ctls=%s not valid JSON array", json_object_to_json_string(ctlsJ)); + goto OnErrorExit; + } + + OnErrorExit: + if (ctlDev) snd_ctl_close(ctlDev); + return; +} \ No newline at end of file diff --git a/ALSA-afb/Alsa-ApiHat.c b/ALSA-afb/Alsa-ApiHat.c index ced5d50..588e91b 100644 --- a/ALSA-afb/Alsa-ApiHat.c +++ b/ALSA-afb/Alsa-ApiHat.c @@ -31,13 +31,13 @@ /* * array of the verbs exported to afb-daemon */ -static const struct afb_verb_v2 binding_verbs[] = { +static const struct afb_verb_v2 api_verbs[] = { /* VERB'S NAME FUNCTION TO CALL */ { .verb= "ping" , .callback= pingtest }, { .verb= "getinfo", .callback= alsaGetInfo}, { .verb= "getctls", .callback= alsaGetCtls}, { .verb= "setctls", .callback= alsaSetCtls}, - { .verb= "subscribe", .callback= alsaSubcribe}, + { .verb= "subscribe", .callback= alsaEvtSubcribe}, { .verb= "getcardid", .callback= alsaGetCardId}, { .verb= "registerHal", .callback= alsaRegisterHal}, { .verb= "ucmquery", .callback= alsaUseCaseQuery}, @@ -45,7 +45,7 @@ static const struct afb_verb_v2 binding_verbs[] = { { .verb= "ucmget", .callback= alsaUseCaseGet}, { .verb= "ucmreset", .callback= alsaUseCaseReset}, { .verb= "ucmclose", .callback= alsaUseCaseClose}, - { .verb= "addctl", .callback= alsaAddCustomCtl}, + { .verb= "addcustomctl",.callback= alsaAddCustomCtls}, { .verb= NULL } /* marker for end of the array */ }; @@ -54,5 +54,5 @@ static const struct afb_verb_v2 binding_verbs[] = { */ const struct afb_binding_v2 afbBindingV2 = { .api = "alsacore", - .verbs = binding_verbs, + .verbs = api_verbs, }; diff --git a/ALSA-afb/Alsa-ApiHat.h b/ALSA-afb/Alsa-ApiHat.h index c33f92e..bd8518f 100644 --- a/ALSA-afb/Alsa-ApiHat.h +++ b/ALSA-afb/Alsa-ApiHat.h @@ -19,6 +19,9 @@ #ifndef ALSALIBMAPPING_H #define ALSALIBMAPPING_H + +#include +#include #include "audio-interface.h" typedef enum { @@ -34,17 +37,24 @@ typedef struct { int count; } queryValuesT; +// use to store crl numid user request +typedef struct { + unsigned int numId; + json_object *jToken; + json_object *jValues; + int used; +} ctlRequestT; + // import from AlsaAfbBinding extern const struct afb_binding_interface *afbIface; PUBLIC int alsaCheckQuery (struct afb_req request, queryValuesT *queryValues); // AlseCoreSetGet exports +PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest, int quiet); PUBLIC void alsaGetInfo (struct afb_req request); PUBLIC void alsaGetCtls(struct afb_req request); PUBLIC void alsaSetCtls(struct afb_req request); -PUBLIC void alsaSubcribe (struct afb_req request); -PUBLIC void alsaGetCardId (struct afb_req request); -PUBLIC void alsaRegisterHal (struct afb_req request); + // AlsaUseCase exports PUBLIC void alsaUseCaseQuery(struct afb_req request); @@ -52,9 +62,12 @@ PUBLIC void alsaUseCaseSet(struct afb_req request); PUBLIC void alsaUseCaseGet(struct afb_req request); PUBLIC void alsaUseCaseClose(struct afb_req request); PUBLIC void alsaUseCaseReset(struct afb_req request); -PUBLIC void alsaAddCustomCtl(struct afb_req request); - +PUBLIC void alsaAddCustomCtls(struct afb_req request); +// AlsaRegEvt +PUBLIC void alsaEvtSubcribe (struct afb_req request); +PUBLIC void alsaGetCardId (struct afb_req request); +PUBLIC void alsaRegisterHal (struct afb_req request); #endif /* ALSALIBMAPPING_H */ diff --git a/ALSA-afb/Alsa-RegEvt.c b/ALSA-afb/Alsa-RegEvt.c new file mode 100644 index 0000000..e06cf87 --- /dev/null +++ b/ALSA-afb/Alsa-RegEvt.c @@ -0,0 +1,309 @@ +/* + * AlsaLibMapping -- provide low level interface with ALSA lib (extracted from alsa-json-gateway code) + * Copyright (C) 2015,2016,2017, Fulup Ar Foll fulup@iot.bzh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + +*/ + +#define _GNU_SOURCE // needed for vasprintf + +#include "Alsa-ApiHat.h" + +// generic sndctrl event handle hook to event callback when pooling +typedef struct { + struct pollfd pfds; + sd_event_source *src; + snd_ctl_t *ctlDev; + int quiet; + struct afb_event afbevt; +} evtHandleT; + +typedef struct { + int ucount; + int cardId; + evtHandleT *evtHandle; +} sndHandleT; + +typedef struct { + char *apiprefix; + char *shortname; +}cardRegistryT; + +cardRegistryT *cardRegistry[MAX_SND_CARD+1]; + +// 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; + evtHandleT *evtHandle = (evtHandleT*)userData; + snd_ctl_event_t *eventId; + json_object *ctlEventJ; + unsigned int mask; + int iface; + int device; + int subdev; + const char*devname; + ctlRequestT ctlRequest; + snd_ctl_elem_id_t *elemId; + + if ((revents & EPOLLHUP) != 0) { + AFB_NOTICE( "SndCtl hanghup [car disconnected]"); + goto ExitOnSucess; + } + + if ((revents & EPOLLIN) != 0) { + + // initialise event structure on stack + snd_ctl_event_alloca(&eventId); + snd_ctl_elem_id_alloca(&elemId); + + err = snd_ctl_read(evtHandle->ctlDev, eventId); + if (err < 0) goto OnErrorExit; + + // we only process sndctrl element + if (snd_ctl_event_get_type(eventId) != SND_CTL_EVENT_ELEM) goto ExitOnSucess; + + // we only process value changed events + mask = snd_ctl_event_elem_get_mask(eventId); + if (!(mask & SND_CTL_EVENT_MASK_VALUE)) goto ExitOnSucess; + + snd_ctl_event_elem_get_id (eventId, elemId); + + err = alsaGetSingleCtl (evtHandle->ctlDev, elemId, &ctlRequest, evtHandle->quiet); + if (err) goto OnErrorExit; + + 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->quiet < 2) { + json_object_object_add(ctlEventJ, "iface" ,json_object_new_int (iface)); + json_object_object_add(ctlEventJ, "devname",json_object_new_string (devname)); + } + if (ctlRequest.jValues) (json_object_object_add(ctlEventJ, "values" ,ctlRequest.jValues)); + AFB_DEBUG( "sndCtlEventCB=%s", json_object_get_string(ctlEventJ)); + afb_event_push(evtHandle->afbevt, ctlEventJ); + } + + ExitOnSucess: + return 0; + + OnErrorExit: + WARNING ("sndCtlEventCB: ignored unsupported event type"); + return (0); +} + +// Subscribe to every Alsa CtlEvent send by a given board +PUBLIC void alsaEvtSubcribe (afb_req request) { + static sndHandleT sndHandles[MAX_SND_CARD]; + evtHandleT *evtHandle; + snd_ctl_t *ctlDev; + int err, idx, cardId, idxFree=-1; + snd_ctl_card_info_t *cardinfo; + queryValuesT queryValues; + + + err = alsaCheckQuery (request, &queryValues); + if (err) goto OnErrorExit; + + + // 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; + } + + snd_ctl_card_info_alloca(&cardinfo); + if ((err = snd_ctl_card_info(ctlDev, cardinfo)) < 0) { + afb_req_fail_f (request, "devid-invalid", "SndCard devid=%s Not Found err=%s", queryValues.devid, snd_strerror(err)); + goto OnErrorExit; + } + + cardId=snd_ctl_card_info_get_card(cardinfo); + + // search for an existing subscription and mark 1st free slot + for (idx= 0; idx < MAX_SND_CARD; idx ++) { + if (sndHandles[idx].ucount > 0 && cardId == sndHandles[idx].cardId) { + evtHandle= sndHandles[idx].evtHandle; + break; + } else if (idxFree == -1) idxFree= idx; + }; + + // if not subscription exist for the event let's create one + if (idx == MAX_SND_CARD) { + + // reach MAX_SND_CARD event registration + if (idxFree == -1) { + afb_req_fail_f (request, "register-toomany", "Cannot register new event Maxcard==%d", idx); + goto OnErrorExit; + } + + evtHandle = malloc (sizeof(evtHandleT)); + evtHandle->ctlDev = ctlDev; + evtHandle->quiet = queryValues.quiet; + sndHandles[idxFree].ucount = 0; + sndHandles[idxFree].cardId = cardId; + sndHandles[idxFree].evtHandle = evtHandle; + + // subscribe for sndctl events attached to devid + err = snd_ctl_subscribe_events(evtHandle->ctlDev, 1); + if (err < 0) { + afb_req_fail_f (request, "subscribe-fail", "Cannot subscribe events from devid=%s err=%d", queryValues.devid, err); + goto OnErrorExit; + } + + // get pollfd attach to this sound board + snd_ctl_poll_descriptors(evtHandle->ctlDev, &evtHandle->pfds, 1); + + // register sound event to binder main loop + err = sd_event_add_io(afb_daemon_get_event_loop(), &evtHandle->src, evtHandle->pfds.fd, EPOLLIN, sndCtlEventCB, evtHandle); + if (err < 0) { + afb_req_fail_f (request, "register-mainloop", "Cannot hook events to mainloop devid=%s err=%d", queryValues.devid, err); + goto OnErrorExit; + } + + // create binder event attached to devid name + evtHandle->afbevt = afb_daemon_make_event (queryValues.devid); + if (!afb_event_is_valid (evtHandle->afbevt)) { + afb_req_fail_f (request, "register-event", "Cannot register new binder event name=%s", queryValues.devid); + goto OnErrorExit; + } + + // everything looks OK let's move forward + idx=idxFree; + } + + // subscribe to binder event + err = afb_req_subscribe(request, evtHandle->afbevt); + if (err != 0) { + afb_req_fail_f (request, "register-eventname", "Cannot subscribe binder event name=%s [invalid channel]", queryValues.devid); + goto OnErrorExit; + } + + // increase usage count and return success + sndHandles[idx].ucount ++; + afb_req_success(request, NULL, NULL); + return; + + OnErrorExit: + if (ctlDev) snd_ctl_close(ctlDev); + return; +} + +// Subscribe to every Alsa CtlEvent send by a given board +PUBLIC void alsaGetCardId (afb_req request) { + char devid [10]; + const char *devname, *shortname, *longname; + int card, err, index, idx; + json_object *respJson; + snd_ctl_t *ctlDev; + snd_ctl_card_info_t *cardinfo; + + const char *sndname = afb_req_value(request, "sndname"); + if (sndname == NULL) { + afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); + goto OnErrorExit; + } + + // loop on potential card number + snd_ctl_card_info_alloca(&cardinfo); + for (card =0; card < MAX_SND_CARD; card++) { + + // build card devid and probe it + snprintf (devid, sizeof(devid), "hw:%i", card); + + // open control interface for devid + err = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY); + if (err < 0) continue; + + // 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); + 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, shortname)) break; + if (!strcmp (sndname, longname)) break; + } + + if (card == MAX_SND_CARD) { + afb_req_fail_f (request, "ctlDev-notfound", "Fail to find card with name=%s", sndname); + goto OnErrorExit; + } + + // 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)); + + // 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; + } + // 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); + return; + + OnErrorExit: + return; +} + +// Register loaded HAL with board Name and API prefix +PUBLIC void alsaRegisterHal (afb_req request) { + static int index=0; + const char *shortname, *apiPrefix; + + apiPrefix = afb_req_value(request, "prefix"); + if (apiPrefix == NULL) { + afb_req_fail_f (request, "argument-missing", "prefix=BindingApiPrefix missing"); + goto OnErrorExit; + } + + shortname = afb_req_value(request, "sndname"); + if (shortname == NULL) { + afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); + goto OnErrorExit; + } + + if (index == MAX_SND_CARD) { + afb_req_fail_f (request, "alsahal-toomany", "Fail to register sndname=[%s]", shortname); + goto OnErrorExit; + } + + 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); + return; + + OnErrorExit: + return; +} + diff --git a/ALSA-afb/Alsa-SetGet.c b/ALSA-afb/Alsa-SetGet.c index d6cf50d..280078c 100644 --- a/ALSA-afb/Alsa-SetGet.c +++ b/ALSA-afb/Alsa-SetGet.c @@ -26,41 +26,8 @@ #define _GNU_SOURCE // needed for vasprintf -#include -#include - #include "Alsa-ApiHat.h" -// use to store crl numid user request -typedef struct { - unsigned int numId; - json_object *jToken; - json_object *jValues; - int used; -} ctlRequestT; - -// generic sndctrl event handle hook to event callback when pooling -typedef struct { - struct pollfd pfds; - sd_event_source *src; - snd_ctl_t *ctlDev; - int quiet; - struct afb_event afbevt; -} evtHandleT; - -typedef struct { - int ucount; - int cardId; - evtHandleT *evtHandle; -} sndHandleT; - -typedef struct { - char *apiprefix; - char *shortname; -}cardRegistryT; - -cardRegistryT *cardRegistry[MAX_SND_CARD+1]; - PUBLIC void NumidsListParse (queryValuesT *queryValues, ctlRequestT *ctlRequest) { json_object *jValues; int length; @@ -103,7 +70,7 @@ PUBLIC void NumidsListParse (queryValuesT *queryValues, ctlRequestT *ctlRequest) case json_type_object: // numid+values formated as {id:xxx, val:[aa,bb...,nn]} if (!json_object_object_get_ex (ctlRequest[idx].jToken,"id", &jId) || !json_object_object_get_ex (ctlRequest[idx].jToken,"val",&jVal)) { - NOTICE("Invalid Json=%s missing 'id'|'val'", json_object_get_string(ctlRequest[idx].jToken)); + AFB_NOTICE("Invalid Json=%s missing 'id'|'val'", json_object_get_string(ctlRequest[idx].jToken)); ctlRequest[idx].used=-1; } else { ctlRequest[idx].numId =json_object_get_int(jId); @@ -478,7 +445,7 @@ STATIC json_object *getControlAcl (snd_ctl_elem_info_t *info) { } // process ALSA control and store resulting value into ctlRequest -STATIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest) { +PUBLIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest) { snd_ctl_elem_value_t *elemData; snd_ctl_elem_info_t *elemInfo; int count, length, err, valueIsArray; @@ -490,13 +457,13 @@ STATIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe snd_ctl_elem_info_alloca(&elemInfo); snd_ctl_elem_info_set_id(elemInfo, elemId); // map ctlInfo to ctlId elemInfo is updated !!! if (snd_ctl_elem_info(ctlDev, elemInfo) < 0) { - NOTICE( "Fail to load ALSA NUMID=%d Values=[%s]", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues)); + AFB_NOTICE( "Fail to load ALSA NUMID=%d Values=[%s]", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues)); 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)) { - NOTICE( "Not Writable ALSA NUMID=%d Values=[%s]", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues)); + AFB_NOTICE( "Not Writable ALSA NUMID=%d Values=[%s]", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues)); goto OnErrorExit; } @@ -515,12 +482,13 @@ STATIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe break; default: count =0; + length = 0; break; } if (count == 0 || count < length) { - NOTICE( "Invalid values NUMID='%d' Values='%s' count='%d' wanted='%d'", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues), length, count); + AFB_NOTICE( "Invalid values NUMID='%d' Values='%s' count='%d' wanted='%d'", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues), length, count); goto OnErrorExit; } @@ -542,7 +510,7 @@ STATIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe err = snd_ctl_elem_write(ctlDev, elemData); if (err < 0) { - NOTICE( "Fail to write ALSA NUMID=%d Values=[%s] Error=%s", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues), snd_strerror(err)); + AFB_NOTICE( "Fail to write ALSA NUMID=%d Values=[%s] Error=%s", ctlRequest->numId, json_object_to_json_string(ctlRequest->jValues), snd_strerror(err)); goto OnErrorExit; } @@ -555,7 +523,7 @@ STATIC int alsaSetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe } // process ALSA control and store then into ctlRequest -STATIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest, int quiet) { +PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest, int quiet) { snd_ctl_elem_type_t elemType; snd_ctl_elem_value_t *elemData; snd_ctl_elem_info_t *elemInfo; @@ -681,7 +649,7 @@ STATIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRe } // assign multiple control to the same value -PUBLIC void alsaSetGetCtls (afb_req request, ActionSetGetT action) { +STATIC void alsaSetGetCtls (afb_req request, ActionSetGetT action) { ctlRequestT *ctlRequest; const char *warmsg=NULL; int err=0, status=0; @@ -736,7 +704,7 @@ PUBLIC void alsaSetGetCtls (afb_req request, ActionSetGetT action) { } else { int numid = snd_ctl_elem_list_get_numid(ctlList, ctlIndex); if (numid < 0) { - NOTICE("snd_ctl_elem_list_get_numid index=%d fail", ctlIndex); + AFB_NOTICE("snd_ctl_elem_list_get_numid index=%d fail", ctlIndex); continue; } // check if current control was requested in query numids list @@ -814,269 +782,3 @@ PUBLIC void alsaSetCtls (afb_req request) { } -// 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; - evtHandleT *evtHandle = (evtHandleT*)userData; - snd_ctl_event_t *eventId; - json_object *ctlEventJ; - unsigned int mask; - int iface; - int device; - int subdev; - const char*devname; - ctlRequestT ctlRequest; - snd_ctl_elem_id_t *elemId; - - if ((revents & EPOLLHUP) != 0) { - NOTICE( "SndCtl hanghup [car disconnected]"); - goto ExitOnSucess; - } - - if ((revents & EPOLLIN) != 0) { - - // initialise event structure on stack - snd_ctl_event_alloca(&eventId); - snd_ctl_elem_id_alloca(&elemId); - - err = snd_ctl_read(evtHandle->ctlDev, eventId); - if (err < 0) goto OnErrorExit; - - // we only process sndctrl element - if (snd_ctl_event_get_type(eventId) != SND_CTL_EVENT_ELEM) goto ExitOnSucess; - - // we only process value changed events - mask = snd_ctl_event_elem_get_mask(eventId); - if (!(mask & SND_CTL_EVENT_MASK_VALUE)) goto ExitOnSucess; - - snd_ctl_event_elem_get_id (eventId, elemId); - - err = alsaGetSingleCtl (evtHandle->ctlDev, elemId, &ctlRequest, evtHandle->quiet); - if (err) goto OnErrorExit; - - 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->quiet < 2) { - json_object_object_add(ctlEventJ, "iface" ,json_object_new_int (iface)); - json_object_object_add(ctlEventJ, "devname",json_object_new_string (devname)); - } - if (ctlRequest.jValues) (json_object_object_add(ctlEventJ, "values" ,ctlRequest.jValues)); - DEBUG( "sndCtlEventCB=%s", json_object_get_string(ctlEventJ)); - afb_event_push(evtHandle->afbevt, ctlEventJ); - - } - - ExitOnSucess: - return 0; - - OnErrorExit: - WARNING ("sndCtlEventCB: ignored unsupported event type"); - return (0); -} - -// Subscribe to every Alsa CtlEvent send by a given board -PUBLIC void alsaSubcribe (afb_req request) { - static sndHandleT sndHandles[MAX_SND_CARD]; - evtHandleT *evtHandle; - snd_ctl_t *ctlDev; - int err, idx, cardId, idxFree=-1; - snd_ctl_card_info_t *cardinfo; - queryValuesT queryValues; - - - err = alsaCheckQuery (request, &queryValues); - if (err) goto OnErrorExit; - - - // 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; - } - - snd_ctl_card_info_alloca(&cardinfo); - if ((err = snd_ctl_card_info(ctlDev, cardinfo)) < 0) { - afb_req_fail_f (request, "devid-invalid", "SndCard devid=%s Not Found err=%s", queryValues.devid, snd_strerror(err)); - goto OnErrorExit; - } - - cardId=snd_ctl_card_info_get_card(cardinfo); - - // search for an existing subscription and mark 1st free slot - for (idx= 0; idx < MAX_SND_CARD; idx ++) { - if (sndHandles[idx].ucount > 0 && cardId == sndHandles[idx].cardId) { - evtHandle= sndHandles[idx].evtHandle; - break; - } else if (idxFree == -1) idxFree= idx; - }; - - // if not subscription exist for the event let's create one - if (idx == MAX_SND_CARD) { - - // reach MAX_SND_CARD event registration - if (idxFree == -1) { - afb_req_fail_f (request, "register-toomany", "Cannot register new event Maxcard==%d", idx); - goto OnErrorExit; - } - - evtHandle = malloc (sizeof(evtHandleT)); - evtHandle->ctlDev = ctlDev; - evtHandle->quiet = queryValues.quiet; - sndHandles[idxFree].ucount = 0; - sndHandles[idxFree].cardId = cardId; - sndHandles[idxFree].evtHandle = evtHandle; - - // subscribe for sndctl events attached to devid - err = snd_ctl_subscribe_events(evtHandle->ctlDev, 1); - if (err < 0) { - afb_req_fail_f (request, "subscribe-fail", "Cannot subscribe events from devid=%s err=%d", queryValues.devid, err); - goto OnErrorExit; - } - - // get pollfd attach to this sound board - snd_ctl_poll_descriptors(evtHandle->ctlDev, &evtHandle->pfds, 1); - - // register sound event to binder main loop - err = sd_event_add_io(afb_daemon_get_event_loop(), &evtHandle->src, evtHandle->pfds.fd, EPOLLIN, sndCtlEventCB, evtHandle); - if (err < 0) { - afb_req_fail_f (request, "register-mainloop", "Cannot hook events to mainloop devid=%s err=%d", queryValues.devid, err); - goto OnErrorExit; - } - - // create binder event attached to devid name - evtHandle->afbevt = afb_daemon_make_event (queryValues.devid); - if (!afb_event_is_valid (evtHandle->afbevt)) { - afb_req_fail_f (request, "register-event", "Cannot register new binder event name=%s", queryValues.devid); - goto OnErrorExit; - } - - // everything looks OK let's move forward - idx=idxFree; - } - - // subscribe to binder event - err = afb_req_subscribe(request, evtHandle->afbevt); - if (err != 0) { - afb_req_fail_f (request, "register-eventname", "Cannot subscribe binder event name=%s [invalid channel]", queryValues.devid); - goto OnErrorExit; - } - - // increase usage count and return success - sndHandles[idx].ucount ++; - afb_req_success(request, NULL, NULL); - return; - - OnErrorExit: - if (ctlDev) snd_ctl_close(ctlDev); - return; -} - -// Subscribe to every Alsa CtlEvent send by a given board -PUBLIC void alsaGetCardId (afb_req request) { - char devid [10]; - const char *devname, *shortname, *longname; - int card, err, index, idx; - json_object *respJson; - snd_ctl_t *ctlDev; - snd_ctl_card_info_t *cardinfo; - - const char *sndname = afb_req_value(request, "sndname"); - if (sndname == NULL) { - afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); - goto OnErrorExit; - } - - // loop on potential card number - snd_ctl_card_info_alloca(&cardinfo); - for (card =0; card < MAX_SND_CARD; card++) { - - // build card devid and probe it - snprintf (devid, sizeof(devid), "hw:%i", card); - - // open control interface for devid - err = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY); - if (err < 0) continue; - - // 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); - 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, shortname)) break; - if (!strcmp (sndname, longname)) break; - } - - if (card == MAX_SND_CARD) { - afb_req_fail_f (request, "ctlDev-notfound", "Fail to find card with name=%s", sndname); - goto OnErrorExit; - } - - // 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)); - - // 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; - } - // 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); - return; - - OnErrorExit: - return; -} - -// Register loaded HAL with board Name and API prefix -PUBLIC void alsaRegisterHal (afb_req request) { - static int index=0; - const char *shortname, *apiPrefix; - - apiPrefix = afb_req_value(request, "prefix"); - if (apiPrefix == NULL) { - afb_req_fail_f (request, "argument-missing", "prefix=BindingApiPrefix missing"); - goto OnErrorExit; - } - - shortname = afb_req_value(request, "name"); - if (shortname == NULL) { - afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); - goto OnErrorExit; - } - - if (index == MAX_SND_CARD) { - afb_req_fail_f (request, "alsahal-toomany", "Fail to register sndname=[%s]", shortname); - goto OnErrorExit; - } - - cardRegistry[index]= malloc (sizeof(cardRegistry)); - cardRegistry[index]->apiprefix=strdup(apiPrefix); - cardRegistry[index]->shortname=strdup(shortname); - index++;cardRegistry[index]=NULL; - - // when OK nothing to return - afb_req_success(request, NULL, NULL); - return; - - OnErrorExit: - return; -} - diff --git a/ALSA-afb/Alsa-Ucm.c b/ALSA-afb/Alsa-Ucm.c index 78a80ad..c9ee4f9 100644 --- a/ALSA-afb/Alsa-Ucm.c +++ b/ALSA-afb/Alsa-Ucm.c @@ -143,7 +143,7 @@ PUBLIC void alsaUseCaseQuery(struct afb_req request) { json_object_object_add (ucmJ, "verb", json_object_new_string(verbList[idx])); if (verbList[idx+1]) json_object_object_add (ucmJ, "info", json_object_new_string(verbList[idx+1])); - DEBUG (afbIface, "Verb[%d] Action=%s Info=%s", idx, verbList[idx], verbList[idx+1]); + AFB_DEBUG ("Verb[%d] Action=%s Info=%s", idx, verbList[idx], verbList[idx+1]); snprintf (identifier, sizeof(identifier), "_devices/%s", verbList[idx]); devCount = snd_use_case_get_list (ucmHandle, identifier, &devList); @@ -152,7 +152,7 @@ PUBLIC void alsaUseCaseQuery(struct afb_req request) { for (int jdx=0; jdx < devCount; jdx+=2) { json_object *devJ = json_object_new_object(); - DEBUG (afbIface, "device[%d] Action=%s Info=%s", jdx, devList[jdx], devList[jdx+1]); + AFB_DEBUG ("device[%d] Action=%s Info=%s", jdx, devList[jdx], devList[jdx+1]); json_object_object_add (devJ, "dev", json_object_new_string(devList[jdx])); if (devList[jdx+1]) json_object_object_add (devJ, "info", json_object_new_string(devList[jdx+1])); json_object_array_add (devsJ, devJ); @@ -168,7 +168,7 @@ PUBLIC void alsaUseCaseQuery(struct afb_req request) { for (int jdx=0; jdx < modCount; jdx+=2) { json_object *modJ = json_object_new_object(); - DEBUG (afbIface, "modifier[%d] Action=%s Info=%s", jdx, modList[jdx], modList[jdx+1]); + AFB_DEBUG ("modifier[%d] Action=%s Info=%s", jdx, modList[jdx], modList[jdx+1]); json_object_object_add (modJ, "mod", json_object_new_string(modList[jdx])); if (modList[jdx+1]) json_object_object_add (modJ, "info", json_object_new_string(modList[jdx+1])); json_object_array_add (modsJ, modJ); @@ -184,7 +184,7 @@ PUBLIC void alsaUseCaseQuery(struct afb_req request) { for (int jdx=0; jdx < tqCount; jdx+=2) { json_object *tqJ = json_object_new_object(); - DEBUG (afbIface, "toneqa[%d] Action=%s Info=%s", jdx, tqList[jdx], tqList[jdx+1]); + AFB_DEBUG ("toneqa[%d] Action=%s Info=%s", jdx, tqList[jdx], tqList[jdx+1]); json_object_object_add (tqJ, "tq", json_object_new_string(tqList[jdx])); if (tqList[jdx+1]) json_object_object_add (tqJ, "info", json_object_new_string(tqList[jdx+1])); json_object_array_add (tqsJ, tqJ); @@ -214,14 +214,14 @@ STATIC json_object *ucmGetValue (ucmHandleT *ucmHandle, const char *verb, const if (!verb) verb=""; if (!label) { - NOTICE (afbIface, "ucmGetValue cardname=[%s] value label missing", ucmHandle->cardName); + AFB_NOTICE ("ucmGetValue cardname=[%s] value label missing", ucmHandle->cardName); goto OnErrorExit; } snprintf (identifier, sizeof(identifier), "%s/%s/%s", label, mod, verb); err = snd_use_case_get (ucmHandle->ucm, identifier, (const char**)&value); // Note: value casting is a known "FEATURE" of AlsaUCM API if (err) { - DEBUG (afbIface, "ucmGetValue cardname=[%s] identifier=[%s] error=%s", ucmHandle->cardName, identifier, snd_strerror (err)); + AFB_DEBUG ("ucmGetValue cardname=[%s] identifier=[%s] error=%s", ucmHandle->cardName, identifier, snd_strerror (err)); goto OnErrorExit; } diff --git a/ALSA-afb/CMakeLists.txt b/ALSA-afb/CMakeLists.txt index 5c62149..4ca7158 100644 --- a/ALSA-afb/CMakeLists.txt +++ b/ALSA-afb/CMakeLists.txt @@ -20,7 +20,7 @@ PROJECT_TARGET_ADD(alsa-lowlevel) # Define project Targets - ADD_LIBRARY(alsa-lowlevel MODULE Alsa-ApiHat.c Alsa-SetGet.c Alsa-Ucm.c Alsa-AddCtl.c) + ADD_LIBRARY(alsa-lowlevel MODULE Alsa-ApiHat.c Alsa-SetGet.c Alsa-Ucm.c Alsa-AddCtl.c Alsa-RegEvt.c) # Binder exposes a unique public entry point SET_TARGET_PROPERTIES(alsa-lowlevel PROPERTIES -- cgit 1.2.3-korg