diff options
-rw-r--r-- | mixer-binding/mixer-binding.c | 11 | ||||
-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 |
9 files changed, 295 insertions, 109 deletions
diff --git a/mixer-binding/mixer-binding.c b/mixer-binding/mixer-binding.c index f79ccdb..3af9c9b 100644 --- a/mixer-binding/mixer-binding.c +++ b/mixer-binding/mixer-binding.c @@ -56,7 +56,12 @@ STATIC int CtrlLoadStaticVerbs (afb_dynapi *apiHandle, AFB_ApiVerbs *verbs) { int errcount=0; for (int idx=0; verbs[idx].verb; idx++) { - errcount+= afb_dynapi_add_verb(apiHandle, CtrlApiVerbs[idx].verb, CtrlApiVerbs[idx].info, CtrlApiVerbs[idx].callback, (void*)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); + errcount+= afb_dynapi_add_verb(apiHandle, + CtrlApiVerbs[idx].verb, + CtrlApiVerbs[idx].info, + CtrlApiVerbs[idx].callback, + (void*)&CtrlApiVerbs[idx], + CtrlApiVerbs[idx].auth, 0); } return errcount; @@ -96,7 +101,8 @@ OnErrorExit: PUBLIC int afbBindingEntry(afb_dynapi *apiHandle) { AFB_default = apiHandle; - AFB_ApiNotice (apiHandle, "Controller in afbBindingVdyn"); + + AFB_ApiNotice (apiHandle, "Controller in afbBindingEntry"); const char *dirList= getenv("CONTROL_CONFIG_PATH"); if (!dirList) dirList=CONTROL_CONFIG_PATH; @@ -121,6 +127,7 @@ PUBLIC int afbBindingEntry(afb_dynapi *apiHandle) { AFB_ApiNotice (apiHandle, "Controller API='%s' info='%s'", ctrlConfig->api, ctrlConfig->info); // create one API per config file (Pre-V3 return code ToBeChanged) + int status = afb_dynapi_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, CtrlLoadOneApi, ctrlConfig); // config exec should be done after api init in order to enable onload to use newly defined ctl API. 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; } |