From 002dccbe68aae864f816f53b6ac92528bd42ab6d Mon Sep 17 00:00:00 2001 From: Jonathan Aillet Date: Wed, 18 Sep 2019 18:04:14 +0200 Subject: Add verb to get PCM availability Add verb to get PCM availability, this verb will return a boolean json. PCM can be specified using two ways : - card & device & subdevice & stream - pcmName & stream BUG-AGL: SPEC-2834 Change-Id: I176fdc261fa117906a2af069d3ddd07d5941904c Signed-off-by: Jonathan Aillet --- alsa-binding/Alsa-ApiHat.c | 1 + alsa-binding/Alsa-ApiHat.h | 7 ++- alsa-binding/Alsa-SetGet.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/alsa-binding/Alsa-ApiHat.c b/alsa-binding/Alsa-ApiHat.c index 5575a9a..13c450c 100644 --- a/alsa-binding/Alsa-ApiHat.c +++ b/alsa-binding/Alsa-ApiHat.c @@ -42,6 +42,7 @@ static const afb_verb_t api_verbs[] = { /* VERB'S NAME FUNCTION TO CALL */ { .verb = "ping", .callback = pingtest, .info="Ping Presence Check on API"}, { .verb = "infoget", .callback = alsaGetInfo, .info="Return sound cards list"}, + { .verb = "pcmready", .callback = alsaGetPcmAvailability, .info="Get Pcm availability"}, { .verb = "ctlget", .callback = alsaGetCtls, .info="Get one or many control values"}, { .verb = "ctlset", .callback = alsaSetCtls, .info="Set one control or more"}, { .verb = "subscribe", .callback = alsaEvtSubscribe, .info="subscribe to alsa events"}, diff --git a/alsa-binding/Alsa-ApiHat.h b/alsa-binding/Alsa-ApiHat.h index 21aaa61..35f96bb 100644 --- a/alsa-binding/Alsa-ApiHat.h +++ b/alsa-binding/Alsa-ApiHat.h @@ -103,8 +103,13 @@ PUBLIC queryModeE alsaGetModeFromQuery(json_object *queryJ); // AlseCoreSetGet exports PUBLIC int getCardNbFromCardPath(char *cardPath); PUBLIC json_object *getCardInfo(int card); -PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest, queryModeE queryMode); PUBLIC void alsaGetInfo (afb_req_t request); +PUBLIC int alsaGetPcmProcStatusFd(unsigned int card, unsigned int device, unsigned int subdevice, snd_pcm_stream_t pcmStream); +PUBLIC int alsaIsPcmAvailableUsingPcmProcFd(int fd); +PUBLIC int alsaIsPcmAvailableUsingId(unsigned int card, unsigned int device, unsigned int subdevice, snd_pcm_stream_t pcmStream); +PUBLIC int alsaIsPcmAvailableUsingPcmName(char *pcmName, snd_pcm_stream_t pcmStream); +PUBLIC void alsaGetPcmAvailability(afb_req_t request); +PUBLIC int alsaGetSingleCtl (snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, ctlRequestT *ctlRequest, queryModeE queryMode); PUBLIC void alsaGetCtls(afb_req_t request); PUBLIC void alsaSetCtls(afb_req_t request); diff --git a/alsa-binding/Alsa-SetGet.c b/alsa-binding/Alsa-SetGet.c index 78ac7e9..af96b86 100644 --- a/alsa-binding/Alsa-SetGet.c +++ b/alsa-binding/Alsa-SetGet.c @@ -37,6 +37,9 @@ #define _IOR_HACKED(type,nr,size) _IOC(_IOC_READ,(type),(nr),size) #define SNDRV_CTL_IOCTL_CARD_INFO(size) _IOR_HACKED('U', 0x01, size) +#define PCM_PROC_STATUS_STRING "/proc/asound/card%i/pcm%i%c/sub%i/status" +#define PCM_PROC_AVAILABLE_PCM_STRING "closed" +#define PCM_PROC_AVAILABLE_PCM_STRING_SIZE (sizeof(PCM_PROC_AVAILABLE_PCM_STRING) - 1) PUBLIC void NumidsListParse(ActionSetGetT action, controlQueryValuesT *queryControlValues, ctlRequestT *ctlRequest) { int length; @@ -999,6 +1002,148 @@ PUBLIC void alsaGetInfo(afb_req_t request) { afb_req_success(request, toReturnJ, "Found requested sound card(s) properties are available in returned Json"); } +STATIC char *getAlsaPcmStatusFilePath(unsigned int card, unsigned int device, unsigned int subdevice, snd_pcm_stream_t stream) +{ + int err; + char *pcmStatusFilePath = NULL; + + if(card > MAX_SND_CARD || device > MAX_CARD_DEVICES || subdevice > MAX_DEVICE_SUBDEVICES) + return NULL; + + err = asprintf(&pcmStatusFilePath, PCM_PROC_STATUS_STRING, card, device, (stream == SND_PCM_STREAM_PLAYBACK) ? 'p' : 'c', subdevice); + if(err <= 0) + return NULL; + + return pcmStatusFilePath; +} + +PUBLIC int alsaGetPcmProcStatusFd(unsigned int card, unsigned int device, unsigned int subdevice, snd_pcm_stream_t pcmStream) +{ + int fd; + + char *pcmStatusFilePath = NULL; + + if(card > MAX_SND_CARD || device > MAX_CARD_DEVICES || subdevice > MAX_DEVICE_SUBDEVICES) + return -1; + + pcmStatusFilePath = getAlsaPcmStatusFilePath(card, device, subdevice, pcmStream); + if(! pcmStatusFilePath) + return -2; + + fd = open(pcmStatusFilePath, O_RDONLY | O_NONBLOCK); + if(fd < 0) + return -3; + + return fd; +} + +PUBLIC int alsaIsPcmAvailableUsingPcmProcFd(int fd) +{ + char statusFileContent[PCM_PROC_AVAILABLE_PCM_STRING_SIZE]; + + if(fd < 0) + return -1; + + if(lseek(fd, 0, SEEK_SET) < 0) + return -2; + + if(read(fd, statusFileContent, PCM_PROC_AVAILABLE_PCM_STRING_SIZE) < 0) + return -3; + + if(! strncmp(statusFileContent, PCM_PROC_AVAILABLE_PCM_STRING, PCM_PROC_AVAILABLE_PCM_STRING_SIZE)) + return 1; + + return 0; +} + +PUBLIC int alsaIsPcmAvailableUsingId(unsigned int card, unsigned int device, unsigned int subdevice, snd_pcm_stream_t pcmStream) +{ + int fd, pcmIsAvailable; + + if(card > MAX_SND_CARD || device > MAX_CARD_DEVICES || subdevice > MAX_DEVICE_SUBDEVICES) + return -1; + + fd = alsaGetPcmProcStatusFd(card, device, subdevice, pcmStream); + if(fd < 0) + return -2; + + pcmIsAvailable = alsaIsPcmAvailableUsingPcmProcFd(fd); + if(pcmIsAvailable < 0) { + close(fd); + return -3; + } + + close(fd); + return pcmIsAvailable; +} + +PUBLIC int alsaIsPcmAvailableUsingPcmName(char *pcmName, snd_pcm_stream_t pcmStream) +{ + int card = NO_CARD_SELECTED, device = NO_DEVICE_SELECTED, subdevice = NO_SUBDEVICE_SELECTED, pcmIsAvailable; + + if(! pcmName) + return -1; + + if(sscanf(pcmName, "hw:%i,%i,%i", &card, &device, &subdevice) != 3) + return -2; + + if(card < 0 || card > MAX_SND_CARD || + device < 0 || device > MAX_CARD_DEVICES || + subdevice < 0 || subdevice > MAX_DEVICE_SUBDEVICES) + return -3; + + pcmIsAvailable = alsaIsPcmAvailableUsingId(card, device, subdevice, pcmStream); + if(pcmIsAvailable < 0) + return -4; + + return pcmIsAvailable; +} + +PUBLIC void alsaGetPcmAvailability(afb_req_t request) +{ + int wrapRet, + pcmIsAvailable, + card = NO_CARD_SELECTED, + device = NO_DEVICE_SELECTED, + subdevice = NO_SUBDEVICE_SELECTED; + + char *pcmName = NULL; + + snd_pcm_stream_t pcmStream; + + json_object *queryJ; + + queryJ = afb_req_json(request); + if(! queryJ) { + afb_req_fail(request, "invalid_request", "Request json is unavailable"); + return; + } + + wrapRet = wrap_json_unpack(queryJ, + "{s?:i, s?:i, s?:i, s?:s, s:i !}", + "card", &card, + "device", &device, + "subdevice", &subdevice, + "name", &pcmName, + "stream", &pcmStream); + if(wrapRet || (! pcmName && (card == NO_CARD_SELECTED || device == NO_DEVICE_SELECTED || subdevice == NO_SUBDEVICE_SELECTED))) { + afb_req_fail_f(request, "invalid_request", "Request json is invalid (%s)", json_object_get_string(queryJ)); + return; + } + + if(! pcmName) + pcmIsAvailable = alsaIsPcmAvailableUsingId(card, device, subdevice, pcmStream); + else + pcmIsAvailable = alsaIsPcmAvailableUsingPcmName(pcmName, pcmStream); + + if(pcmIsAvailable < 0) { + afb_req_fail_f(request, "invalid_pcm", "Pcm specified in json is invalid (%s)", json_object_get_string(queryJ)); + return; + } + + afb_req_success(request, json_object_new_boolean(pcmIsAvailable), NULL); +} + // pack Alsa element's ACL into a JSON object STATIC json_object *getControlAcl(snd_ctl_elem_info_t *info) { -- cgit 1.2.3-korg