diff options
-rw-r--r-- | alsa-binding/Alsa-ApiHat.h | 23 | ||||
-rw-r--r-- | alsa-binding/Alsa-SetGet.c | 671 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 4 |
3 files changed, 598 insertions, 100 deletions
diff --git a/alsa-binding/Alsa-ApiHat.h b/alsa-binding/Alsa-ApiHat.h index eaef9c7..6987448 100644 --- a/alsa-binding/Alsa-ApiHat.h +++ b/alsa-binding/Alsa-ApiHat.h @@ -38,6 +38,9 @@ #define CONTROL_MAXPATH_LEN 255 #endif +#define NO_CARD_SELECTED -1 +#define NO_DEVICE_SELECTED -1 + typedef enum { QUERY_QUIET =0, QUERY_COMPACT =1, @@ -46,15 +49,25 @@ typedef enum { } queryModeE; typedef enum { - INFO_BY_DEVID, - INFO_BY_PATH -} InfoGetT; - -typedef enum { ACTION_SET, ACTION_GET } ActionSetGetT; +// structure to store card +typedef struct { + int cardNb; + char *cardPath; + char *cardId; + char *cardShortName; + char *cardLongName; + char *cardDriver; + char *cardMixerName; + char *cardComponents; + int playbackDeviceNb; + char *playbackDeviceId; + char *playbackDeviceName; +} queryCardInfo; + // generic structure to pass parsed query values typedef struct { const char *devid; diff --git a/alsa-binding/Alsa-SetGet.c b/alsa-binding/Alsa-SetGet.c index 4685811..ad205a1 100644 --- a/alsa-binding/Alsa-SetGet.c +++ b/alsa-binding/Alsa-SetGet.c @@ -29,6 +29,8 @@ #include <sys/ioctl.h> +#include <wrap-json.h> + #include "Alsa-ApiHat.h" // extracted IOCTLs from <alsa/asoundlib.h> @@ -343,137 +345,618 @@ STATIC json_object *decodeTlv(unsigned int *tlv, unsigned int tlv_size, int mode return (decodeTlvJson); } +STATIC int searchInQueryForAlsaCardToProbe(queryCardInfo *queryInfo, int *cardToProbe) +{ + int err, cardPathFileId; -// retreive info for one given card + snd_ctl_card_info_t *currentCardInfo; -STATIC json_object* alsaCardProbe(const char *rqt, InfoGetT infoType) { - const char *info, *name; - const char *driver; - char devid[6]; - json_object *ctlDev; - snd_ctl_t *handle; - snd_ctl_card_info_t *cardinfo; - int err, open_dev; + snd_ctl_card_info_alloca(¤tCardInfo); - snd_ctl_card_info_alloca(&cardinfo); + if(! queryInfo) { + AFB_ERROR("Structure to look for an ALSA card is NULL"); + return -1; + } - switch(infoType) { - case INFO_BY_DEVID: - if((snd_ctl_open(&handle, rqt, 0)) < 0) { - AFB_INFO("%s: '%s' Not Found", __func__, rqt); - return NULL; - } + if(queryInfo->cardNb == NO_CARD_SELECTED && + ! queryInfo->cardPath && + ! queryInfo->cardId && + ! queryInfo->cardShortName && + ! queryInfo->cardLongName && + ! queryInfo->cardDriver && + ! queryInfo->cardMixerName && + ! queryInfo->cardComponents) { + AFB_WARNING("Not enough information specified in structure to look for an ALSA card"); + return -2; + } - err = snd_ctl_card_info(handle, cardinfo); + *cardToProbe = NO_CARD_SELECTED; - snd_ctl_close(handle); + if(queryInfo->cardNb >= 0 && queryInfo->cardNb < MAX_SND_CARD) { + *cardToProbe = queryInfo->cardNb; + } + else if(queryInfo->cardNb != NO_CARD_SELECTED) { + AFB_ERROR("ALSA card number %i is invalid", queryInfo->cardNb); + return -3; + } - if(err < 0) { - AFB_WARNING("%s: SndCard '%s' info error: %s", __func__, rqt, snd_strerror(err)); - return NULL; - } + if(queryInfo->cardPath) { + if((cardPathFileId = open(queryInfo->cardPath, O_RDONLY)) < 0) { + AFB_ERROR("CardPath '%s' error %i during open", queryInfo->cardPath, cardPathFileId); + return -4; + } - break; + err = ioctl(cardPathFileId, SNDRV_CTL_IOCTL_CARD_INFO(snd_ctl_card_info_sizeof()), currentCardInfo); + close(cardPathFileId); + + *cardToProbe = snd_ctl_card_info_get_card(currentCardInfo); + + if(err < 0) { + AFB_ERROR("CardPath '%s' error %i during ioctl", queryInfo->cardPath, err); + return -5; + } + else if(*cardToProbe < 0 || *cardToProbe >= MAX_SND_CARD) { + AFB_ERROR("CardPath '%s' returned an incorrect card number %i", queryInfo->cardPath, *cardToProbe); + return -6; + } + else if(queryInfo->cardNb != NO_CARD_SELECTED && *cardToProbe != queryInfo->cardNb) { + AFB_WARNING("CardPath '%s' (id %i) is not corresponding to the requested card number %i", + queryInfo->cardPath, + *cardToProbe, + queryInfo->cardNb); + return -7; + } + + queryInfo->cardNb = *cardToProbe; + } + + if(*cardToProbe != NO_CARD_SELECTED) + return 0; + + if((err = snd_card_next(cardToProbe)) < 0) { + AFB_ERROR("Error %i happened when tried to get next ALSA card number", err); + return -8; + } + + if(*cardToProbe < 0) { + AFB_NOTICE("No ALSA card connected"); + return -9; + } + + return 1; +} + +STATIC int jumpToCardNextDevice(unsigned int card, int *currentDevice) +{ + int err; + + char cardString[6]; + + snd_ctl_t *cardHandle; + + if(card >= MAX_SND_CARD) { + AFB_ERROR("ALSA card number %i is not valid", card); + return -1; + } + + if(*currentDevice != NO_DEVICE_SELECTED && + (*currentDevice < 0 || *currentDevice > MAX_CARD_DEVICES)) { + AFB_ERROR("ALSA card device %i is not valid", *currentDevice); + return -2; + } + + snprintf(cardString, sizeof(cardString), "hw:%d", card); + + if((err = snd_ctl_open(&cardHandle, cardString, 0)) < 0) { + AFB_ERROR("Error %i happened when tried to open ALSA card %i", err, *currentDevice); + return -3; + } + + if((err = snd_ctl_pcm_next_device(cardHandle, currentDevice)) < 0) { + AFB_ERROR("Error %i happened when tried to get ALSA card %i next device number", err, *currentDevice); + snd_ctl_close(cardHandle); + return -4; + } + + snd_ctl_close(cardHandle); + return 0; +} + +STATIC int checkIfCardIsCorrespondingToQuery(queryCardInfo *queryInfo, int card) +{ + int err; + + char cardString[6]; + + snd_ctl_t *cardHandle; + snd_ctl_card_info_t *cardInfo; + + snd_ctl_card_info_alloca(&cardInfo); + + if(! queryInfo) { + AFB_ERROR("Structure to look for an ALSA card is NULL"); + return -1; + } + + if(queryInfo->cardNb == NO_CARD_SELECTED && + ! queryInfo->cardPath && + ! queryInfo->cardId && + ! queryInfo->cardShortName && + ! queryInfo->cardLongName && + ! queryInfo->cardDriver && + ! queryInfo->cardMixerName && + ! queryInfo->cardComponents) { + AFB_WARNING("Not enough information specified in structure to look for an ALSA card"); + return -2; + } + + if(card < 0 || card >= MAX_SND_CARD) { + AFB_ERROR("ALSA card number %i is not valid", card); + return -3; + } + + snprintf(cardString, sizeof(cardString), "hw:%d", card); + + if((err = snd_ctl_open(&cardHandle, cardString, 0)) < 0) { + AFB_ERROR("Error %i happened when tried to open ALSA card %i", err, card); + return -4; + } + + if((err = snd_ctl_card_info(cardHandle, cardInfo)) < 0) { + AFB_ERROR("Error %i happened when tried to get ALSA card %i info", err, card); + snd_ctl_close(cardHandle); + return -5; + } + + if((queryInfo->cardId && strcmp(queryInfo->cardId, snd_ctl_card_info_get_id(cardInfo)) != 0) || + (queryInfo->cardShortName && strcmp(queryInfo->cardShortName, snd_ctl_card_info_get_name(cardInfo)) != 0) || + (queryInfo->cardLongName && strcmp(queryInfo->cardLongName, snd_ctl_card_info_get_longname(cardInfo)) != 0) || + (queryInfo->cardDriver && strcmp(queryInfo->cardDriver, snd_ctl_card_info_get_driver(cardInfo)) != 0) || + (queryInfo->cardMixerName && strcmp(queryInfo->cardMixerName, snd_ctl_card_info_get_mixername(cardInfo)) != 0) || + (queryInfo->cardComponents && strcmp(queryInfo->cardComponents, snd_ctl_card_info_get_components(cardInfo)) != 0)) { + AFB_DEBUG("Card %i tested but not corresponding to requested card:\n" + "Card ID: '%s', requested ID: '%s'\n" + "Card short name: '%s', requested short name: '%s'\n" + "Card long name: '%s', requested long name: '%s'\n" + "Card driver: '%s', requested driver: '%s'\n" + "Card mixer name: '%s', requested mixer name: '%s'\n" + "Card components: '%s', requested components: '%s'", + snd_ctl_card_info_get_card(cardInfo), + snd_ctl_card_info_get_id(cardInfo), queryInfo->cardId ? queryInfo->cardId : "none", + snd_ctl_card_info_get_name(cardInfo), queryInfo->cardShortName ? queryInfo->cardShortName : "none", + snd_ctl_card_info_get_longname(cardInfo), queryInfo->cardLongName ? queryInfo->cardLongName : "none", + snd_ctl_card_info_get_driver(cardInfo), queryInfo->cardDriver ? queryInfo->cardDriver : "none", + snd_ctl_card_info_get_mixername(cardInfo), queryInfo->cardMixerName ? queryInfo->cardMixerName : "none", + snd_ctl_card_info_get_components(cardInfo), queryInfo->cardComponents ? queryInfo->cardComponents : "none"); + snd_ctl_close(cardHandle); + return 0; + } + + snd_ctl_close(cardHandle); + return 1; +} + +STATIC int checkIfPlaybackDeviceIsCorrespondingToQuery(queryCardInfo *queryInfo, int card, int device) +{ + int err; + + char cardString[6]; + + snd_ctl_t *cardHandle; + snd_pcm_info_t *cardPcminfo; + + snd_pcm_info_alloca(&cardPcminfo); + + if(! queryInfo) { + AFB_ERROR("Structure to look for an ALSA card is NULL"); + return -1; + } + + if(queryInfo->playbackDeviceNb == NO_DEVICE_SELECTED && + ! queryInfo->playbackDeviceId && + ! queryInfo->playbackDeviceName) { + AFB_WARNING("Not enough information specified in structure to look for a device on card %i", card); + return -2; + } + + if(card < 0 || card >= MAX_SND_CARD) { + AFB_ERROR("ALSA card number %i is not valid", card); + return -3; + } + + if(device < 0 || device >= MAX_CARD_DEVICES) { + AFB_ERROR("ALSA card device %i is not valid", device); + return -4; + } + + snprintf(cardString, sizeof(cardString), "hw:%d", card); + + if((err = snd_ctl_open(&cardHandle, cardString, 0)) < 0) { + AFB_ERROR("Error %i happened when tried to open ALSA card %i", err, card); + return -5; + } + + snd_pcm_info_set_device(cardPcminfo, device); + snd_pcm_info_set_subdevice(cardPcminfo, 0); + snd_pcm_info_set_stream(cardPcminfo, SND_PCM_STREAM_PLAYBACK); + + if((err = snd_ctl_pcm_info(cardHandle, cardPcminfo)) == -ENOENT) { + snd_ctl_close(cardHandle); + return 0; + } + else if(err < 0) { + AFB_ERROR("Error %i happened when tried to get ALSA card %i device %i info", err, card, device); + snd_ctl_close(cardHandle); + return -6; + } + + if((queryInfo->playbackDeviceId && strcmp(queryInfo->playbackDeviceId, snd_pcm_info_get_id(cardPcminfo)) != 0) || + (queryInfo->playbackDeviceName && strcmp(queryInfo->playbackDeviceName, snd_pcm_info_get_name(cardPcminfo)) != 0)) { + AFB_DEBUG("Card %i, device %i tested but not corresponding to requested device:\n" + "Device ID: '%s', requested ID: '%s'\n" + "Device name: '%s', requested name: '%s'", + card, device, + snd_pcm_info_get_id(cardPcminfo), queryInfo->playbackDeviceId ? queryInfo->playbackDeviceId : "none", + snd_pcm_info_get_name(cardPcminfo), queryInfo->playbackDeviceName ? queryInfo->playbackDeviceName : "none"); + snd_ctl_close(cardHandle); + return 0; + } + + snd_ctl_close(cardHandle); + return 1; +} + +STATIC json_object *getCardInfo(int card) +{ + int err; + + char cardString[6]; + + snd_ctl_t *cardHandle; + snd_ctl_card_info_t *cardInfo; + + json_object *cardInfoJ; + + snd_ctl_card_info_alloca(&cardInfo); + + if(card < 0 || card >= MAX_SND_CARD) { + AFB_ERROR("ALSA card number %i is not valid", card); + return NULL; + } + + snprintf(cardString, sizeof(cardString), "hw:%d", card); + + if((err = snd_ctl_open(&cardHandle, cardString, 0)) < 0) { + AFB_ERROR("Error %i happened when tried to open ALSA card %i", err, card); + return NULL; + } + + if((err = snd_ctl_card_info(cardHandle, cardInfo)) < 0) { + AFB_ERROR("Error %i happened when tried to get ALSA card %i info", err, card); + snd_ctl_close(cardHandle); + return NULL; + } + + wrap_json_pack(&cardInfoJ, + "{s:i, s:s, s:s, s:s, s:s, s:s, s:s}", + "cardNb", snd_ctl_card_info_get_card(cardInfo), + "cardId", snd_ctl_card_info_get_id(cardInfo), + "cardShortName", snd_ctl_card_info_get_name(cardInfo), + "cardLongName", snd_ctl_card_info_get_longname(cardInfo), + "cardDriver", snd_ctl_card_info_get_driver(cardInfo), + "cardMixerName", snd_ctl_card_info_get_mixername(cardInfo), + "cardComponents", snd_ctl_card_info_get_components(cardInfo)); + + snd_ctl_close(cardHandle); + return cardInfoJ; +} + +STATIC json_object *getDeviceInfo(int card, int device) +{ + int err; + + char cardString[6]; + + snd_ctl_t *cardHandle; + snd_pcm_info_t *cardPcminfo; + + json_object *deviceInfoJ; + + snd_pcm_info_alloca(&cardPcminfo); + + if(card < 0 || card >= MAX_SND_CARD) { + AFB_ERROR("ALSA card number %i is not valid", card); + return NULL; + } + + if(device < 0 || device >= MAX_CARD_DEVICES) { + AFB_ERROR("ALSA card device %i is not valid", device); + return NULL; + } + + snprintf(cardString, sizeof(cardString), "hw:%d", card); + + if((err = snd_ctl_open(&cardHandle, cardString, 0)) < 0) { + AFB_ERROR("Error %i happened when tried to open ALSA card %i", err, card); + return NULL; + } + + snd_pcm_info_set_device(cardPcminfo, device); + snd_pcm_info_set_subdevice(cardPcminfo, 0); + snd_pcm_info_set_stream(cardPcminfo, SND_PCM_STREAM_PLAYBACK); + + if((err = snd_ctl_pcm_info(cardHandle, cardPcminfo)) == -ENOENT) { + snd_ctl_close(cardHandle); + return NULL; + } + else if(err < 0) { + AFB_ERROR("Error %i happened when tried to get ALSA card %i device %i info", err, card, device); + snd_ctl_close(cardHandle); + return NULL; + } + + wrap_json_pack(&deviceInfoJ, + "{s:i, s:s, s:s}", + "playbackDeviceNb", (int) snd_pcm_info_get_device(cardPcminfo), + "playbackDeviceId", snd_pcm_info_get_id(cardPcminfo), + "playbackDeviceName", snd_pcm_info_get_name(cardPcminfo)); + + snd_ctl_close(cardHandle); + return deviceInfoJ; +} + +// Retrieve info for one given card + +STATIC json_object *alsaCardProbe(queryCardInfo *queryInfo) { + int cardToProbe = NO_CARD_SELECTED, playbackDeviceToProbe, multipleCardToCheck, isCardCorresponding, isDeviceCorresponding; + unsigned int searchingForDevice = 1, correspondingCard = NO_CARD_SELECTED; + + json_object *correspondingCardJ, *correspondingDeviceJ = NULL, *correspondingCardAndDeviceJ, *toReturnJ; + + if(! queryInfo) { + AFB_NOTICE("Structure to look for an ALSA card is NULL"); + return NULL; + } + + if(queryInfo->cardNb == NO_CARD_SELECTED && + ! queryInfo->cardPath && + ! queryInfo->cardId && + ! queryInfo->cardShortName && + ! queryInfo->cardLongName && + ! queryInfo->cardDriver && + ! queryInfo->cardMixerName && + ! queryInfo->cardComponents) { + AFB_NOTICE("Not enough information specified in structure to look for an ALSA card"); + return NULL; + } + else if(queryInfo->cardNb != NO_CARD_SELECTED && + (queryInfo->cardNb < 0 || queryInfo->cardNb > MAX_SND_CARD)) { + AFB_WARNING("ALSA card %i is not valid", queryInfo->cardNb); + return NULL; + } + + if(queryInfo->playbackDeviceNb == NO_DEVICE_SELECTED && + ! queryInfo->playbackDeviceId && + ! queryInfo->playbackDeviceName) { + searchingForDevice = 0; + } + else if(queryInfo->playbackDeviceNb != NO_DEVICE_SELECTED && + (queryInfo->playbackDeviceNb < 0 || queryInfo->playbackDeviceNb > MAX_CARD_DEVICES)) { + AFB_WARNING("ALSA card device %i is not valid", queryInfo->playbackDeviceNb); + return NULL; + } + + if((multipleCardToCheck = searchInQueryForAlsaCardToProbe(queryInfo, &cardToProbe)) < 0) + return NULL; + + if(! (toReturnJ = json_object_new_array())) { + AFB_ERROR("Error while allocating answer json array"); + return NULL; + } + + while(cardToProbe >= 0 && + cardToProbe < MAX_SND_CARD) { + if((isCardCorresponding = checkIfCardIsCorrespondingToQuery(queryInfo, cardToProbe)) < 0) { + json_object_put(toReturnJ); + return NULL; + } + else if(isCardCorresponding) { + correspondingCard = cardToProbe; + } + + if(! multipleCardToCheck || (snd_card_next(&cardToProbe) < 0)) + cardToProbe = NO_CARD_SELECTED; - case INFO_BY_PATH: - if(! rqt) { - AFB_INFO("%s: no dev path specified", __func__); + if(! isCardCorresponding) + continue; + + correspondingCardJ = getCardInfo(correspondingCard); + + if(! searchingForDevice) { + json_object_array_add(toReturnJ, correspondingCardJ); + continue; + } + + playbackDeviceToProbe = queryInfo->playbackDeviceNb; + + correspondingCardAndDeviceJ = NULL; + + if(queryInfo->playbackDeviceNb != NO_DEVICE_SELECTED) { + playbackDeviceToProbe = queryInfo->playbackDeviceNb; + } + else if(jumpToCardNextDevice(correspondingCard, &playbackDeviceToProbe)) { + json_object_put(toReturnJ); + json_object_put(correspondingCardJ); + return NULL; + } + + while(playbackDeviceToProbe >= 0 && + playbackDeviceToProbe < MAX_CARD_DEVICES) { + if((isDeviceCorresponding = checkIfPlaybackDeviceIsCorrespondingToQuery(queryInfo, correspondingCard, playbackDeviceToProbe)) < 0) { + json_object_put(correspondingCardJ); + json_object_put(toReturnJ); return NULL; } - open_dev = open(rqt, O_RDONLY); - if(open_dev < 0) { - AFB_WARNING("%s: DevPath '%s' open error: %i", __func__, rqt, open_dev); + if(isDeviceCorresponding) + correspondingDeviceJ = getDeviceInfo(correspondingCard, playbackDeviceToProbe); + + if(queryInfo->playbackDeviceNb != NO_DEVICE_SELECTED) { + playbackDeviceToProbe = NO_DEVICE_SELECTED; + } + else if(jumpToCardNextDevice(correspondingCard, &playbackDeviceToProbe)) { + if(correspondingDeviceJ) + json_object_put(correspondingDeviceJ); + json_object_put(correspondingCardJ); + json_object_put(toReturnJ); return NULL; } - err = ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO(snd_ctl_card_info_sizeof()), cardinfo); + if(! isDeviceCorresponding || ! correspondingDeviceJ) + continue; - close(open_dev); + correspondingCardAndDeviceJ = wrap_json_clone(correspondingCardJ); - if(err < 0) { - AFB_WARNING("%s: DevPath '%s' ioctl error: %i", __func__, rqt, err); - return NULL; - } + wrap_json_object_add(correspondingCardAndDeviceJ, correspondingDeviceJ); + json_object_array_add(toReturnJ, correspondingCardAndDeviceJ); + } + + if(! correspondingCardAndDeviceJ) + AFB_DEBUG("Card %i tested and corresponding to requested card, but the requested device was not found", correspondingCard); + + json_object_put(correspondingCardJ); + + if(! multipleCardToCheck) break; } - // start a new json object to store card info - ctlDev = json_object_new_object(); + switch(json_object_array_length(toReturnJ)) { + case 0: + AFB_DEBUG("Requested card/device not found"); + return NULL; - snprintf(devid, 6, "hw:%i", snd_ctl_card_info_get_card(cardinfo)); - json_object_object_add(ctlDev, "devid", json_object_new_string(devid)); - name = snd_ctl_card_info_get_name(cardinfo); - json_object_object_add(ctlDev, "name", json_object_new_string(name)); + case 1: + correspondingCardJ = json_object_get(json_object_array_get_idx(toReturnJ, 0)); + json_object_put(toReturnJ); + return correspondingCardJ; -#if(AFB_BINDING_VERSION == 3) - if (afb_api_wants_log_level(afbBindingV3root, AFB_SYSLOG_LEVEL_NOTICE)) { -#else - if (afb_get_verbosity() >= AFB_VERBOSITY_LEVEL_NOTICE) { -#endif - driver = snd_ctl_card_info_get_driver(cardinfo); - 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)); - if(infoType == INFO_BY_DEVID) - AFB_INFO("AJG: Soundcard Devid=%-5s devid=%-7s Name=%s\n", rqt, devid, info); - else if(infoType == INFO_BY_DEVID) - AFB_INFO("AJG: Soundcard DevPath=%-5s devid=%-7s Name=%s\n", rqt, devid, info); - } - - // return info - return (ctlDev); + default: + return toReturnJ; + } } -// Loop on every potential Sound card and register active one - PUBLIC void alsaGetInfo(afb_req_t request) { - int card; - json_object *ctlDev, *ctlDevs; - char devid[32]; + int card = NO_CARD_SELECTED; + unsigned int idx, count; + + json_object *requestJ, *currentCardRequestJ, *currentCardInfoJ, *toReturnJ = NULL; + json_type requestJType; - json_object *rqtJ = afb_req_json(request); - const char *rqtSndId = afb_req_value(request, "devid"); - const char *rqtDevPath = afb_req_value(request, "devpath"); + queryCardInfo queryInfo; - // if no specific card requested loop on all + if(! (requestJ = afb_req_json(request))) { + if(snd_card_next(&card) >= 0 && + card >= 0) { + toReturnJ = json_object_new_array(); - if (rqtSndId) { - // only one card was requested let's probe it - ctlDev = alsaCardProbe(rqtSndId, INFO_BY_DEVID); - if (ctlDev != NULL) afb_req_success(request, ctlDev, NULL); - else afb_req_fail_f(request, "sndscard-notfound", "SndCard '%s' Not Found", rqtSndId); + while(card >= 0) { + if((currentCardInfoJ = getCardInfo(card))) + json_object_array_add(toReturnJ, currentCardInfoJ); + + if(snd_card_next(&card) < 0) + card = NO_CARD_SELECTED; + } + } + afb_req_success(request, toReturnJ, "All sound cards properties are available in returned Json"); + return; } - else if (rqtDevPath) { - // only one card was requested let's probe it - ctlDev = alsaCardProbe(rqtDevPath, INFO_BY_PATH); - if (ctlDev != NULL) afb_req_success(request, ctlDev, NULL); - else afb_req_fail_f(request, "sndscard-notfound", "SndCard '%s' Not Found", rqtSndId); + + switch((requestJType = json_object_get_type(requestJ))) { + case json_type_object: + count = 1; + break; + + case json_type_array: + count = (unsigned int) json_object_array_length(requestJ); + toReturnJ = json_object_new_array(); + break; + + default: + afb_req_fail_f(request, "invalid-request", "Invalid request json '%s'", json_object_get_string(requestJ)); + return; } - else if (!rqtJ) { - // return an array of ctlDev - ctlDevs = json_object_new_array(); - // loop on potential card number - for (card = 0; card < MAX_SND_CARD; card++) { + for(idx = 0; idx < count; idx++) { + if(requestJType == json_type_array) + currentCardRequestJ = json_object_array_get_idx(requestJ, idx); + else + currentCardRequestJ = requestJ; + + memset(&queryInfo, 0, sizeof(queryInfo)); + queryInfo.cardNb = NO_CARD_SELECTED; + queryInfo.playbackDeviceNb = NO_DEVICE_SELECTED; + + if((wrap_json_unpack(currentCardRequestJ, + "{s?:i, s?:s, s?:s, s?:s, s?:s, s?:s, s?:s, s?:s, s?:i, s?:s, s?:s !}", + "cardNb", (int *) &queryInfo.cardNb, + "cardPath", &queryInfo.cardPath, + "cardId", &queryInfo.cardId, + "cardShortName", &queryInfo.cardShortName, + "cardLongName", &queryInfo.cardLongName, + "cardDriver", &queryInfo.cardDriver, + "cardMixerName", &queryInfo.cardMixerName, + "cardComponents", &queryInfo.cardComponents, + "playbackDeviceNb", (int *) &queryInfo.playbackDeviceNb, + "playbackDeviceId", &queryInfo.playbackDeviceId, + "playbackDeviceName", &queryInfo.playbackDeviceName)) || + ((queryInfo.cardNb < 0 || queryInfo.cardNb >= MAX_SND_CARD) && + (! queryInfo.cardPath) && + (! queryInfo.cardId) && + (! queryInfo.cardShortName) && + (! queryInfo.cardLongName) && + (! queryInfo.cardDriver) && + (! queryInfo.cardMixerName) && + (! queryInfo.cardComponents))) { + if(toReturnJ) + json_object_put(toReturnJ); + afb_req_fail_f(request, + "invalid-request", + "Invalid request (case %u) json '%s'", + idx, + json_object_get_string(currentCardRequestJ)); + return; + } - // build card devid and probe it - snprintf(devid, sizeof (devid), "hw:%i", card); - ctlDev = alsaCardProbe(devid, INFO_BY_DEVID); + currentCardInfoJ = alsaCardProbe(&queryInfo); - // Alsa has hole within card list [ignore them] - if (ctlDev != NULL) { - // add current ctlDev to ctlDevs object - json_object_array_add(ctlDevs, ctlDev); - } + switch(requestJType) { + case json_type_object: + if((currentCardInfoJ)) + afb_req_success(request, + currentCardInfoJ, + "Requested sound card properties are available in returned Json"); + else + afb_req_fail_f(request, + "sndcard-not-found", + "Sound card requested is not connected (request : '%s')", + json_object_get_string(currentCardRequestJ)); + return; + + case json_type_array: + if((currentCardInfoJ)) + json_object_array_add(toReturnJ, currentCardInfoJ); + else + json_object_array_add(toReturnJ, json_object_new_string("sndcard-not-found")); + break; + + default: + break; } - afb_req_success(request, ctlDevs, NULL); - } - else { - afb_req_fail_f(request, "sndscard-notfound", "Invalid request json '%s'", json_object_get_string(rqtJ)); } + + afb_req_success(request, toReturnJ, "Found requested sound card(s) properties are available in returned Json"); } // pack Alsa element's ACL into a JSON object diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 3f6facc..cad98ee 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -75,6 +75,7 @@ set (PKG_REQUIRED_LIST libmicrohttpd>=0.9.55 libafbwsc alsa>=1.1.2 + afb-helpers ) # Prefix path where will be installed the files @@ -109,7 +110,8 @@ set(COMPILE_OPTIONS -fdata-sections -fPIC # Personal compilation options --DMAX_SND_CARD=16 # should be more than enough even in luxury vehicule +-DMAX_SND_CARD=32 # default ALSA max cards +-DMAX_CARD_DEVICES=32 # 32 devices by sound card should be enough (more investigation needed about this) -DMAX_LINEAR_DB_SCALE=24 # until 24db volume normalisation use a simple linear scale -DTLV_BYTE_SIZE=256 # Alsa use 4096 as default but 256 should fit most sndcards -DCONTROL_MAXPATH_LEN=255 |