diff options
author | Thierry Bultel <thierry.bultel@iot.bzh> | 2018-07-11 17:50:44 +0200 |
---|---|---|
committer | Thierry Bultel <thierry.bultel@iot.bzh> | 2018-07-11 17:50:44 +0200 |
commit | 283bf0a4ab7dbd6f4393f6a1b4ef5a201ee92f62 (patch) | |
tree | d0ece00821901244465ef5fb3694389430db3085 /plugins | |
parent | afd9f87786fe0cc3070ec976b89399603112c845 (diff) |
stops the read/write loop when the stream is muted
when the stream is muted (due to the configuration, or
due to a HAL request), the read/write loop is stopped.
The benefit is that muting will work with capture devices
that do not implement the mute in their driver.
The inconvenient of stopping the read loop is that it
has made appear an unexpected side-effect: the poll on
capture does not trig for further incoming frames.
The workaround is to completely close, then reopen
and configure the capture PCM.
Signed-off-by: Thierry Bultel <thierry.bultel@iot.bzh>
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/alsa/alsa-api-mixer.c | 9 | ||||
-rw-r--r-- | plugins/alsa/alsa-api-pcm.c | 4 | ||||
-rw-r--r-- | plugins/alsa/alsa-api-streams.c | 12 | ||||
-rw-r--r-- | plugins/alsa/alsa-core-ctl.c | 128 | ||||
-rw-r--r-- | plugins/alsa/alsa-core-pcm.c | 170 | ||||
-rw-r--r-- | plugins/alsa/alsa-softmixer.c | 4 | ||||
-rw-r--r-- | plugins/alsa/alsa-softmixer.h | 62 | ||||
-rw-r--r-- | plugins/alsa/alsa-utils-bypath.c | 4 |
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; } |