summaryrefslogtreecommitdiffstats
path: root/plugins/alsa
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/alsa')
-rw-r--r--plugins/alsa/alsa-capture.c80
-rw-r--r--plugins/alsa/alsa-core-ctl.c (renamed from plugins/alsa/alsa-ctl.c)264
-rw-r--r--plugins/alsa/alsa-core-pcm.c (renamed from plugins/alsa/alsa-pcm.c)183
-rw-r--r--plugins/alsa/alsa-plug-dmix.c (renamed from plugins/alsa/alsa-dmix.c)54
-rw-r--r--plugins/alsa/alsa-plug-vol.c77
-rw-r--r--plugins/alsa/alsa-softmixer.c95
-rw-r--r--plugins/alsa/alsa-softmixer.h84
-rw-r--r--plugins/alsa/alsa-utils-bypath.c75
-rw-r--r--plugins/alsa/alsa-utils-dump.c2
9 files changed, 472 insertions, 442 deletions
diff --git a/plugins/alsa/alsa-capture.c b/plugins/alsa/alsa-capture.c
deleted file mode 100644
index 992f731..0000000
--- a/plugins/alsa/alsa-capture.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 "IoT.bzh"
- * Author Fulup Ar Foll <fulup@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define _GNU_SOURCE // needed for vasprintf
-
-#include "alsa-softmixer.h"
-
-PUBLIC snd_pcm_t* AlsaCreateCapture(CtlSourceT *source, const char* sndDevPath, unsigned int deviceIdx, unsigned int subpcmNamex, unsigned int channelCount) {
- char pcmName[32];
- int error;
- snd_pcm_t *pcmHandle;
- snd_pcm_hw_params_t *pcmParams;
-
- AFB_ApiNotice(source->api, "AlsaCreateCapture: start ");
-
- // get card info from /dev/snd/xxx
- snd_ctl_card_info_t *cardInfo = AlsaByPathInfo(source, sndDevPath);
-
- if (!cardInfo) {
- AFB_ApiError(source->api,"AlsaCreateCapture: fail to find sndcard by path= %s", sndDevPath);
- goto OnErrorExit;
- }
-
- // extract useful info from cardInfo handle
- int cardIdx = snd_ctl_card_info_get_card(cardInfo);
- const char *cardName = snd_ctl_card_info_get_name(cardInfo);
-
-
- // build a valid name and open sndcard
- snprintf(pcmName, sizeof (pcmName), "hw:%i,%i,%i", cardIdx, deviceIdx, subpcmNamex);
- error= snd_pcm_open(&pcmHandle, pcmName, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC);
- if (error) {
- AFB_ApiError(source->api,"AlsaCreateCapture: fail openpcm (hw:%d -> %s pcmNamex=%i subpcmNamex=%d): %s"
- , cardIdx, cardName, deviceIdx, subpcmNamex, snd_strerror(error));
- goto OnErrorExit;
- }
-
- // set default to param object
- snd_pcm_hw_params_alloca(&pcmParams);
- snd_pcm_hw_params_any(pcmHandle, pcmParams);
-
-
- error= snd_pcm_hw_params_set_channels (pcmHandle, pcmParams, channelCount);
- if (error) {
- AFB_ApiError(source->api,"lsaCreateCapture: fail set channel count (hw:%d -> %s pcmNamex=%i subpcmNamex=%d channelCount=%d): %s"
- , cardIdx, cardName, deviceIdx, subpcmNamex, channelCount, snd_strerror(error));
- goto OnErrorExit;
- }
-
- // push selected params to PCM
- error= snd_pcm_hw_params(pcmHandle, pcmParams);
- if (error) {
- AFB_ApiError(source->api,"lsaCreateCapture: fail pushing params (hw:%d -> %s pcmNamex=%i subpcmNamex=%d): %s"
- , cardIdx, cardName, deviceIdx, subpcmNamex, snd_strerror(error));
- goto OnErrorExit;
- }
-
- AFB_ApiNotice(source->api, "AlsaCreateCapture: done");
- free (cardInfo);
- return NULL;
-
-OnErrorExit:
- AFB_ApiNotice(source->api, "AlsaCreateCapture: OnErrorExit");
- return NULL;
-} \ No newline at end of file
diff --git a/plugins/alsa/alsa-ctl.c b/plugins/alsa/alsa-core-ctl.c
index b469e94..5944fb8 100644
--- a/plugins/alsa/alsa-ctl.c
+++ b/plugins/alsa/alsa-core-ctl.c
@@ -39,37 +39,68 @@ typedef struct {
} SubscribeHandleT;
typedef struct {
- snd_pcm_t *pcm[MAX_AUDIO_STREAMS+1];
- int numid[MAX_AUDIO_STREAMS+1];
+ AlsaPcmInfoT *pcm;
+ int numid;
+} SubStreamT;
+
+typedef struct {
+ SubStreamT stream[MAX_AUDIO_STREAMS + 1];
int count;
} AudioStreamHandleT;
static AudioStreamHandleT AudioStreamHandle;
-// Clone of AlsaLib snd_card_load2 static function
-
-snd_ctl_card_info_t *AlsaCtlGetInfo(CtlSourceT *source, const char *devid) {
+STATIC snd_ctl_elem_id_t *AlsaCtlGetElemId(CtlSourceT *source, snd_ctl_t* ctlDev, int numid) {
+ char string[32];
int error;
- snd_ctl_t *ctlDev;
+ int index;
+ snd_ctl_elem_list_t *ctlList = NULL;
+ snd_ctl_elem_id_t *elemId;
- if (devid) goto OnErrorExit;
+ snd_ctl_elem_list_alloca(&ctlList);
- if ((error = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY)) < 0) {
- devid = "Not Defined";
+ if ((error = snd_ctl_elem_list(ctlDev, ctlList)) < 0) {
+ AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve controls", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
- snd_ctl_card_info_t *cardInfo = malloc(snd_ctl_card_info_sizeof());
- if ((error = snd_ctl_card_info(ctlDev, cardInfo)) < 0) {
+ if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) {
+ AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve count", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
- return cardInfo;
+
+ // Fulup: do not understand why snd_ctl_elem_list should be call twice to get a valid ctlCount
+ if ((error = snd_ctl_elem_list(ctlDev, ctlList)) < 0) {
+ AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve controls", ALSA_CTL_UID(ctlDev, string));
+ goto OnErrorExit;
+ }
+
+ // loop on control to find the right one
+ int ctlCount = snd_ctl_elem_list_get_used(ctlList);
+ for (index = 0; index < ctlCount; index++) {
+
+ if (numid == snd_ctl_elem_list_get_numid(ctlList, index)) {
+ snd_ctl_elem_id_malloc(&elemId);
+ snd_ctl_elem_list_get_id(ctlList, index, elemId);
+ break;
+ }
+ }
+
+ if (index == ctlCount) {
+ AFB_ApiError(source->api, "AlsaCtlRegister [%s] fail get numid=%i count", ALSA_CTL_UID(ctlDev, string), numid);
+ goto OnErrorExit;
+ }
+
+ // clear ctl list and return elemid
+ snd_ctl_elem_list_clear(ctlList);
+ return elemId;
OnErrorExit:
- AFB_ApiError(source->api, "AlsaCtlGetInfo: fail to find sndcard by id= %s", devid);
+ if (ctlList) snd_ctl_elem_list_clear(ctlList);
return NULL;
}
+
PUBLIC snd_ctl_t *AlsaCtlOpenCtl(CtlSourceT *source, const char *devid) {
int error;
snd_ctl_t *ctlDev;
@@ -88,7 +119,23 @@ OnErrorExit:
return NULL;
}
-STATIC int CtlElemIdGetInt (AFB_ApiT api, snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, long *value) {
+STATIC int CtlElemIdGetNumid(AFB_ApiT api, snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, int *numid) {
+ snd_ctl_elem_info_t *elemInfo;
+
+ snd_ctl_elem_info_alloca(&elemInfo);
+ snd_ctl_elem_info_set_id(elemInfo, elemId);
+ if (snd_ctl_elem_info(ctlDev, elemInfo) < 0) goto OnErrorExit;
+ if (!snd_ctl_elem_info_is_readable(elemInfo)) goto OnErrorExit;
+
+ *numid = snd_ctl_elem_info_get_numid(elemInfo);
+
+ return 0;
+
+OnErrorExit:
+ return -1;
+}
+
+STATIC int CtlElemIdGetInt(AFB_ApiT api, snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, long *value) {
int error;
snd_ctl_elem_value_t *elemData;
snd_ctl_elem_info_t *elemInfo;
@@ -115,7 +162,7 @@ OnSuccessExit:
return 0;
OnErrorExit:
-
+
AFB_ApiWarning(api, "CtlSubscribeEventCB: ignored unsupported event Numid=%i", snd_ctl_elem_info_get_numid(elemInfo));
for (int idx = 0; idx < count; idx++) {
long valueL;
@@ -123,23 +170,23 @@ OnErrorExit:
switch (elemType) {
case SND_CTL_ELEM_TYPE_BOOLEAN:
valueL = snd_ctl_elem_value_get_boolean(elemData, idx);
- AFB_ApiNotice(api, "CtlElemIdGetBool: value=%ld", valueL);
+ AFB_ApiNotice(api, "CtlElemIdGetBool: value=%ld", valueL);
break;
case SND_CTL_ELEM_TYPE_INTEGER:
valueL = snd_ctl_elem_value_get_integer(elemData, idx);
- AFB_ApiNotice(api, "CtlElemIdGetInt: value=%ld", valueL);
+ AFB_ApiNotice(api, "CtlElemIdGetInt: value=%ld", valueL);
break;
case SND_CTL_ELEM_TYPE_INTEGER64:
valueL = snd_ctl_elem_value_get_integer64(elemData, idx);
- AFB_ApiNotice(api, "CtlElemIdGetInt64: value=%ld", valueL);
+ AFB_ApiNotice(api, "CtlElemIdGetInt64: value=%ld", valueL);
break;
case SND_CTL_ELEM_TYPE_ENUMERATED:
valueL = snd_ctl_elem_value_get_enumerated(elemData, idx);
- AFB_ApiNotice(api, "CtlElemIdGetEnum: value=%ld", valueL);
+ AFB_ApiNotice(api, "CtlElemIdGetEnum: value=%ld", valueL);
break;
case SND_CTL_ELEM_TYPE_BYTES:
valueL = snd_ctl_elem_value_get_byte(elemData, idx);
- AFB_ApiNotice(api, "CtlElemIdGetByte: value=%ld", valueL);
+ AFB_ApiNotice(api, "CtlElemIdGetByte: value=%ld", valueL);
break;
case SND_CTL_ELEM_TYPE_IEC958:
default:
@@ -150,12 +197,53 @@ OnErrorExit:
return -1;
}
-STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, void* userData) {
+// Clone of AlsaLib snd_card_load2 static function
+PUBLIC snd_ctl_card_info_t *AlsaCtlGetInfo(CtlSourceT *source, const char *devid) {
int error;
+ snd_ctl_t *ctlDev;
+
+ if (devid) goto OnErrorExit;
+
+ if ((error = snd_ctl_open(&ctlDev, devid, SND_CTL_READONLY)) < 0) {
+ devid = "Not Defined";
+ goto OnErrorExit;
+ }
+
+ snd_ctl_card_info_t *cardInfo = malloc(snd_ctl_card_info_sizeof());
+ if ((error = snd_ctl_card_info(ctlDev, cardInfo)) < 0) {
+ goto OnErrorExit;
+ }
+ return cardInfo;
+
+OnErrorExit:
+ AFB_ApiError(source->api, "AlsaCtlGetInfo: fail to find sndcard by id= %s", devid);
+ return NULL;
+}
+
+PUBLIC int AlsaCtlGetNumidValueI(CtlSourceT *source, snd_ctl_t* ctlDev, int numid, long* value) {
+
+ snd_ctl_elem_id_t *elemId = AlsaCtlGetElemId(source, ctlDev, numid);
+ if (!elemId) {
+ AFB_ApiError(source->api, "AlsaCtlGetNumValueI [sndcard=%s] fail to find numid=%d", snd_ctl_name(ctlDev), numid);
+ goto OnErrorExit;
+ }
+
+ int error = CtlElemIdGetInt(source->api, ctlDev, elemId, value);
+ if (error) {
+ AFB_ApiError(source->api, "AlsaCtlGetNumValueI [sndcard=%s] fail to get numid=%d value", snd_ctl_name(ctlDev), numid);
+ goto OnErrorExit;
+ }
+
+ return 0;
+OnErrorExit:
+ return -1;
+}
+
+STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, void* userData) {
+ int error, numid;
SubscribeHandleT *subscribeHandle = (SubscribeHandleT*) userData;
snd_ctl_event_t *eventId;
snd_ctl_elem_id_t *elemId;
- snd_ctl_elem_info_t *elemInfo;
long value;
if ((revents & EPOLLHUP) != 0) {
@@ -181,21 +269,17 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v
// extract element from event and get value
snd_ctl_event_elem_get_id(eventId, elemId);
- error= CtlElemIdGetInt (subscribeHandle->api, subscribeHandle->ctlDev, elemId, &value);
+ error = CtlElemIdGetInt(subscribeHandle->api, subscribeHandle->ctlDev, elemId, &value);
+ if (error) goto OnErrorExit;
+
+ error = CtlElemIdGetNumid(subscribeHandle->api, subscribeHandle->ctlDev, elemId, &numid);
if (error) goto OnErrorExit;
-
- // Fulup we have to reload info as elemId from event does not hold numid
- snd_ctl_elem_info_alloca(&elemInfo);
- snd_ctl_elem_info_set_id(elemInfo, elemId);
- if (snd_ctl_elem_info(subscribeHandle->ctlDev, elemInfo) < 0) goto OnErrorExit;
- int numid= snd_ctl_elem_info_get_numid(elemInfo);
-
- for (int idx=0; idx < AudioStreamHandle.count; idx++) {
- if (AudioStreamHandle.numid[idx] == numid) {
- const char *pcmName = snd_pcm_name(AudioStreamHandle.pcm[idx]);
+ for (int idx = 0; idx < AudioStreamHandle.count; idx++) {
+ if (AudioStreamHandle.stream[idx].numid == numid) {
+ const char *pcmName = AudioStreamHandle.stream[idx].pcm->devid;
+ snd_pcm_pause(AudioStreamHandle.stream[idx].pcm->handle, !value);
AFB_ApiNotice(subscribeHandle->api, "CtlSubscribeEventCB:%s/%d pcm=%s pause=%d numid=%d", subscribeHandle->info, subscribeHandle->tid, pcmName, !value, numid);
- snd_pcm_pause(AudioStreamHandle.pcm[idx], !value);
break;
}
}
@@ -220,7 +304,7 @@ static void *LoopInThread(void *handle) {
for (;;) {
int res = sd_event_run(subscribeHandle->sdLoop, watchdog);
if (res == 0) {
- AFB_ApiNotice(subscribeHandle->api, "LoopInThread:%s/%d Idle count=%d", subscribeHandle->info, subscribeHandle->tid, count++);
+ AFB_ApiInfo(subscribeHandle->api, "LoopInThread:%s/%d Idle count=%d", subscribeHandle->info, subscribeHandle->tid, count++);
continue;
}
if (res < 0) {
@@ -241,7 +325,7 @@ PUBLIC snd_ctl_t* AlsaCrlFromPcm(CtlSourceT *source, snd_pcm_t *pcm) {
if ((error = snd_pcm_info(pcm, pcmInfo)) < 0) goto OnErrorExit;
int pcmCard = snd_pcm_info_get_card(pcmInfo);
- snprintf(buffer, sizeof(buffer), "hw:%i", pcmCard);
+ snprintf(buffer, sizeof (buffer), "hw:%i", pcmCard);
if ((error = snd_ctl_open(&ctlDev, buffer, SND_CTL_READONLY)) < 0) goto OnErrorExit;
return ctlDev;
@@ -250,56 +334,6 @@ OnErrorExit:
return NULL;
}
-PUBLIC snd_ctl_elem_id_t * AlsaCtlGetElemId(CtlSourceT *source, snd_ctl_t* ctlDev, int numid) {
- char string[32];
- int error;
- int index;
- snd_ctl_elem_list_t *ctlList = NULL;
- snd_ctl_elem_id_t *elemId;
-
- snd_ctl_elem_list_alloca(&ctlList);
-
- if ((error = snd_ctl_elem_list(ctlDev, ctlList)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve controls", AlsaCtlUID (ctlDev, string));
- goto OnErrorExit;
- }
-
- if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) {
- AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve count", AlsaCtlUID (ctlDev, string));
- goto OnErrorExit;
- }
-
- // Fulup: do not understand why snd_ctl_elem_list should be call twice to get a valid ctlCount
- if ((error = snd_ctl_elem_list(ctlDev, ctlList)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlElemIdGetInt [%s] fail retrieve controls", AlsaCtlUID (ctlDev, string));
- goto OnErrorExit;
- }
-
- // loop on control to find the right one
- int ctlCount = snd_ctl_elem_list_get_used(ctlList);
- for (index = 0; index < ctlCount; index++) {
-
- if (numid == snd_ctl_elem_list_get_numid(ctlList, index)) {
- snd_ctl_elem_id_malloc(&elemId);
- snd_ctl_elem_list_get_id(ctlList, index, elemId);
- break;
- }
- }
-
- if (index == ctlCount) {
- AFB_ApiError(source->api, "AlsaCtlRegister [%s] fail get numid=%i count", AlsaCtlUID (ctlDev, string), numid);
- goto OnErrorExit;
- }
-
- // clear ctl list and return elemid
- snd_ctl_elem_list_clear(ctlList);
- return elemId;
-
-OnErrorExit:
- if (ctlList) snd_ctl_elem_list_clear(ctlList);
- return NULL;
-}
-
PUBLIC int AlsaCtlSubscribe(CtlSourceT *source, snd_ctl_t * ctlDev) {
int error;
@@ -313,32 +347,32 @@ PUBLIC int AlsaCtlSubscribe(CtlSourceT *source, snd_ctl_t * ctlDev) {
// subscribe for sndctl events attached to devid
if ((error = snd_ctl_subscribe_events(ctlDev, 1)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlSubscribe: fail sndcard=%s to subscribe events", AlsaCtlUID(ctlDev, string));
+ AFB_ApiError(source->api, "AlsaCtlSubscribe: fail sndcard=%s to subscribe events", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
// get pollfd attach to this sound board
int count = snd_ctl_poll_descriptors(ctlDev, &pfds, 1);
if (count != 1) {
- AFB_ApiError(source->api, "AlsaCtlSubscribe: fail sndcard=%s get poll descriptors", AlsaCtlUID(ctlDev, string));
+ AFB_ApiError(source->api, "AlsaCtlSubscribe: fail sndcard=%s get poll descriptors", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
// add poll descriptor to AGL systemd mainloop
if ((error = sd_event_new(&subscribeHandle->sdLoop)) < 0) {
- fprintf(stderr, "AlsaCtlSubscribe: fail sndcard=%s creating a new loop", AlsaCtlUID(ctlDev, string));
+ fprintf(stderr, "AlsaCtlSubscribe: fail sndcard=%s creating a new loop", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
// register sound event to binder main loop
if ((error = sd_event_add_io(subscribeHandle->sdLoop, &subscribeHandle->evtsrc, pfds.fd, EPOLLIN, CtlSubscribeEventCB, subscribeHandle)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlSubscribe: Fail sndcard=%s adding mainloop", AlsaCtlUID(ctlDev, string));
+ AFB_ApiError(source->api, "AlsaCtlSubscribe: Fail sndcard=%s adding mainloop", ALSA_CTL_UID(ctlDev, string));
goto OnErrorExit;
}
// start a thread with a mainloop to monitor Audio-Agent
if ((error = pthread_create(&subscribeHandle->thread, NULL, &LoopInThread, subscribeHandle)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlSubscribe: Fail sndcard=%s create waiting thread err=%d", AlsaCtlUID(ctlDev, string), error);
+ AFB_ApiError(source->api, "AlsaCtlSubscribe: Fail sndcard=%s create waiting thread err=%d", ALSA_CTL_UID(ctlDev, string), error);
goto OnErrorExit;
}
@@ -348,49 +382,41 @@ OnErrorExit:
return -1;
}
-PUBLIC int AlsaCtlRegister(CtlSourceT *source, snd_pcm_t *pcm, int numid) {
+PUBLIC int AlsaCtlRegister(CtlSourceT *source, AlsaPcmInfoT *pcm, int numid) {
long value;
int error;
-
+
// NumID are attached to sndcard retrieve ctldev from PCM
- snd_ctl_t* ctlDev = AlsaCrlFromPcm(source, pcm);
+ snd_ctl_t* ctlDev = AlsaCrlFromPcm(source, pcm->handle);
if (!ctlDev) {
- AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail attache sndcard", snd_pcm_name(pcm));
+ AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail attache sndcard", pcm->devid);
goto OnErrorExit;
}
-
+
// This is the first registration let's subscrive to event
if (AudioStreamHandle.count == 0) {
- AlsaCtlSubscribe (source, ctlDev);
- }
-
- snd_ctl_elem_id_t *elemId= AlsaCtlGetElemId(source, ctlDev, numid);
- if (!elemId) {
- AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail to find numid=%d", snd_pcm_name(pcm), numid);
- goto OnErrorExit;
+ AlsaCtlSubscribe(source, ctlDev);
}
- if ((error = CtlElemIdGetInt (source->api, ctlDev, elemId, &value)) != 0) {
- AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail to get numid=%d value", snd_pcm_name(pcm), numid);
- goto OnErrorExit;
- }
-
- AFB_ApiNotice(source->api, "AlsaCtlRegister [pcm=%s] numid=%d value=%ld", snd_pcm_name(pcm), numid, value);
+ error = AlsaCtlGetNumidValueI(source, ctlDev, numid, &value);
+ if (error) goto OnErrorExit;
+
+ AFB_ApiNotice(source->api, "AlsaCtlRegister [pcm=%s] numid=%d value=%ld", pcm->devid, numid, value);
// store PCM in order to pause/resume depending on event
- AudioStreamHandle.pcm[AudioStreamHandle.count] = pcm;
- AudioStreamHandle.numid[AudioStreamHandle.count] = numid;
- AudioStreamHandle.count++;
-
+ int count=AudioStreamHandle.count;
+ AudioStreamHandle.stream[count].pcm = pcm;
+ AudioStreamHandle.stream[count].numid = numid;
+
// we only need to keep ctldev open for initial registration
- if (AudioStreamHandle.count >1) snd_ctl_close(ctlDev);
-
+ if (AudioStreamHandle.count++ > 0) snd_ctl_close(ctlDev);
+
// toggle pause/resume (should be done after pcm_start)
- if ((error = snd_pcm_pause(pcm, !value)) < 0) {
- AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail to pause", snd_pcm_name(pcm));
- goto OnErrorExit;
+ if ((error = snd_pcm_pause(pcm->handle, !value)) < 0) {
+ AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail to pause", pcm->devid);
+ goto OnErrorExit;
}
-
+
return 0;
OnErrorExit:
diff --git a/plugins/alsa/alsa-pcm.c b/plugins/alsa/alsa-core-pcm.c
index f342888..a08dfca 100644
--- a/plugins/alsa/alsa-pcm.c
+++ b/plugins/alsa/alsa-core-pcm.c
@@ -32,7 +32,6 @@ for the specific language governing permissions and
#define BUFFER_FRAME_COUNT 1024
-
typedef struct {
snd_pcm_t *pcmIn;
snd_pcm_t *pcmOut;
@@ -40,7 +39,7 @@ typedef struct {
sd_event_source* evtsrc;
void* buffer;
size_t frameSize;
- unsigned int frameCount;
+ unsigned int frameCount;
unsigned int channels;
sd_event *sdLoop;
pthread_t thread;
@@ -48,11 +47,6 @@ typedef struct {
char* info;
} AlsaPcmCopyHandleT;
-static int defaultPcmRate = 48000;
-static int defaultPcmChannels = 2;
-static snd_pcm_format_t defaultPcmFormat = SND_PCM_FORMAT_S16_LE;
-static snd_pcm_access_t defaultPcmAccess = SND_PCM_ACCESS_RW_INTERLEAVED;
-
STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
int pcmSampleSize;
@@ -84,8 +78,7 @@ STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
return pcmSampleSize;
}
-
-PUBLIC int AlsaPcmConf(CtlSourceT *source, snd_pcm_t *pcmHandle, snd_pcm_format_t pcmFormat, unsigned int pcmRate, unsigned int pcmChannels, AlsaPcmHwInfoT *pcmHwInfo) {
+PUBLIC int AlsaPcmConf(CtlSourceT *source, AlsaPcmInfoT *pcm, AlsaPcmHwInfoT *opts) {
char string[32];
int error;
snd_pcm_hw_params_t *pxmHwParams;
@@ -93,75 +86,76 @@ PUBLIC int AlsaPcmConf(CtlSourceT *source, snd_pcm_t *pcmHandle, snd_pcm_format_
// retrieve hadware config from PCM
snd_pcm_hw_params_alloca(&pxmHwParams);
- snd_pcm_hw_params_any(pcmHandle, pxmHwParams);
+ snd_pcm_hw_params_any(pcm->handle, pxmHwParams);
- error = snd_pcm_hw_params_set_access(pcmHandle, pxmHwParams, defaultPcmAccess);
+ if (!opts->access) opts->access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ error = snd_pcm_hw_params_set_access(pcm->handle, pxmHwParams, opts->access);
if (error) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Interleave=%d mode error=%s", AlsaPcmUID(pcmHandle, string), defaultPcmAccess, snd_strerror(error));
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Interleave=%d mode error=%s", ALSA_PCM_UID(pcm->handle, string), opts->access, snd_strerror(error));
goto OnErrorExit;
};
- if (pcmFormat == ALSA_PCM_DEFAULT_FORMAT) pcmFormat = defaultPcmFormat;
- if (pcmFormat != SND_PCM_FORMAT_UNKNOWN) {
- if ((error = snd_pcm_hw_params_set_format(pcmHandle, pxmHwParams, pcmFormat)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Format=%d error=%s", AlsaPcmUID(pcmHandle, string), pcmFormat, snd_strerror(error));
- AlsaDumpFormats(source, pcmHandle);
+ if (opts->format != SND_PCM_FORMAT_UNKNOWN) {
+ if ((error = snd_pcm_hw_params_set_format(pcm->handle, pxmHwParams, opts->format)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Format=%d error=%s", ALSA_PCM_UID(pcm->handle, string), opts->format, snd_strerror(error));
+ AlsaDumpFormats(source, pcm->handle);
goto OnErrorExit;
}
}
- if (pcmRate == ALSA_PCM_DEFAULT_RATE) pcmRate = defaultPcmRate;
- pcmHwInfo->rate = pcmRate;
- if ((error = snd_pcm_hw_params_set_rate_near(pcmHandle, pxmHwParams, &pcmHwInfo->rate, 0)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Rate=%d error=%s", AlsaPcmUID(pcmHandle, string), pcmRate, snd_strerror(error));
- goto OnErrorExit;
- }
+ if (opts->rate > 0) {
+ unsigned int pcmRate = opts->rate;
+ if ((error = snd_pcm_hw_params_set_rate_near(pcm->handle, pxmHwParams, &opts->rate, 0)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Rate=%d error=%s", ALSA_PCM_UID(pcm->handle, string), opts->rate, snd_strerror(error));
+ goto OnErrorExit;
+ }
- // check we got requested rate
- if (pcmHwInfo->rate != pcmRate) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Rate ask=%dHz get=%dHz", AlsaPcmUID(pcmHandle, string), pcmRate, pcmHwInfo->rate);
- goto OnErrorExit;
+ // check we got requested rate
+ if (opts->rate != pcmRate) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Rate ask=%dHz get=%dHz", ALSA_PCM_UID(pcm->handle, string), pcmRate, opts->rate);
+ goto OnErrorExit;
+ }
}
- if (pcmChannels == ALSA_PCM_DEFAULT_CHANNELS) pcmChannels = defaultPcmChannels;
- if ((error = snd_pcm_hw_params_set_channels(pcmHandle, pxmHwParams, pcmChannels)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Channels=%d current=%d mode error=%s", AlsaPcmUID(pcmHandle, string), pcmChannels, pcmHwInfo->channels, snd_strerror(error));
- goto OnErrorExit;
- };
+ if (opts->channels) {
+ if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, opts->channels)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s Set_Channels=%d error=%s", ALSA_PCM_UID(pcm->handle, string), opts->channels, snd_strerror(error));
+ goto OnErrorExit;
+ };
+ }
// store selected values
- if ((error = snd_pcm_hw_params(pcmHandle, pxmHwParams)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s apply hwparams error=%s", AlsaPcmUID(pcmHandle, string), snd_strerror(error));
+ if ((error = snd_pcm_hw_params(pcm->handle, pxmHwParams)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s apply hwparams error=%s", ALSA_PCM_UID(pcm->handle, string), snd_strerror(error));
goto OnErrorExit;
}
// check we effective hw params after optional format change
- snd_pcm_hw_params_get_channels(pxmHwParams, &pcmHwInfo->channels);
- snd_pcm_hw_params_get_format(pxmHwParams, &pcmHwInfo->format);
- snd_pcm_hw_params_get_rate(pxmHwParams, &pcmHwInfo->rate, 0);
- pcmHwInfo->sampleSize = AlsaPeriodSize(pcmHwInfo->format);
- if (pcmHwInfo->sampleSize == 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s unsupported format format=%d", AlsaPcmUID(pcmHandle, string), pcmFormat);
+ snd_pcm_hw_params_get_channels(pxmHwParams, &opts->channels);
+ snd_pcm_hw_params_get_format(pxmHwParams, &opts->format);
+ snd_pcm_hw_params_get_rate(pxmHwParams, &opts->rate, 0);
+ opts->sampleSize = AlsaPeriodSize(opts->format);
+ if (opts->sampleSize == 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail PCM=%s unsupported format format=%d", ALSA_PCM_UID(pcm->handle, string), opts->format);
goto OnErrorExit;
}
// retrieve software config from PCM
snd_pcm_sw_params_alloca(&pxmSwParams);
- snd_pcm_sw_params_current(pcmHandle, pxmSwParams);
+ snd_pcm_sw_params_current(pcm->handle, pxmSwParams);
- if ((error = snd_pcm_sw_params_set_avail_min(pcmHandle, pxmSwParams, 16)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail to PCM=%s set_buffersize error=%s", AlsaPcmUID(pcmHandle, string), snd_strerror(error));
+ if ((error = snd_pcm_sw_params_set_avail_min(pcm->handle, pxmSwParams, 16)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail to PCM=%s set_buffersize error=%s", ALSA_PCM_UID(pcm->handle, string), snd_strerror(error));
goto OnErrorExit;
};
// push software params into PCM
- if ((error = snd_pcm_sw_params(pcmHandle, pxmSwParams)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmConf: Fail to push software=%s params error=%s", AlsaPcmUID(pcmHandle, string), snd_strerror(error));
+ if ((error = snd_pcm_sw_params(pcm->handle, pxmSwParams)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmConf: Fail to push software=%s params error=%s", ALSA_PCM_UID(pcm->handle, string), snd_strerror(error));
goto OnErrorExit;
};
-
- AFB_ApiNotice(source->api, "AlsaPcmConf: PCM=%s done", AlsaPcmUID(pcmHandle, string));
+ AFB_ApiNotice(source->api, "AlsaPcmConf: PCM=%s channels=%d rate=%d format=%d access=%d done", ALSA_PCM_UID(pcm->handle,string), opts->channels, opts->rate, opts->format, opts->access);
return 0;
OnErrorExit:
@@ -174,10 +168,9 @@ STATIC int AlsaPcmReadCB(sd_event_source* src, int fd, uint32_t revents, void* u
snd_pcm_sframes_t framesIn, framesOut, availIn, availOut;
AlsaPcmCopyHandleT *pcmCopyHandle = (AlsaPcmCopyHandleT*) userData;
-
// PCM has was closed
if ((revents & EPOLLHUP) != 0) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s hanghup/disconnected", AlsaPcmUID(pcmCopyHandle->pcmIn, string));
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s hanghup/disconnected", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
goto ExitOnSuccess;
}
@@ -186,26 +179,30 @@ STATIC int AlsaPcmReadCB(sd_event_source* src, int fd, uint32_t revents, void* u
goto ExitOnSuccess;
}
- // Fulup this should be optimised to limit CPU usage when idle
+ // retrieve PCM state
snd_pcm_state_t pcmState = snd_pcm_state(pcmCopyHandle->pcmIn);
+
+ // When pause flush remaining frame and wait
if (pcmState == SND_PCM_STATE_PAUSED) {
- sleep(1);
+ framesIn = snd_pcm_readi(pcmCopyHandle->pcmIn, pcmCopyHandle->buffer, pcmCopyHandle->frameCount);
+ AFB_ApiInfo(pcmCopyHandle->api, "AlsaPcmReadCB: paused frame:%ld ignored", framesIn);
+ goto ExitOnSuccess;
}
-
+
// When XRNS append try to restore PCM
if (pcmState == SND_PCM_STATE_XRUN) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s XRUN", AlsaPcmUID(pcmCopyHandle->pcmIn, string));
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s XRUN", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
snd_pcm_prepare(pcmCopyHandle->pcmIn);
}
-
+
// when PCM suspending loop until ready to go
if (pcmState == SND_PCM_STATE_SUSPENDED) {
while (1) {
if ((error = snd_pcm_resume(pcmCopyHandle->pcmIn)) < 0) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED fail to resume", AlsaPcmUID(pcmCopyHandle->pcmIn, string));
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED fail to resume", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
sleep(1); // Fulup should be replace with corresponding AFB_timer
} else {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED success to resume", AlsaPcmUID(pcmCopyHandle->pcmIn, string));
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s SUSPENDED success to resume", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
}
}
}
@@ -228,31 +225,28 @@ STATIC int AlsaPcmReadCB(sd_event_source* src, int fd, uint32_t revents, void* u
// we get too many data ignore some
if (availIn > pcmCopyHandle->frameCount) {
- AFB_ApiInfo(pcmCopyHandle->api, "AlsaPcmReadCB PcmIn=%s XRUN lost=%ld", AlsaPcmUID(pcmCopyHandle->pcmIn, string), availIn - pcmCopyHandle->frameCount);
availIn = pcmCopyHandle->frameCount;
}
// effectively read pcmIn and push frame to pcmOut
framesIn = snd_pcm_readi(pcmCopyHandle->pcmIn, pcmCopyHandle->buffer, availIn);
if (framesIn < 0 || framesIn != availIn) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmIn=%s UNDERUN frame=%ld", AlsaPcmUID(pcmCopyHandle->pcmIn, string), framesIn);
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmIn=%s UNDERUN frame=%ld", ALSA_PCM_UID(pcmCopyHandle->pcmIn, string), framesIn);
goto ExitOnSuccess;
}
// In/Out frames transfer through buffer copy
framesOut = snd_pcm_writei(pcmCopyHandle->pcmOut, pcmCopyHandle->buffer, framesIn);
if (framesOut < 0 || framesOut != framesIn) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmOut=%s UNDERUN/SUSPEND frameOut=%ld", AlsaPcmUID(pcmCopyHandle->pcmOut, string), framesOut);
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PcmOut=%s UNDERUN/SUSPEND frameOut=%ld", ALSA_PCM_UID(pcmCopyHandle->pcmOut, string), framesOut);
goto ExitOnSuccess;
}
if (framesIn != framesOut) {
- AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s Loosing frames=%ld", AlsaPcmUID(pcmCopyHandle->pcmOut, string), (framesIn - framesOut));
+ AFB_ApiNotice(pcmCopyHandle->api, "AlsaPcmReadCB PCM=%s Loosing frames=%ld", ALSA_PCM_UID(pcmCopyHandle->pcmOut, string), (framesIn - framesOut));
goto ExitOnSuccess;
}
- // fprintf(stderr, ".");
-
return 0;
// Cannot handle error in callback
@@ -273,107 +267,90 @@ static void *LoopInThread(void *handle) {
for (;;) {
int res = sd_event_run(pcmCopyHandle->sdLoop, watchdog);
if (res == 0) {
- AFB_ApiNotice(pcmCopyHandle->api, "LoopInThread:%s/%d Idle count=%d", pcmCopyHandle->info, pcmCopyHandle->tid, count++);
+ AFB_ApiInfo(pcmCopyHandle->api, "LoopInThread:%s/%d Idle count=%d", pcmCopyHandle->info, pcmCopyHandle->tid, count++);
continue;
}
if (res < 0) {
- AFB_ApiError(pcmCopyHandle->api,"LoopInThread:%s/%d ERROR=%i Exit errno=%s.\n", pcmCopyHandle->info, pcmCopyHandle->tid, res, strerror(res));
+ AFB_ApiError(pcmCopyHandle->api, "LoopInThread:%s/%d ERROR=%i Exit errno=%s.\n", pcmCopyHandle->info, pcmCopyHandle->tid, res, strerror(res));
break;
}
}
pthread_exit(0);
}
-PUBLIC int AlsaPcmCopy(CtlSourceT *source, snd_pcm_t *pcmIn, snd_pcm_t *pcmOut, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int rate, unsigned int channels) {
+PUBLIC int AlsaPcmCopy(CtlSourceT *source, AlsaPcmInfoT *pcmIn, AlsaPcmInfoT *pcmOut, AlsaPcmHwInfoT * opts) {
char string[32];
- struct pollfd *pcmInFds;
+ struct pollfd *pcmInFds;
int error;
- AlsaPcmHwInfoT infoIn, infoOut;
-
-
- if (format == ALSA_PCM_DEFAULT_FORMAT) format = defaultPcmFormat;
- if (rate == ALSA_PCM_DEFAULT_RATE) rate = defaultPcmRate;
- if (access == ALSA_PCM_DEFAULT_ACCESS) access = defaultPcmAccess;
- if (channels == ALSA_PCM_DEFAULT_CHANNELS) channels = defaultPcmChannels;
// prepare PCM for capture and replay
- error = AlsaPcmConf(source, pcmIn, format, rate, channels, &infoIn);
+ error = AlsaPcmConf(source, pcmIn, opts);
if (error) goto OnErrorExit;
// Prepare PCM for usage
- if ((error = snd_pcm_start(pcmIn)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail to prepare PCM=%s error=%s", AlsaPcmUID(pcmIn, string), snd_strerror(error));
+ if ((error = snd_pcm_start(pcmIn->handle)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail to prepare PCM=%s error=%s", ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
goto OnErrorExit;
};
-
- error = AlsaPcmConf(source, pcmOut, infoIn.format, infoIn.rate, infoIn.channels, &infoOut);
+
+ error = AlsaPcmConf(source, pcmOut, opts);
if (error) goto OnErrorExit;
// Prepare PCM for usage
- if ((error = snd_pcm_prepare(pcmOut)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail to start PCM=%s error=%s", AlsaPcmUID(pcmOut, string), snd_strerror(error));
+ if ((error = snd_pcm_prepare(pcmOut->handle)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail to start PCM=%s error=%s", ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
goto OnErrorExit;
};
+
- if (infoIn.format != infoOut.format) {
- AFB_ApiError(source->api, "AlsaPcmCopy: pcmIn=%s pcmOut=%s format mismatch in=%d out=%d"
- , AlsaPcmUID(pcmIn, string), AlsaPcmUID(pcmOut, string), infoIn.format, infoOut.format);
- goto OnErrorExit;
- }
-
- if (infoIn.channels != infoOut.channels) {
- AFB_ApiError(source->api, "AlsaPcmCopy: pcmIn=%s pcmOut=%s channel count mismatch in=%d out=%d"
- , AlsaPcmUID(pcmIn, string), AlsaPcmUID(pcmOut, string), infoIn.channels, infoOut.channels);
- goto OnErrorExit;
- }
AlsaPcmCopyHandleT *pcmCopyHandle = malloc(sizeof (AlsaPcmCopyHandleT));
pcmCopyHandle->info = "pcmCpy";
- pcmCopyHandle->pcmIn = pcmIn;
- pcmCopyHandle->pcmOut = pcmOut;
+ pcmCopyHandle->pcmIn = pcmIn->handle;
+ pcmCopyHandle->pcmOut = pcmOut->handle;
pcmCopyHandle->api = source->api;
- pcmCopyHandle->channels = infoIn.channels;
- pcmCopyHandle->frameSize = infoIn.channels * infoIn.sampleSize;
+ pcmCopyHandle->channels = opts->channels;
+ pcmCopyHandle->frameSize = opts->channels * opts->sampleSize;
pcmCopyHandle->frameCount = BUFFER_FRAME_COUNT;
pcmCopyHandle->buffer = malloc(pcmCopyHandle->frameCount * pcmCopyHandle->frameSize);
-
+
// get FD poll descriptor for capture PCM
int pcmInCount = snd_pcm_poll_descriptors_count(pcmCopyHandle->pcmIn);
if (pcmInCount <= 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s get fds count error=%s", AlsaPcmUID(pcmIn, string), snd_strerror(error));
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s get fds count error=%s", ALSA_PCM_UID(pcmIn->handle, string), snd_strerror(error));
goto OnErrorExit;
};
pcmInFds = alloca(sizeof (*pcmInFds) * pcmInCount);
- if ((error = snd_pcm_poll_descriptors(pcmIn, pcmInFds, pcmInCount)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s get pollfds error=%s", AlsaPcmUID(pcmOut, string), snd_strerror(error));
+ if ((error = snd_pcm_poll_descriptors(pcmIn->handle, pcmInFds, pcmInCount)) < 0) {
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s get pollfds error=%s", ALSA_PCM_UID(pcmOut->handle, string), snd_strerror(error));
goto OnErrorExit;
};
// add poll descriptor to AGL systemd mainloop
if ((error = sd_event_new(&pcmCopyHandle->sdLoop)) < 0) {
- fprintf(stderr, "LaunchCallRequest: fail pcmin=%s creating a new loop: %s\n", AlsaPcmUID(pcmOut, string), strerror(error));
+ fprintf(stderr, "LaunchCallRequest: fail pcmin=%s creating a new loop: %s\n", ALSA_PCM_UID(pcmOut->handle, string), strerror(error));
goto OnErrorExit;
}
for (int idx = 0; idx < pcmInCount; idx++) {
if ((error = sd_event_add_io(pcmCopyHandle->sdLoop, &pcmCopyHandle->evtsrc, pcmInFds[idx].fd, EPOLLIN, AlsaPcmReadCB, pcmCopyHandle)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s sd_event_add_io err=%d", AlsaPcmUID(pcmIn, string), error);
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail pcmIn=%s sd_event_add_io err=%d", ALSA_PCM_UID(pcmIn->handle, string), error);
goto OnErrorExit;
}
}
// start a thread with a mainloop to monitor Audio-Agent
if ((error = pthread_create(&pcmCopyHandle->thread, NULL, &LoopInThread, pcmCopyHandle)) < 0) {
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail create waiting thread pcmIn=%s err=%d", AlsaPcmUID(pcmIn, string), error);
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail create waiting thread pcmIn=%s err=%d", ALSA_PCM_UID(pcmIn->handle, string), error);
goto OnErrorExit;
}
return 0;
OnErrorExit:
- AFB_ApiError(source->api, "AlsaPcmCopy: Fail \n - pcmIn=%s \n - pcmOut=%s", AlsaPcmUID(pcmIn, string), AlsaPcmUID(pcmOut, string));
+ AFB_ApiError(source->api, "AlsaPcmCopy: Fail \n - pcmIn=%s \n - pcmOut=%s", ALSA_PCM_UID(pcmIn->handle, string), ALSA_PCM_UID(pcmOut->handle, string));
return -1;
}
diff --git a/plugins/alsa/alsa-dmix.c b/plugins/alsa/alsa-plug-dmix.c
index d527657..3d67410 100644
--- a/plugins/alsa/alsa-dmix.c
+++ b/plugins/alsa/alsa-plug-dmix.c
@@ -22,51 +22,53 @@
static int uniqueIpcIndex = 1024;
+ALSA_PLUG_PROTO(dmix);
-PUBLIC snd_pcm_t* AlsaCreateDmix(CtlSourceT *source, const char *dmixName, const char *slaveName) {
-
- AFB_ApiNotice(source->api, "AlsaCreateDmix: start ");
-
- int cardIndex= snd_ctl_card_info_get_card(AlsaByPathInfo (source, "/dev/snd/by-id/usb-Focusrite_Scarlett_18i8_USB_10004EE6-00"));
-
- AFB_ApiNotice(source->api, "AlsaCreateDmix: card index=%d ", cardIndex);
-
- snd_pcm_t *dmixPcm;
- snd_config_t *dmixConfig, *slaveConfig, *elemConfig;
- snd_pcm_stream_t streamPcm = SND_PCM_STREAM_PLAYBACK;
- int error = 0, streamMode = SND_PCM_NONBLOCK;
+PUBLIC AlsaPcmInfoT* AlsaCreateDmix(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave) {
+
+ snd_config_t *dmixConfig, *slaveConfig, *elemConfig, *pcmConfig;
+ AlsaPcmInfoT *pcmPlug= malloc(sizeof(AlsaPcmInfoT));
+ pcmPlug->devid= pcmName;
+ int error=0;
+ // refresh global alsalib config and create PCM top config
+ snd_config_update();
error += snd_config_top(&dmixConfig);
+ error += snd_config_set_id (dmixConfig, pcmPlug->devid);
+ error += snd_config_imake_string(&elemConfig, "type", "dmix");
+ error += snd_config_add(dmixConfig, elemConfig);
error += snd_config_imake_integer(&elemConfig, "ipc_key", uniqueIpcIndex++);
error += snd_config_add(dmixConfig, elemConfig);
if (error) goto OnErrorExit;
error += snd_config_make_compound(&slaveConfig, "slave", 0);
- error += snd_config_imake_string(&elemConfig, "pcm", slaveName);
+ error += snd_config_imake_string(&elemConfig, "pcm", pcmSlave->devid);
error += snd_config_add(slaveConfig, elemConfig);
if (error) goto OnErrorExit;
// add leaf into config
error += snd_config_add(dmixConfig, slaveConfig);
if (error) goto OnErrorExit;
+
+ error = _snd_pcm_dmix_open(&pcmPlug->handle, pcmPlug->devid, snd_config, dmixConfig, SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK);
+ if (error) {
+ AFB_ApiError(source->api, "AlsaCreateDmix: fail to create DMIX=%s SLAVE=%s", pcmPlug->devid, pcmSlave->devid);
+ goto OnErrorExit;
+ }
- snd_config_update();
- //AlsaDumpConfig (source, snd_config, 1);
- AlsaDumpCtlConfig (source, dmixConfig, 1);
-
-
- error = _snd_pcm_dmix_open(&dmixPcm, dmixName, snd_config, dmixConfig, streamPcm , streamMode);
+ error += snd_config_search(snd_config, "pcm", &pcmConfig);
+ error += snd_config_add(pcmConfig, dmixConfig);
if (error) {
- AFB_ApiError(source->api, "AlsaCreateDmix: fail to create DMIX=%s SLAVE=%s", dmixName, slaveName);
+ AFB_ApiError(source->api, "AlsaCreateDmix: fail to add configDMIX=%s", pcmPlug->devid);
goto OnErrorExit;
}
-
- AlsaDumpPcmInfo(source, dmixPcm, "DmixPCM");
-
- AFB_ApiNotice(source->api, "AlsaCreateDmix: done");
-
- return dmixPcm;
+
+ // Debug config & pcm
+ AlsaDumpCtlConfig (source, dmixConfig, 1);
+ //AlsaDumpPcmInfo(source, pcmPlug->handle, pcmPlug->devid);
+ AFB_ApiNotice(source->api, "AlsaCreateDmix: %s done", pcmPlug->devid);
+ return pcmPlug;
OnErrorExit:
AFB_ApiNotice(source->api, "AlsaCreateDmix: OnErrorExit");
diff --git a/plugins/alsa/alsa-plug-vol.c b/plugins/alsa/alsa-plug-vol.c
new file mode 100644
index 0000000..6de4ddf
--- /dev/null
+++ b/plugins/alsa/alsa-plug-vol.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author Fulup Ar Foll <fulup@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE // needed for vasprintf
+
+#include "alsa-softmixer.h"
+
+ALSA_PLUG_PROTO(softvol);
+
+PUBLIC AlsaPcmInfoT* AlsaCreateVol(CtlSourceT *source, const char *pcmName, AlsaPcmInfoT* ctlTarget, AlsaPcmInfoT* pcmSlave) {
+
+ snd_config_t *volConfig, *elemConfig, *slaveConfig, *controlConfig,*pcmConfig;
+ int error = 0;
+ AlsaPcmInfoT *pcmPlug= malloc(sizeof(AlsaPcmInfoT));
+ pcmPlug->devid= pcmName;
+
+ // refresh global alsalib config and create PCM top config
+ snd_config_update();
+ error += snd_config_top(&volConfig);
+
+ // add slave leaf
+ error += snd_config_make_compound(&slaveConfig, "slave", 0);
+ error += snd_config_imake_string(&elemConfig, "pcm", pcmSlave->devid);
+ error += snd_config_add(slaveConfig, elemConfig);
+ error += snd_config_add(volConfig, slaveConfig);
+ if (error) goto OnErrorExit;
+
+ // add control leaf
+ error += snd_config_make_compound(&controlConfig, "control", 0);
+ error += snd_config_imake_string(&elemConfig, "name", pcmName);
+ error += snd_config_add(controlConfig, elemConfig);
+ error += snd_config_imake_integer(&elemConfig, "card", ctlTarget->cardid);
+ error += snd_config_add(controlConfig, elemConfig);
+ error += snd_config_add(volConfig, controlConfig);
+ if (error) goto OnErrorExit;
+
+ // update top config to access previous plugin PCM
+ snd_config_update();
+
+ error = _snd_pcm_softvol_open(&pcmPlug->handle, pcmName, snd_config, volConfig, SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK);
+ if (error) {
+ AFB_ApiError(source->api, "AlsaCreateVol: fail to create Plug=%s Slave=%s", pcmPlug->devid, pcmSlave->devid);
+ goto OnErrorExit;
+ }
+
+ error += snd_config_search(snd_config, "pcm", &pcmConfig);
+ error += snd_config_add(pcmConfig, volConfig);
+ if (!error) {
+ AFB_ApiError(source->api, "AlsaCreateDmix: fail to add configDMIX=%s", pcmPlug->devid);
+ goto OnErrorExit;
+ }
+
+ // Debug config & pcm
+ AlsaDumpCtlConfig (source, volConfig, 1);
+ //AlsaDumpPcmInfo(source, pcmPlug->handle, "pcmPlug->handle");
+ AFB_ApiNotice(source->api, "AlsaCreateVol: %s done", pcmPlug->devid);
+ return pcmPlug;
+
+OnErrorExit:
+ AFB_ApiNotice(source->api, "AlsaCreateVol: OnErrorExit");
+ return NULL;
+} \ No newline at end of file
diff --git a/plugins/alsa/alsa-softmixer.c b/plugins/alsa/alsa-softmixer.c
index 253a00b..9586fa3 100644
--- a/plugins/alsa/alsa-softmixer.c
+++ b/plugins/alsa/alsa-softmixer.c
@@ -29,71 +29,86 @@ CTLP_ONLOAD(plugin, callbacks) {
return NULL;
}
+CTLP_LUA2C(AlsaDmix, source, argsJ, responseJ) {
+ json_object* subscribeArgsJ = NULL;
+
+ int error = 0;
+ wrap_json_pack(&subscribeArgsJ, "{ss}", "value", "location");
+ AFB_ApiNotice(source->api, "lua2c router with %s", json_object_to_json_string_ext(subscribeArgsJ, JSON_C_TO_STRING_PRETTY));
+
+ return error;
+}
+
+
CTLP_LUA2C(AlsaRouter, source, argsJ, responseJ) {
- json_object *devInJ, *devOutJ, *paramsJ=NULL;
- AlsaDevByPathT devIn, devOut;
- int err;
+ json_object *sndInJ, *sndOutJ, *paramsJ=NULL;
+ AlsaPcmInfoT *sndIn, *sndOut;
+ int error;
- // init default values
- memset(&devIn,0,sizeof(AlsaDevByPathT));
- memset(&devOut,0,sizeof(AlsaDevByPathT));
- int rate=ALSA_PCM_DEFAULT_RATE;
- int channels=ALSA_PCM_DEFAULT_CHANNELS;
- snd_pcm_format_t format=ALSA_PCM_DEFAULT_FORMAT;
- snd_pcm_access_t access=ALSA_PCM_DEFAULT_ACCESS;
+ // make sndIn/Out a pointer to get cleaner code
+ sndIn=calloc(1, sizeof(AlsaPcmInfoT));
+ sndOut=calloc(1, sizeof(AlsaPcmInfoT));
+ // set pcm options to defaults
+ AlsaPcmHwInfoT *pcmOpts;
+ pcmOpts=calloc(1, sizeof(AlsaPcmHwInfoT));
+ pcmOpts->format=SND_PCM_FORMAT_UNKNOWN;
+ pcmOpts->access=SND_PCM_ACCESS_RW_INTERLEAVED;
- err= wrap_json_unpack(argsJ, "{s:o,s:o,s?o}", "devin", &devInJ, "devout", &devOutJ, "params", &paramsJ);
- if (err) {
+ error= wrap_json_unpack(argsJ, "{s:o,s:o,s?o}", "devin", &sndInJ, "devout", &sndOutJ, "params", &paramsJ);
+ if (error) {
AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter ARGS missing devIn|devOut args=%s", json_object_get_string(argsJ));
goto OnErrorExit;
}
- AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter **** PARAMS missing 'format|access|rate|channels' params=%s", json_object_get_string(paramsJ));
-
- err= wrap_json_unpack(devInJ, "{s?s,s?s,s?i,s?i}", "path", &devIn.devpath, "id",&devIn.devid,"numid",&devIn.numid,"dev", &devIn.device, "sub", &devIn.subdev);
- if (err || (!devIn.devpath && !devIn.devid)) {
- AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter DEV-IN missing 'path|id|dev|sub|numid' devin=%s", json_object_get_string(devInJ));
+ error= wrap_json_unpack(sndInJ, "{s?s,s?s,s?i,s?i,s?i}", "path",&sndIn->devpath, "id",&sndIn->devid, "numid",&sndIn->numid, "dev",&sndIn->device, "sub",&sndIn->subdev);
+ if (error || (!sndIn->devpath && !sndIn->devid)) {
+ AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter DEV-IN missing 'path|id|dev|sub|numid' devin=%s", json_object_get_string(sndInJ));
goto OnErrorExit;
}
- err= wrap_json_unpack(devOutJ, "{s?s,s?s,s?i, s?i,s?i}", "path", &devOut.devpath, "id", &devOut.device, "sub", &devOut.subdev);
- if (err || (!devOut.devpath && !devOut.devid)) {
- AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter DEV-OUT missing 'path|id|dev|sub' devout=%s", json_object_get_string(devOutJ));
+ error= wrap_json_unpack(sndOutJ, "{s?s,s?s,s?i,s?i, s?i}", "path",&sndOut->devpath, "id",&sndOut->devid, "numid",&sndOut->numid,"dev",&sndOut->device, "sub",&sndOut->subdev);
+ if (error || (!sndOut->devpath && !sndOut->devid)) {
+ AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter DEV-OUT missing 'path|id|dev|sub' devout=%s", json_object_get_string(sndOutJ));
goto OnErrorExit;
}
- if (paramsJ) if ((err= wrap_json_unpack(paramsJ, "{s?i, s?i, s?i, s?i}", "format", &format, "access", &access, "rate", &rate, "channels",&channels)) != 0) {
+ if (paramsJ) if ((error= wrap_json_unpack(paramsJ, "{s?i, s?i, s?i, s?i}", "format", &pcmOpts->format, "access", &pcmOpts->access, "rate", &pcmOpts->rate, "channels",&pcmOpts->channels)) != 0) {
AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter PARAMS missing 'format|access|rate|channels' params=%s", json_object_get_string(paramsJ));
goto OnErrorExit;
}
- AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter devIn=%s devOut=%s rate=%d channel=%d", devIn.devpath, devOut.devpath, rate, channels);
-
- // open PCM and start frame copy from binder Mainloop
- snd_pcm_t* pcmIn = AlsaByPathOpenPcm(source, &devIn, SND_PCM_STREAM_CAPTURE);
- snd_pcm_t* pcmOut = AlsaByPathOpenPcm(source, &devOut, SND_PCM_STREAM_PLAYBACK);
- err = AlsaPcmCopy(source, pcmIn, pcmOut, format, access, (unsigned int)rate, (unsigned int)channels);
- if(err) goto OnErrorExit;
+ AFB_ApiNotice(source->api, "--lua2c-- AlsaRouter devin=%s devout=%s rate=%d channel=%d", sndIn->devpath, sndOut->devpath, pcmOpts->rate, pcmOpts->channels);
+
+ // Check sndOut Exist and build a valid devid config
+ error= AlsaByPathDevid (source, sndOut);
+ if (error) goto OnErrorExit;
+
+ //AlsaPcmInfoT *pcmOut = AlsaByPathOpenPcm(source, sndOut, SND_PCM_STREAM_PLAYBACK);
+
+ // open capture PCM
+ AlsaPcmInfoT *pcmIn = AlsaByPathOpenPcm(source, sndIn, SND_PCM_STREAM_CAPTURE);
+ if (!pcmIn) goto OnErrorExit;
+
+ AlsaPcmInfoT *pcmDmix= AlsaCreateDmix(source, "DmixPlugPcm", sndOut);
+ if(!pcmDmix) goto OnErrorExit;
+
+ AlsaPcmInfoT *pcmVol= AlsaCreateVol(source, "SoftVol", sndIn, pcmDmix);
+ if(!pcmVol) goto OnErrorExit;
+
+ error = AlsaPcmCopy(source, pcmIn, pcmVol, pcmOpts);
+ if(error) goto OnErrorExit;
// Registration to event should be done after pcm_start
- if (devIn.numid) {
- err= AlsaCtlRegister(source, pcmIn, devIn.numid);
- if(err) goto OnErrorExit;
+ if (sndIn->numid) {
+ error= AlsaCtlRegister(source, pcmIn, sndIn->numid);
+ if(error) goto OnErrorExit;
}
return 0;
OnErrorExit:
+ AFB_ApiNotice(source->api, "--lua2c-- ERROR AlsaRouter sndIn=%s sndOut=%s rate=%d channel=%d", sndIn->devpath, sndOut->devpath, pcmOpts->rate, pcmOpts->channels);
return -1;
}
-CTLP_LUA2C(AlsaDmix, source, argsJ, responseJ) {
- json_object* subscribeArgsJ = NULL;
-
- int err = 0;
- wrap_json_pack(&subscribeArgsJ, "{ss}", "value", "location");
- AFB_ApiNotice(source->api, "lua2c router with %s", json_object_to_json_string_ext(subscribeArgsJ, JSON_C_TO_STRING_PRETTY));
-
- return err;
-}
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index c777f5d..17e7cf2 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -31,63 +31,61 @@
#include <alsa/asoundlib.h>
-#define MAINLOOP_WATCHDOG 10000
+#define MAINLOOP_WATCHDOG 30000
#define MAX_AUDIO_STREAMS 8
-// Provide proto for LibASound low level API
-int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
- snd_config_t *root, snd_config_t *conf,
- snd_pcm_stream_t stream, int mode);
+#define ALSA_PLUG_PROTO(plugin) \
+ int _snd_pcm_ ## plugin ## _open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode)
-// alsa-ctl.c
-PUBLIC snd_ctl_card_info_t *AlsaCtlGetInfo (CtlSourceT *source, const char *devid);
-PUBLIC snd_ctl_t *AlsaCtlOpenCtl (CtlSourceT *source, const char *devid);
-PUBLIC int AlsaCtlSubscribe(CtlSourceT *source, snd_ctl_t *ctlDev);
-PUBLIC int AlsaCtlRegister(CtlSourceT *source, snd_pcm_t *pcm, int numid);
-
-// alsa-tools-dump.c
-PUBLIC void AlsaDumpFormats(CtlSourceT *source, snd_pcm_t *pcmHandle);
-PUBLIC char *AlsaDumpPcmUid(snd_pcm_t *pcmHandle, char *buffer, size_t len);
-PUBLIC void AlsaDumpCtlSubdev(CtlSourceT *source, snd_ctl_t *handle);
-PUBLIC void AlsaDumpPcmInfo(CtlSourceT *source, snd_pcm_t *pcm, const char* info);
-PUBLIC void AlsaDumpPcmParams(CtlSourceT *source, snd_pcm_hw_params_t *pcmHwParams);
-PUBLIC void AlsaDumpCtlConfig(CtlSourceT *source, snd_config_t *config, int indent);
-#define AlsaPcmUID(pcmHandle, buffer) AlsaDumpPcmUid(pcmHandle, buffer, sizeof(buffer))
-PUBLIC char *AlsaDumpCtlUid(snd_ctl_t *ctlHandle, char *buffer, size_t len);
-#define AlsaCtlUID(ctlHandle, buffer) AlsaDumpCtlUid(ctlHandle, buffer, sizeof(buffer))
-
-// alsa-tools-bypath.c
+// alsa-utils-bypath.c
typedef struct {
- char *devpath;
- char *devid;
+ const char *devpath;
+ const char *devid;
int device;
int subdev;
int numid;
-} AlsaDevByPathT;
+ int cardid;
+ snd_pcm_t *handle;
+} AlsaPcmInfoT;
-PUBLIC snd_ctl_card_info_t* AlsaByPathInfo (CtlSourceT *source, const char *control);
-PUBLIC snd_pcm_t* AlsaByPathOpenPcm(CtlSourceT *source, AlsaDevByPathT *dev, snd_pcm_stream_t direction);
-PUBLIC snd_ctl_t *AlsaByPathOpenCtl (CtlSourceT *source, AlsaDevByPathT *dev);
-#define ALSA_PCM_DEFAULT_FORMAT (unsigned int)-99
-#define ALSA_PCM_DEFAULT_ACCESS (snd_pcm_access_t)-99
-#define ALSA_PCM_DEFAULT_RATE (snd_pcm_format_t)-99
-#define ALSA_PCM_DEFAULT_CHANNELS (unsigned int)-99
-
-// alsa-pcm.c
typedef struct {
- snd_pcm_format_t format;
+ unsigned int rate;
unsigned int channels;
+ snd_pcm_format_t format;
+ snd_pcm_access_t access;
size_t sampleSize;
- unsigned int rate;
} AlsaPcmHwInfoT;
-PUBLIC void AlsaPcmSetDefault (snd_pcm_format_t format, snd_pcm_access_t access, unsigned int rate, unsigned int channel);
-PUBLIC int AlsaPcmConf(CtlSourceT *source, snd_pcm_t *pcmHandle, snd_pcm_format_t pcmFormat, unsigned int pcmRate, unsigned int pcmChannels, AlsaPcmHwInfoT *pcmHwInfo);
-PUBLIC int AlsaPcmCopy(CtlSourceT *source, snd_pcm_t *pcmIn, snd_pcm_t *pcmOut, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int rate, unsigned int channel);
+PUBLIC snd_ctl_card_info_t* AlsaByPathInfo (CtlSourceT *source, const char *control);
+PUBLIC AlsaPcmInfoT* AlsaByPathOpenPcm(CtlSourceT *source, AlsaPcmInfoT *dev, snd_pcm_stream_t direction);
+PUBLIC snd_ctl_t *AlsaByPathOpenCtl (CtlSourceT *source, AlsaPcmInfoT *dev);
+PUBLIC int AlsaByPathDevid (CtlSourceT *source, AlsaPcmInfoT *dev);
+
+// alsa-utils-dump.c
+PUBLIC void AlsaDumpFormats(CtlSourceT *source, snd_pcm_t *pcmHandle);
+PUBLIC char *AlsaDumpPcmUid(snd_pcm_t *pcmHandle, char *buffer, size_t len);
+PUBLIC void AlsaDumpCtlSubdev(CtlSourceT *source, snd_ctl_t *handle);
+PUBLIC void AlsaDumpPcmInfo(CtlSourceT *source, snd_pcm_t *pcm, const char* info);
+PUBLIC void AlsaDumpPcmParams(CtlSourceT *source, snd_pcm_hw_params_t *pcmHwParams);
+PUBLIC void AlsaDumpCtlConfig(CtlSourceT *source, snd_config_t *config, int indent);
+#define ALSA_PCM_UID(pcmHandle, buffer) AlsaDumpPcmUid(pcmHandle, buffer, sizeof(buffer))
+PUBLIC char *AlsaDumpCtlUid(snd_ctl_t *ctlHandle, char *buffer, size_t len);
+#define ALSA_CTL_UID(ctlHandle, buffer) AlsaDumpCtlUid(ctlHandle, buffer, sizeof(buffer))
+
+// alsa-core-ctl.c
+PUBLIC snd_ctl_card_info_t *AlsaCtlGetInfo (CtlSourceT *source, const char *devid);
+PUBLIC snd_ctl_t *AlsaCtlOpenCtl (CtlSourceT *source, const char *devid);
+PUBLIC int AlsaCtlSubscribe(CtlSourceT *source, snd_ctl_t *ctlDev);
+PUBLIC int AlsaCtlRegister(CtlSourceT *source, AlsaPcmInfoT *pcm, int numid);
+PUBLIC int AlsaCtlGetNumidValueI(CtlSourceT *source, snd_ctl_t* ctlDev, int numid, long* value);
+
+
-// alse-dmix.c
-PUBLIC snd_pcm_t* AlsaCreateDmix(CtlSourceT *source, const char *dmixName, const char *slaveName);
-PUBLIC snd_pcm_t* AlsaCreateCapture(CtlSourceT *source, const char* sndDevPath, unsigned int deviceIdx, unsigned int subdevIdx, unsigned int channelCount);
+PUBLIC int AlsaPcmConf(CtlSourceT *source, AlsaPcmInfoT *pcm, AlsaPcmHwInfoT *opts);
+PUBLIC int AlsaPcmCopy(CtlSourceT *source, AlsaPcmInfoT *pcmIn, AlsaPcmInfoT *pcmOut, AlsaPcmHwInfoT *opts);
+// _snd_pcm_PLUGIN_open_ see macro ALSA_PLUG_PROTO(plugin)
+PUBLIC AlsaPcmInfoT* AlsaCreateDmix(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave);
+PUBLIC AlsaPcmInfoT* AlsaCreateVol(CtlSourceT *source, const char *pcmName, AlsaPcmInfoT* ctlTarget, AlsaPcmInfoT* pcmSlave);
#endif \ No newline at end of file
diff --git a/plugins/alsa/alsa-utils-bypath.c b/plugins/alsa/alsa-utils-bypath.c
index e4a8833..8fba1f0 100644
--- a/plugins/alsa/alsa-utils-bypath.c
+++ b/plugins/alsa/alsa-utils-bypath.c
@@ -34,78 +34,93 @@
// Clone of AlsaLib snd_card_load2 static function
-PUBLIC snd_ctl_card_info_t *AlsaByPathInfo (CtlSourceT *source, const char *devpath) {
+
+PUBLIC snd_ctl_card_info_t *AlsaByPathInfo(CtlSourceT *source, const char *devpath) {
int open_dev;
snd_ctl_card_info_t *cardInfo = malloc(snd_ctl_card_info_sizeof());
if (!devpath) goto OnErrorExit;
-
+
open_dev = open(devpath, O_RDONLY);
if (open_dev < 0) goto OnErrorExit;
-
+
int rc = ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO(snd_ctl_card_info_sizeof()), cardInfo);
if (rc < 0) {
close(open_dev);
goto OnErrorExit;
}
-
+
close(open_dev);
return cardInfo;
-
+
OnErrorExit:
- AFB_ApiError(source->api,"AlsaCardInfoByPath: fail to find sndcard by path= %s", devpath);
+ AFB_ApiError(source->api, "AlsaCardInfoByPath: fail to find sndcard by path= %s", devpath);
return NULL;
}
-PUBLIC snd_pcm_t* AlsaByPathOpenPcm(CtlSourceT *source, AlsaDevByPathT *dev, snd_pcm_stream_t direction) {
- char pcmName[32];
- int error;
- snd_pcm_t *pcmHandle;
+PUBLIC int AlsaByPathDevid(CtlSourceT *source, AlsaPcmInfoT *dev) {
// get card info from /dev/snd/xxx if not use hw:x,x,x
- snd_ctl_card_info_t *cardInfo=NULL;
+ snd_ctl_card_info_t *cardInfo = NULL;
if (dev->devpath) cardInfo = AlsaByPathInfo(source, dev->devpath);
- else if (dev->devid) cardInfo = AlsaCtlGetInfo (source, dev->devid);
+ else if (dev->devid) cardInfo = AlsaCtlGetInfo(source, dev->devid);
if (!cardInfo) {
- AFB_ApiError(source->api, "AlsaByPathOpenPcm: fail to find sndcard by path=%s id=%s", dev->devpath, dev->devid);
+ AFB_ApiWarning(source->api, "AlsaByPathOpenPcm: fail to find sndcard by path=%s id=%s", dev->devpath, dev->devid);
goto OnErrorExit;
}
// extract useful info from cardInfo handle
- int cardIdx = snd_ctl_card_info_get_card(cardInfo);
- const char *cardName = snd_ctl_card_info_get_name(cardInfo);
+ dev->cardid = snd_ctl_card_info_get_card(cardInfo);
+
+ // if not provided build a valid PCM devid
+ if (!dev->devid) {
+ #define DEVID_MAX_LEN 32
+ dev->devid=malloc(DEVID_MAX_LEN);
+ if (dev->subdev) snprintf((char*)dev->devid, DEVID_MAX_LEN, "hw:%i,%i,%i", dev->cardid, dev->device, dev->subdev);
+ else if (dev->device) snprintf((char*)dev->devid, DEVID_MAX_LEN, "hw:%i,%i", dev->cardid, dev->device);
+ else snprintf((char*)dev->devid, DEVID_MAX_LEN, "hw:%i", dev->cardid);
+ }
+ return 0;
- // build a valid name and open sndcard
- snprintf(pcmName, sizeof (pcmName), "hw:%i,%i,%i", cardIdx, dev->device, dev->subdev);
- error = snd_pcm_open(&pcmHandle, pcmName, direction, SND_PCM_NONBLOCK);
+OnErrorExit:
+ return -1;
+}
+
+PUBLIC AlsaPcmInfoT* AlsaByPathOpenPcm(CtlSourceT *source, AlsaPcmInfoT *dev, snd_pcm_stream_t direction) {
+ int error;
+
+ error = AlsaByPathDevid(source, dev);
+ if (error) goto OnErrorExit;
+
+ error = snd_pcm_open(&dev->handle, dev->devid, direction, SND_PCM_NONBLOCK);
if (error) {
- AFB_ApiError(source->api, "AlsaByPathOpenPcm: fail openpcm (hw:%d -> %s name=%i subdev=%d): %s"
- , cardIdx, cardName, dev->device, dev->subdev, snd_strerror(error));
+ AFB_ApiError(source->api, "AlsaByPathOpenPcm: fail openpcm (devid=%s idxdev=%i subdev=%d): %s"
+ , dev->devid, dev->device, dev->subdev, snd_strerror(error));
goto OnErrorExit;
}
-
- return (pcmHandle);
+
+ return (dev);
OnErrorExit:
return NULL;
}
-PUBLIC snd_ctl_t *AlsaByPathOpenCtl (CtlSourceT *source, AlsaDevByPathT *dev) {
+PUBLIC snd_ctl_t *AlsaByPathOpenCtl(CtlSourceT *source, AlsaPcmInfoT *dev) {
int err;
char devid[32];
snd_ctl_t *handle;
-
+
// get card info from /dev/snd/xxx if not use hw:x,x,x
- snd_ctl_card_info_t *cardInfo=NULL;
+ snd_ctl_card_info_t *cardInfo = NULL;
if (dev->devpath) cardInfo = AlsaByPathInfo(source, dev->devpath);
- else if (dev->devid) cardInfo = AlsaCtlGetInfo (source, dev->devid);
+ else if (dev->devid) cardInfo = AlsaCtlGetInfo(source, dev->devid);
if (!cardInfo) {
AFB_ApiError(source->api, "AlsaByPathOpenCtl: fail to find sndcard by path=%s id=%s", dev->devpath, dev->devid);
goto OnErrorExit;
}
-
+
// extract useful info from cardInfo handle
int cardIndex = snd_ctl_card_info_get_card(cardInfo);
const char *cardId = snd_ctl_card_info_get_id(cardInfo);
@@ -114,14 +129,14 @@ PUBLIC snd_ctl_t *AlsaByPathOpenCtl (CtlSourceT *source, AlsaDevByPathT *dev) {
// build a valid name and open sndcard
snprintf(devid, sizeof (devid), "hw:%i", cardIndex);
if ((err = snd_ctl_open(&handle, devid, 0)) < 0) {
- AFB_ApiError(source->api,"control open (hw:%d -> %s): %s", cardIndex, cardName, snd_strerror(err));
+ AFB_ApiError(source->api, "control open (hw:%d -> %s): %s", cardIndex, cardName, snd_strerror(err));
goto OnErrorExit;
}
AFB_ApiNotice(source->api, "AlsaCtlOpenByPath: sndcard hw:%d id=%s name=%s", cardIndex, cardId, cardName);
- free (cardInfo);
+ free(cardInfo);
return handle;
-
+
OnErrorExit:
return NULL;
}
diff --git a/plugins/alsa/alsa-utils-dump.c b/plugins/alsa/alsa-utils-dump.c
index 7cfa899..b3bc864 100644
--- a/plugins/alsa/alsa-utils-dump.c
+++ b/plugins/alsa/alsa-utils-dump.c
@@ -67,7 +67,7 @@ PUBLIC void AlsaDumpFormats(CtlSourceT *source, snd_pcm_t *pcmHandle) {
snd_pcm_hw_params_alloca(&pxmHwParams);
snd_pcm_hw_params_any(pcmHandle, pxmHwParams);
- AFB_ApiNotice(source->api, "Available formats: PCM=%s", AlsaPcmUID(pcmHandle, string));
+ AFB_ApiNotice(source->api, "Available formats: PCM=%s", ALSA_PCM_UID(pcmHandle, string));
for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
if (snd_pcm_hw_params_test_format(pcmHandle, pxmHwParams, format) == 0) {
AFB_ApiNotice(source->api, "- %s", snd_pcm_format_name(format));