summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Aillet <jonathan.aillet@iot.bzh>2019-02-19 16:46:03 +0100
committerJonathan Aillet <jonathan.aillet@iot.bzh>2019-02-19 16:46:03 +0100
commitb8af262e1377072e4091a1a3196e1a739d671975 (patch)
tree6c2cd39d741b10ee666022c21f5c8a4befa985c5
parent4eb02cc449f51343bd5a08b76d92e4099f9ddf54 (diff)
Rework ALSA card get info function
Rework ALSA card get info function to : - Be able to probe an ALSA card depending on multiple parameters (card number, card path, card id, card short name, card long name, card driver, card mixer name, card components). If several parameters are requested, all should be true to find a corresponding card. - Be able to add parameters about a playback device depending on multiple parameters (device number, device id, device name). The combination of all card parameters and all device parameters should be true to find a corresponding card/device. - If a corresponding card/device is found, information about it will be returned as a json object. - If multiple card/device are corresponding to the request, all cards information will be returned in a json array. - If no request json is available, all cards information will be returned (using a json array). - Add the possibility to ask for multiple card/device in one verb call using a json array in request json. Each case will be handled as an individual request. The response will be an array of the same length as the request json, with each response case corresponding to the request case. Change-Id: Ia71e40ce10c8bb10d51099832748c5621d202647 Signed-off-by: Jonathan Aillet <jonathan.aillet@iot.bzh>
-rw-r--r--alsa-binding/Alsa-ApiHat.h23
-rw-r--r--alsa-binding/Alsa-SetGet.c671
-rw-r--r--conf.d/cmake/config.cmake4
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(&currentCardInfo);
- 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