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-SetGet.c | 145 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) (limited to 'alsa-binding/Alsa-SetGet.c') 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