summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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