summaryrefslogtreecommitdiffstats
path: root/plugins/alsa
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/alsa')
-rw-r--r--plugins/alsa/alsa-api-mixer.c9
-rw-r--r--plugins/alsa/alsa-api-pcm.c4
-rw-r--r--plugins/alsa/alsa-api-streams.c12
-rw-r--r--plugins/alsa/alsa-core-ctl.c128
-rw-r--r--plugins/alsa/alsa-core-pcm.c170
-rw-r--r--plugins/alsa/alsa-softmixer.c4
-rw-r--r--plugins/alsa/alsa-softmixer.h62
-rw-r--r--plugins/alsa/alsa-utils-bypath.c4
8 files changed, 286 insertions, 107 deletions
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c
index e3538f8..ebb3f10 100644
--- a/plugins/alsa/alsa-api-mixer.c
+++ b/plugins/alsa/alsa-api-mixer.c
@@ -31,6 +31,7 @@ static void MixerRemoveVerb(AFB_ReqT request) {
for (int idx = 0; mixer->streams[idx]->uid; idx++) {
AlsaStreamAudioT *stream = mixer->streams[idx];
+ AlsaPcmCopyHandleT * copy = stream->copy;
AFB_ApiNotice(mixer->api, "cleaning mixer=%s stream=%s", mixer->uid, stream->uid);
@@ -47,10 +48,10 @@ static void MixerRemoveVerb(AFB_ReqT request) {
}
// free audio-stream dynamic structures
- snd_pcm_close(mixer->streams[idx]->copy->pcmIn);
- snd_pcm_close(mixer->streams[idx]->copy->pcmOut);
- if (stream->copy->evtsrc) sd_event_source_unref(stream->copy->evtsrc);
- if (stream->copy->sdLoop) sd_event_unref(stream->copy->sdLoop);
+ snd_pcm_close(copy->pcmIn->handle);
+ snd_pcm_close(copy->pcmOut->handle);
+ if (copy->evtsrc) sd_event_source_unref(copy->evtsrc);
+ if (copy->sdLoop) sd_event_unref(copy->sdLoop);
}
// // (Fulup to be Done) registry is attached to source
diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c
index f8a2414..a51bb6f 100644
--- a/plugins/alsa/alsa-api-pcm.c
+++ b/plugins/alsa/alsa-api-pcm.c
@@ -521,7 +521,9 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm
, "mute", &muteJ
);
if (error) {
- AFB_ApiNotice(mixer->api, "ApiPcmAttachOne: source missing [volume]|[mute] error=%s control=%s", wrap_json_get_error_string(error), json_object_get_string(controlsJ));
+ AFB_ApiNotice(mixer->api,
+ "%s: source missing [volume]|[mute] error=%s control=%s",
+ __func__, wrap_json_get_error_string(error), json_object_get_string(controlsJ));
goto OnErrorExit;
}
diff --git a/plugins/alsa/alsa-api-streams.c b/plugins/alsa/alsa-api-streams.c
index dab7748..cf54d91 100644
--- a/plugins/alsa/alsa-api-streams.c
+++ b/plugins/alsa/alsa-api-streams.c
@@ -20,6 +20,7 @@
#include "alsa-softmixer.h"
#include <string.h>
+#include <stdbool.h>
// Set stream volume control in %
#define VOL_CONTROL_MAX 100
@@ -56,6 +57,7 @@ STATIC void StreamApiVerbCB(AFB_ReqT request) {
, "volume", &volumeJ
, "ramp", &rampJ
);
+
if (error) {
AFB_ReqFailF(request, "syntax-error", "Missing 'close|mute|volume|verbose' args=%s", json_object_get_string(argsJ));
goto OnErrorExit;
@@ -82,9 +84,9 @@ STATIC void StreamApiVerbCB(AFB_ReqT request) {
}
if (doMute != -1) {
- error = AlsaCtlNumidSetLong(mixer, handle->sndcard, handle->stream->mute, !mute);
+ error = AlsaCtlNumidSetLong(mixer, handle->sndcard, handle->stream->mute, doMute);
if (error) {
- AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%d", handle->stream->volume, !mute);
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%d", handle->stream->volume, !doMute);
goto OnErrorExit;
}
@@ -194,8 +196,8 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT
char *volName = NULL;
AFB_ApiInfo(mixer->api,
- "%s, stream %s %s, source %s, sink %s\n",
- __func__,uid, stream->uid, stream->source, stream->sink);
+ "%s, stream %s %s, source %s, sink %s, mute %d",
+ __func__,uid, stream->uid, stream->source, stream->sink, stream->mute);
loopDev = ApiLoopFindSubdev(mixer, stream->uid, stream->source, &loop);
if (loopDev) {
@@ -236,6 +238,8 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT
AlsaPcmCtlT *capturePcm = AlsaByPathOpenPcm(mixer, captureDev, SND_PCM_STREAM_CAPTURE);
if (!capturePcm) goto OnErrorExit;
+ capturePcm->mute = stream->mute;
+
// Registry capturePcm PCM for active/pause event
if (loopDev && loopDev->numid) {
error = AlsaCtlRegister(mixer, captureCard, capturePcm, FONTEND_NUMID_RUN, loopDev->numid);
diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c
index bdf6bf5..dee8c0b 100644
--- a/plugins/alsa/alsa-core-ctl.c
+++ b/plugins/alsa/alsa-core-ctl.c
@@ -46,18 +46,24 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT *
snd_ctl_elem_list_alloca(&ctlList);
if ((error = snd_ctl_elem_list(sndcard->ctl, ctlList)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNumidElemId [%s] fail retrieve controls", ALSA_CTL_UID(sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s [%s] fail retrieve controls",
+ __func__, ALSA_CTL_UID(sndcard->ctl, string));
goto OnErrorExit;
}
if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNumidElemId [%s] fail retrieve count", ALSA_CTL_UID(sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s [%s] fail retrieve count",
+ __func__, ALSA_CTL_UID(sndcard->ctl, 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(sndcard->ctl, ctlList)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNumidElemId [%s] fail retrieve controls", ALSA_CTL_UID(sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s [%s] fail retrieve controls",
+ __func__, ALSA_CTL_UID(sndcard->ctl, string));
goto OnErrorExit;
}
@@ -73,7 +79,9 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT *
}
if (index == ctlCount) {
- AFB_ApiNotice(mixer->api, "AlsaCtlGetNumidElemId [%s] fail get numid=%i count", ALSA_CTL_UID(sndcard->ctl, string), numid);
+ AFB_ApiNotice(mixer->api,
+ "%s [%s] fail get numid=%i count",
+ __func__, ALSA_CTL_UID(sndcard->ctl, string), numid);
goto OnErrorExit;
}
@@ -95,18 +103,24 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *s
snd_ctl_elem_list_alloca(&ctlList);
if ((error = snd_ctl_elem_list(sndcard->ctl, ctlList)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNameElemId cardid='%s' cardname='%s' fail retrieve controls", sndcard->cid.cardid, sndcard->cid.name);
+ AFB_ApiError(mixer->api,
+ "%s cardid='%s' cardname='%s' fail retrieve controls",
+ __func__, sndcard->cid.cardid, sndcard->cid.name);
goto OnErrorExit;
}
if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNameElemId cardid='%s' cardname='%s' fail retrieve count", sndcard->cid.cardid, sndcard->cid.name);
+ AFB_ApiError(mixer->api,
+ "%s cardid='%s' cardname='%s' fail retrieve count",
+ __func__, sndcard->cid.cardid, sndcard->cid.name);
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(sndcard->ctl, ctlList)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlGetNameElemId cardid='%s' cardname='%s' fail retrieve controls", sndcard->cid.cardid, sndcard->cid.name);
+ AFB_ApiError(mixer->api,
+ "%s cardid='%s' cardname='%s' fail retrieve controls",
+ __func__, sndcard->cid.cardid, sndcard->cid.name);
goto OnErrorExit;
}
@@ -291,13 +305,17 @@ PUBLIC int AlsaCtlNumidSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi
snd_ctl_elem_id_t *elemId = AlsaCtlGetNumidElemId(mixer, sndcard, numid);
if (!elemId) {
- AFB_ApiError(mixer->api, "AlsaCtlNumidSetLong cardid=%s cardname=%s fail to find numid=%d", sndcard->cid.cardid, sndcard->cid.longname, numid);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to find numid=%d",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, numid);
goto OnErrorExit;
}
int error = CtlElemIdSetLong(mixer, sndcard, elemId, value);
if (error) {
- AFB_ApiError(mixer->api, "AlsaCtlNumidSetLong cardid=%s cardname=%s fail to set numid=%d value=%ld", sndcard->cid.cardid, sndcard->cid.longname, numid, value);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to set numid=%d value=%ld",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, numid, value);
goto OnErrorExit;
}
@@ -310,13 +328,17 @@ PUBLIC int AlsaCtlNumidGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi
snd_ctl_elem_id_t *elemId = AlsaCtlGetNumidElemId(mixer, sndcard, numid);
if (!elemId) {
- AFB_ApiError(mixer->api, "AlsaCtlNumidGetLong cardid=%s cardname=%s fail to find numid=%d", sndcard->cid.cardid, sndcard->cid.longname, numid);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to find numid=%d",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, numid);
goto OnErrorExit;
}
int error = CtlElemIdGetLong(mixer, sndcard, elemId, value);
if (error) {
- AFB_ApiError(mixer->api, "AlsaCtlNumidGetLong cardid=%s cardname=%s fail to get numid=%d value", sndcard->cid.cardid, sndcard->cid.longname, numid);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to get numid=%d value",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, numid);
goto OnErrorExit;
}
@@ -329,13 +351,17 @@ PUBLIC int AlsaCtlNameSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha
snd_ctl_elem_id_t *elemId = AlsaCtlGetNameElemId(mixer, sndcard, ctlName);
if (!elemId) {
- AFB_ApiError(mixer->api, "AlsaCtlNameSetLong cardid=%s cardname=%s fail to find crlName=%s", sndcard->cid.cardid, sndcard->cid.longname, ctlName);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to find crlName=%s",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
goto OnErrorExit;
}
int error = CtlElemIdSetLong(mixer, sndcard, elemId, value);
if (error) {
- AFB_ApiError(mixer->api, "AlsaCtlNameSetLong cardid=%s cardname=%s fail to set crlName=%s value=%ld", sndcard->cid.cardid, sndcard->cid.longname, ctlName, value);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to set crlName=%s value=%ld",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName, value);
goto OnErrorExit;
}
@@ -348,13 +374,17 @@ PUBLIC int AlsaCtlNameGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha
snd_ctl_elem_id_t *elemId = AlsaCtlGetNameElemId(mixer, sndcard, ctlName);
if (!elemId) {
- AFB_ApiError(mixer->api, "AlsaCtlNameGetLong cardid=%s cardname=%s fail to find crlName=%s", sndcard->cid.cardid, sndcard->cid.longname, ctlName);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to find crlName=%s",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
goto OnErrorExit;
}
int error = CtlElemIdGetLong(mixer, sndcard, elemId, value);
if (error) {
- AFB_ApiError(mixer->api, "AlsaCtlNameGetLong cardid=%s cardname=%s fail to get crlName=%s value", sndcard->cid.cardid, sndcard->cid.longname, ctlName);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to get crlName=%s value",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
goto OnErrorExit;
}
@@ -395,7 +425,9 @@ STATIC int AlsaCtlMakeControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha
break;
default:
- AFB_ApiError(mixer->api, "AlsaCtlMakeControl: mixer=%s cardid=%s cardname=%s fail to create %s(control)", mixer->uid, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s cardname=%s fail to create %s(control)",
+ __func__, mixer->uid, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
goto OnErrorExit;
}
@@ -418,7 +450,9 @@ PUBLIC int AlsaCtlCreateControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, char* c
// create or get numid control when already exist
numid = AlsaCtlMakeControl(mixer, sndcard, ctlName, ctlCount, ctlMin, ctlMax, ctlStep);
if (numid <= 0) {
- AFB_ApiError(mixer->api, "AlsaCtlCreateControl cardid=%s cardname=%s fail to create ctlName=%s", sndcard->cid.cardid, sndcard->cid.longname, ctlName);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to create ctlName=%s",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName);
goto OnErrorExit;
}
@@ -427,11 +461,15 @@ PUBLIC int AlsaCtlCreateControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, char* c
int error = CtlElemIdSetLong(mixer, sndcard, elemId, value);
if (error) {
- AFB_ApiError(mixer->api, "AlsaCtlCreateControl cardid=%s cardname=%s fail to set ctlName=%s Numid=%d", sndcard->cid.cardid, sndcard->cid.longname, ctlName, numid);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s fail to set ctlName=%s Numid=%d",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName, numid);
goto OnErrorExit;
}
- AFB_ApiNotice(mixer->api, "AlsaCtlCreateControl cardid=%s cardname=%s ctl create name=%s numid=%d value=%ld", sndcard->cid.cardid, sndcard->cid.longname, ctlName, numid, value);
+ AFB_ApiNotice(mixer->api,
+ "%s cardid=%s cardname=%s ctl create name=%s numid=%d value=%ld",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName, numid, value);
return numid;
OnErrorExit:
return -1;
@@ -448,7 +486,7 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v
int index;
if ((revents & EPOLLHUP) != 0) {
- AFB_ApiNotice(mixer->api, "CtlSubscribeEventCB hanghup [card:%s disconnected]", sHandle->uid);
+ AFB_ApiNotice(mixer->api, "%s hanghup [card:%s disconnected]", __func__, sHandle->uid);
goto OnSuccessExit;
}
@@ -482,33 +520,46 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v
const char *name= snd_ctl_elem_info_get_name(elemInfo);
for (index = 0; sndcard->registry[index]; index++) {
- if (sndcard->registry[index]->numid == numid) {
-
- switch (sndcard->registry[index]->type) {
+ RegistryEntryPcmT * reg = sndcard->registry[index];
+ if (reg->numid == numid) {
+ int ret;
+ switch (reg->type) {
case FONTEND_NUMID_RUN:
- (void) snd_pcm_pause(sndcard->registry[index]->pcm->handle, (int) (!value));
- AFB_ApiNotice(mixer->api, "CtlSubscribeEventCB:%s numid=%d name=%s active=%ld", sHandle->uid, numid, name, value);
+ reg->pcm->mute = !value;
+ ret = snd_pcm_pause(reg->pcm->handle, (int) (!value));
+ AFB_ApiNotice(mixer->api, "%s:%s numid=%d name=%s active=%ld ret %d",
+ __func__, sHandle->uid, numid, name, value, ret);
+ if (ret < 0) {
+ AFB_ApiNotice(mixer->api, "%s error: %s", __func__, snd_strerror(ret));
+ }
break;
case FONTEND_NUMID_PAUSE:
- AFB_ApiNotice(mixer->api, "CtlSubscribeEventCB:%s numid=%d name=%s pause=%ld", sHandle->uid, numid, name, value);
- (void) snd_pcm_pause(sndcard->registry[index]->pcm->handle, (int) value);
+ reg->pcm->mute = value;
+ ret = snd_pcm_pause(reg->pcm->handle, (int) value);
+ AFB_ApiNotice(mixer->api, "%s:%s numid=%d name=%s pause=%ld ret %d",
+ __func__, sHandle->uid, numid, name, value, ret);
+ if (ret < 0) {
+ AFB_ApiNotice(mixer->api, "%s error %s", __func__, snd_strerror(ret));
+ }
break;
case FONTEND_NUMID_IGNORE:
default:
- AFB_ApiInfo(mixer->api, "CtlSubscribeEventCB:%s numid=%d name=%s ignored=%ld", sHandle->uid, numid, name, value);
+ AFB_ApiInfo(mixer->api,
+ "%s:%s numid=%d name=%s ignored=%ld",
+ __func__, sHandle->uid, numid, name, value);
}
break;
}
}
if (index == sndcard->rcount) {
- AFB_ApiNotice(mixer->api, "CtlSubscribeEventCB:%s numid=%d (unknown)", sHandle->uid, numid);
+ AFB_ApiNotice(mixer->api, "%s:%s numid=%d (unknown)", __func__, sHandle->uid, numid);
}
OnSuccessExit:
return 0;
OnErrorExit:
- AFB_ApiInfo(mixer->api, "CtlSubscribeEventCB: ignored unsupported event");
+ AFB_ApiInfo(mixer->api, "%s: ignored unsupported event", __func__);
return 0;
}
@@ -543,23 +594,28 @@ PUBLIC int AlsaCtlSubscribe(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *snd
// subscribe for sndctl events attached to cardid
if ((error = snd_ctl_subscribe_events(handle->sndcard->ctl, 1)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlSubscribe: fail sndcard=%s to subscribe events", ALSA_CTL_UID(handle->sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s: fail sndcard=%s to subscribe events",
+ __func__, ALSA_CTL_UID(handle->sndcard->ctl, string));
goto OnErrorExit;
}
// get pollfd attach to this sound board
int count = snd_ctl_poll_descriptors(handle->sndcard->ctl, &pfds, 1);
if (count != 1) {
- AFB_ApiError(mixer->api, "AlsaCtlSubscribe: fail sndcard=%s get poll descriptors", ALSA_CTL_UID(handle->sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s: fail sndcard=%s get poll descriptors",
+ __func__, ALSA_CTL_UID(handle->sndcard->ctl, string));
goto OnErrorExit;
}
// Registry sound event to binder main loop
if ((error = sd_event_add_io(mixer->sdLoop, &handle->evtsrc, pfds.fd, EPOLLIN, CtlSubscribeEventCB, handle)) < 0) {
- AFB_ApiError(mixer->api, "AlsaCtlSubscribe: Fail sndcard=%s adding mainloop", ALSA_CTL_UID(handle->sndcard->ctl, string));
+ AFB_ApiError(mixer->api,
+ "%s: Fail sndcard=%s adding mainloop",
+ __func__, ALSA_CTL_UID(handle->sndcard->ctl, string));
goto OnErrorExit;
}
-
return 0;
OnErrorExit:
@@ -574,7 +630,9 @@ PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT
}
if (index == sndcard->rcount) {
- AFB_ApiError(mixer->api, "AlsaCtlRegister cardid=%s cardname=%s to many audio stream max=%ld", sndcard->cid.cardid, sndcard->cid.longname, sndcard->rcount);
+ AFB_ApiError(mixer->api,
+ "%s cardid=%s cardname=%s to many audio stream max=%ld",
+ __func__, sndcard->cid.cardid, sndcard->cid.longname, sndcard->rcount);
goto OnErrorExit;
}
diff --git a/plugins/alsa/alsa-core-pcm.c b/plugins/alsa/alsa-core-pcm.c
index cc3d2f6..885d2bf 100644
--- a/plugins/alsa/alsa-core-pcm.c
+++ b/plugins/alsa/alsa-core-pcm.c
@@ -69,13 +69,15 @@ STATIC int AlsaPeriodSize(snd_pcm_format_t pcmFormat) {
return pcmSampleSize;
}
-PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts, int mode) {
+PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) {
int error;
snd_pcm_hw_params_t *pxmHwParams;
snd_pcm_sw_params_t *pxmSwParams;
snd_pcm_format_t format;
snd_pcm_access_t access;
+ AlsaPcmHwInfoT * opts = pcm->params;
+
AFB_ApiInfo(mixer->api,
"%s: mixer info %s uid %s , pcm %s, mode %d",
__func__, mixer->info, mixer->uid, pcm->cid.cardid, mode);
@@ -114,23 +116,33 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts
}
}
- if (opts->rate > 0) {
+ if (opts->rate > 0 ) {
+
+ AFB_ApiInfo(mixer->api," %s: set rate to %d", __func__, opts->rate);
unsigned int pcmRate = opts->rate;
- if ((error = snd_pcm_hw_params_set_rate_near(pcm->handle, pxmHwParams, &opts->rate, 0)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s FailSet_Rate=%d error=%s", mixer->uid, pcm->cid.cardid, opts->rate, snd_strerror(error));
+ /* Attempt to set the rate. Failing on a capture dev is acceptable */
+ error = snd_pcm_hw_params_set_rate_near(pcm->handle, pxmHwParams, &opts->rate, 0);
+ if ( mode == SND_PCM_STREAM_PLAYBACK && error < 0) {
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s FailSet_Rate=%d error=%s",
+ __func__, mixer->uid, pcm->cid.cardid, opts->rate, snd_strerror(error));
goto OnErrorExit;
}
// check we got requested rate
- if (opts->rate != pcmRate) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Set_Rate Fail ask=%dHz get=%dHz", mixer->uid, pcm->cid.cardid,pcmRate, opts->rate);
+ if (mode == SND_PCM_STREAM_PLAYBACK && opts->rate != pcmRate) {
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s Set_Rate Fail ask=%dHz get=%dHz",
+ __func__, mixer->uid, pcm->cid.cardid,pcmRate, opts->rate);
goto OnErrorExit;
}
}
if (opts->channels) {
if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, opts->channels)) < 0) {
- AFB_ApiError(mixer->api, "AlsaPcmConf: mixer=%s cardid=%s Set_Channels=%d Fail error=%s",mixer->uid, pcm->cid.cardid, opts->channels, snd_strerror(error));
+ AFB_ApiError(mixer->api,
+ "%s: mixer=%s cardid=%s Set_Channels=%d Fail error=%s",
+ __func__, mixer->uid, pcm->cid.cardid, opts->channels, snd_strerror(error));
goto OnErrorExit;
};
}
@@ -223,11 +235,14 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
snd_pcm_sframes_t availIn, availOut, availInBuf;
int err;
+ snd_pcm_t * pcmIn = pcmCopyHandle->pcmIn->handle;
+ snd_pcm_t * pcmOut= pcmCopyHandle->pcmOut->handle;
+
// PCM has was closed
if ((pfd->revents & POLLHUP) != 0) {
AFB_ApiNotice(pcmCopyHandle->api,
"%s PCM=%s hanghup/disconnected",
- __func__, ALSA_PCM_UID(pcmCopyHandle->pcmIn, string));
+ __func__, ALSA_PCM_UID(pcmIn, string));
goto ExitOnSuccess;
}
@@ -237,11 +252,11 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
}
// do we have waiting frame
- availIn = snd_pcm_avail_update(pcmCopyHandle->pcmIn);
+ availIn = snd_pcm_avail_update(pcmIn);
if (availIn <= 0) {
if (availIn == -EPIPE) {
- printf("XXX read EPIPE\n");
- xrun(pcmCopyHandle->pcmIn);
+ int ret = xrun(pcmIn);
+ printf("XXX read EPIPE (recov=%d)\n", ret);
}
goto ExitOnSuccess;
}
@@ -263,7 +278,7 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
r = pcmCopyHandle->buf_size - pcmCopyHandle->buf_pos;
if (r > availIn)
r = availIn;
- r = snd_pcm_readi(pcmCopyHandle->pcmIn,
+ r = snd_pcm_readi(pcmIn,
pcmCopyHandle->buf +
pcmCopyHandle->buf_pos *
pcmCopyHandle->frame_size, r);
@@ -271,12 +286,11 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
goto ExitOnSuccess;
if (r < 0) {
if (r == -EPIPE) {
- printf("read EPIPE (%d)\n", ++pcmCopyHandle->read_err_count);
- err = xrun(pcmCopyHandle->pcmIn);
+ printf("read EPIPE (%d), recov %d\n", ++pcmCopyHandle->read_err_count, xrun(pcmIn));
goto ExitOnSuccess;
} else if (r == -ESTRPIPE) {
printf("read ESTRPIPE\n");
- if ((err = suspend(pcmCopyHandle->pcmIn)) < 0)
+ if ((err = suspend(pcmIn)) < 0)
goto ExitOnSuccess;
r = 0;
} else {
@@ -293,16 +307,16 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
}
// do we have space to push frame
- availOut = snd_pcm_avail_update(pcmCopyHandle->pcmOut);
+ availOut = snd_pcm_avail_update(pcmOut);
if (availOut < 0) {
if (availOut == -EPIPE) {
printf("write update EPIPE\n");
- xrun(pcmCopyHandle->pcmOut);
+ xrun(pcmOut);
goto ExitOnSuccess;
}
if (availOut == -ESTRPIPE) {
printf("write update ESTRPIPE\n");
- suspend(pcmCopyHandle->pcmOut);
+ suspend(pcmOut);
goto ExitOnSuccess;
}
}
@@ -322,14 +336,14 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
r = availOut;
r = snd_pcm_writei(
- pcmCopyHandle->pcmOut,
+ pcmOut,
pcmCopyHandle->buf +
pcmCopyHandle->buf_pos *
pcmCopyHandle->frame_size, r);
if (r <= 0) {
if (r == -EPIPE) {
- printf("XXX write EPIPE (%d)\n", ++pcmCopyHandle->write_err_count );
- err = xrun(pcmCopyHandle->pcmOut);
+ printf("XXX write EPIPE (%d), recov %d\n", ++pcmCopyHandle->write_err_count , xrun(pcmOut));
+
continue;
} else if (r == -ESTRPIPE) {
printf("XXX write ESTRPIPE\n");
@@ -350,10 +364,10 @@ STATIC int AlsaPcmReadCB( struct pollfd * pfd, AlsaPcmCopyHandleT * pcmCopyHandl
* before the loop. If we ignore a new bigger value, we will keep
* writing small chunks, keep in tight loops and stave the CPU */
- snd_pcm_sframes_t newAvailOut = snd_pcm_avail(pcmCopyHandle->pcmOut);
+ snd_pcm_sframes_t newAvailOut = snd_pcm_avail(pcmOut);
if (newAvailOut == 0) {
- snd_pcm_wait(pcmCopyHandle->pcmOut, 5);
+ snd_pcm_wait(pcmOut, 5);
} else if (newAvailOut > 0) {
availOut = newAvailOut;
}
@@ -390,30 +404,111 @@ static int suspend( snd_pcm_t * pcm)
return 0;
}
+static int capturePcmReopen(AlsaPcmCopyHandleT * pcmCopyHandle) {
+ int res = -1;
+ int err;
+ char string[32];
+
+ err = snd_pcm_open(&pcmCopyHandle->pcmIn->handle,
+ pcmCopyHandle->pcmIn->cid.cardid,
+ SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+
+ if (err < 0) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: failed to re-open pcm", __func__);
+ goto OnErrorExit;
+ };
+
+ // prepare PCM for capture
+ err = AlsaPcmConf(pcmCopyHandle->pcmIn->mixer, pcmCopyHandle->pcmIn, SND_PCM_STREAM_CAPTURE);
+ if (err) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: PCM configuration failed", __func__);
+ goto OnErrorExit;
+ }
+
+ err = snd_pcm_prepare(pcmCopyHandle->pcmIn->handle);
+ if (err < 0) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: failed to prepare PCM, %s", __func__, snd_strerror(err));
+ goto OnErrorExit;
+ };
+
+ err = snd_pcm_start(pcmCopyHandle->pcmIn->handle);
+ if (err < 0) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: failed start capture PCM: %s",__func__, snd_strerror(err));
+ goto OnErrorExit;
+ };
+
+ struct pollfd * pcmInFds;
+
+ int pcmInCount = snd_pcm_poll_descriptors_count(pcmCopyHandle->pcmIn->handle);
+ pcmInFds = malloc(sizeof (*pcmInFds) * pcmInCount);
+
+ if ((err = snd_pcm_poll_descriptors(pcmCopyHandle->pcmIn->handle, pcmInFds, pcmInCount)) < 0) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: Fail pcmIn=%s get pollfds error=%s",
+ __func__, ALSA_PCM_UID(pcmCopyHandle->pcmIn->handle, string), snd_strerror(err));
+ goto OnErrorExit;
+ };
+
+ /* free old descriptors */
+ free(pcmCopyHandle->pollFds);
+ pcmCopyHandle->pollFds = pcmInFds;
+ pcmCopyHandle->pcmInCount = pcmInCount;
+
+ res = 0;
+
+OnErrorExit:
+ return res;
+}
static void *LoopInThread(void *handle) {
+#define LOOP_TIMEOUT_MSEC 10*1000
+
AlsaPcmCopyHandleT *pcmCopyHandle = (AlsaPcmCopyHandleT*) handle;
pcmCopyHandle->tid = (int) syscall(SYS_gettid);
AFB_ApiNotice(pcmCopyHandle->api,
- "%s :%s/%d Started",
- __func__, pcmCopyHandle->info, pcmCopyHandle->tid);
+ "%s :%s/%d Started, mute %d",
+ __func__, pcmCopyHandle->info, pcmCopyHandle->tid, pcmCopyHandle->pcmIn->mute);
for (int ix=0; ix<pcmCopyHandle->pcmInCount; ix++) {
struct pollfd * pfd = &pcmCopyHandle->pollFds[ix];
pfd->events = POLLIN | POLLHUP;
}
+ bool muted = false;
+
/* loop until end */
for (;;) {
- int err = poll(pcmCopyHandle->pollFds, pcmCopyHandle->pcmInCount, 5000); // TODO
+ if (pcmCopyHandle->pcmIn->mute) {
+ if (!muted) {
+ int err;
+ muted = true;
+
+ err = snd_pcm_close(pcmCopyHandle->pcmIn->handle);
+ if (err < 0) AFB_ApiNotice(pcmCopyHandle->api, "failed to close capture fd\n");
+
+ AFB_ApiNotice(pcmCopyHandle->api, "capture muted");
+ }
+ sleep(1);
+ continue;
+ }
+
+ if (muted) {
+ if (capturePcmReopen(pcmCopyHandle) < 0)
+ goto OnErrorExit;
- if (err < 0)
+ muted = false;
+ }
+
+ int err = poll(pcmCopyHandle->pollFds, pcmCopyHandle->pcmInCount, LOOP_TIMEOUT_MSEC);
+ if (err < 0) {
+ AFB_ApiError(pcmCopyHandle->api, "%s: poll err %s", __func__, strerror(errno));
continue;
+ }
if (err == 0) {
/* timeout */
+ AFB_ApiInfo(pcmCopyHandle->api, "%s(%s) alive", __func__, pcmCopyHandle->pcmIn->cid.cardid );
continue;
}
@@ -421,6 +516,7 @@ static void *LoopInThread(void *handle) {
AlsaPcmReadCB(&pcmCopyHandle->pollFds[ix], pcmCopyHandle);
}
+OnErrorExit:
pthread_exit(0);
}
@@ -442,8 +538,18 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
AFB_ApiInfo(mixer->api, "%s: Configure CAPTURE PCM", __func__);
+ /* remember configuration of capture */
+ pcmIn->params = (AlsaPcmHwInfoT*)malloc(sizeof(AlsaPcmHwInfoT));
+ memcpy(pcmIn->params, opts, sizeof(AlsaPcmHwInfoT));
+
+ pcmOut->params = (AlsaPcmHwInfoT*)malloc(sizeof(AlsaPcmHwInfoT));
+ memcpy(pcmOut->params, opts, sizeof(AlsaPcmHwInfoT));
+
+ pcmIn->mixer = mixer;
+ pcmOut->mixer = mixer;
+
// prepare PCM for capture and replay
- error = AlsaPcmConf(mixer, pcmIn, opts, SND_PCM_STREAM_CAPTURE);
+ error = AlsaPcmConf(mixer, pcmIn, SND_PCM_STREAM_CAPTURE);
if (error) {
AFB_ApiError(mixer->api, "%s: PCM configuration for capture failed", __func__);
goto OnErrorExit;
@@ -452,7 +558,7 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
AFB_ApiInfo(mixer->api, "%s: Configure PLAYBACK PCM", __func__);
// input and output should match
- error = AlsaPcmConf(mixer, pcmOut, opts, SND_PCM_STREAM_PLAYBACK);
+ error = AlsaPcmConf(mixer, pcmOut, SND_PCM_STREAM_PLAYBACK);
if (error) {
AFB_ApiError(mixer->api, "%s: PCM configuration for playback failed", __func__);
goto OnErrorExit;
@@ -485,8 +591,8 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
AlsaPcmCopyHandleT *cHandle= calloc(1, sizeof(AlsaPcmCopyHandleT));
cHandle->info = "pcmCpy";
- cHandle->pcmIn = pcmIn->handle;
- cHandle->pcmOut = pcmOut->handle;
+ cHandle->pcmIn = pcmIn;
+ cHandle->pcmOut = pcmOut;
cHandle->api = mixer->api;
cHandle->channels = opts->channels;
@@ -509,7 +615,7 @@ PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT
AFB_ApiInfo(mixer->api, "%s Copy buf size is %zu", __func__, size);
// get FD poll descriptor for capture PCM
- int pcmInCount = snd_pcm_poll_descriptors_count(cHandle->pcmIn);
+ int pcmInCount = snd_pcm_poll_descriptors_count(pcmIn->handle);
if (pcmInCount <= 0) {
AFB_ApiError(mixer->api,
"%s: Fail pcmIn=%s get fds count error=%s",
diff --git a/plugins/alsa/alsa-softmixer.c b/plugins/alsa/alsa-softmixer.c
index 27dba3c..c8b50a0 100644
--- a/plugins/alsa/alsa-softmixer.c
+++ b/plugins/alsa/alsa-softmixer.c
@@ -25,8 +25,8 @@
CTLP_LUA_REGISTER("alsa-softmixer")
// Call at initialisation time
-CTLP_ONLOAD(plugin, callbacks) {
- AFB_ApiDebug(plugin->api, "SoftMixer Plugin Registered: uid='%s' 'info='%s'", plugin->uid, plugin->info);
+CTLP_ONLOAD(plugin, callbacks){
+// AFB_ApiDebug(plugin->api, "SoftMixer Plugin Registered: uid='%s' 'info='%s'", plugin->uid, plugin->info);
return 0;
}
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index 481188b..8a8ad40 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -79,8 +79,37 @@ typedef enum {
} RegistryNumidT;
typedef struct {
- snd_pcm_t *pcmIn;
- snd_pcm_t *pcmOut;
+ int cardidx;
+ const char *devpath;
+ const char *cardid;
+ const char *name;
+ const char *longname;
+ int device;
+ int subdev;
+} AlsaDevInfoT;
+
+typedef struct {
+ unsigned int rate;
+ unsigned int channels;
+ const char *formatS;
+ snd_pcm_format_t format;
+ snd_pcm_access_t access;
+ size_t sampleSize;
+} AlsaPcmHwInfoT;
+
+typedef struct {
+ int ccount;
+ bool mute;
+ AlsaDevInfoT cid;
+ snd_pcm_t *handle;
+ AlsaPcmHwInfoT *params;
+
+ void * mixer;
+} AlsaPcmCtlT;
+
+typedef struct {
+ AlsaPcmCtlT *pcmIn;
+ AlsaPcmCtlT *pcmOut;
AFB_ApiT api;
sd_event_source* evtsrc;
@@ -121,14 +150,7 @@ typedef struct {
int port;
} AlsaPcmChannelT;
-typedef struct {
- unsigned int rate;
- unsigned int channels;
- const char *formatS;
- snd_pcm_format_t format;
- snd_pcm_access_t access;
- size_t sampleSize;
-} AlsaPcmHwInfoT;
+
typedef struct {
const char *uid;
@@ -137,23 +159,9 @@ typedef struct {
int stepUp; // linear %
} AlsaVolRampT;
-typedef struct {
- int cardidx;
- const char *devpath;
- const char *cardid;
- const char *name;
- const char *longname;
- int device;
- int subdev;
-} AlsaDevInfoT;
-typedef struct {
- int ccount;
- AlsaDevInfoT cid;
- snd_pcm_t *handle;
- AlsaPcmHwInfoT *params;
- uint32_t avail_min;
-} AlsaPcmCtlT;
+
+
typedef struct {
int numid;
@@ -274,7 +282,7 @@ PUBLIC int AlsaCtlSubscribe(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *snd
PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT *pcmdev, RegistryNumidT type, int numid);
// alsa-core-pcm.c
-PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, AlsaPcmHwInfoT *opts, int mode);
+PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode);
PUBLIC int AlsaPcmCopy(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcmCtlT *pcmIn, AlsaPcmCtlT *pcmOut, AlsaPcmHwInfoT * opts);
// alsa-plug-*.c _snd_pcm_PLUGIN_open_ see macro ALSA_PLUG_PROTO(plugin)
diff --git a/plugins/alsa/alsa-utils-bypath.c b/plugins/alsa/alsa-utils-bypath.c
index 71810c2..2f22333 100644
--- a/plugins/alsa/alsa-utils-bypath.c
+++ b/plugins/alsa/alsa-utils-bypath.c
@@ -88,12 +88,12 @@ PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcm(SoftMixerT *mixer, AlsaDevInfoT *pcmDev, s
pcmCtl->cid.longname=NULL;
AFB_ApiInfo(mixer->api,
- "%s OPEN PCM %s, direction %s",
+ "%s OPEN PCM '%s', direction %s",
__func__, pcmCtl->cid.cardid, direction==SND_PCM_STREAM_PLAYBACK?"playback":"capture");
error = snd_pcm_open(&pcmCtl->handle, pcmCtl->cid.cardid, direction, SND_PCM_NONBLOCK);
if (error < 0) {
- AFB_ApiError(mixer->api, "AlsaByPathOpenPcm: fail openpcm cardid=%s error=%s", pcmCtl->cid.cardid, snd_strerror(error));
+ AFB_ApiError(mixer->api, "%s: fail openpcm cardid=%s error=%s", __func__, pcmCtl->cid.cardid, snd_strerror(error));
goto OnErrorExit;
}