From bb70b4863ce923b80bee0cbc48229db168be067c Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Wed, 13 Feb 2019 11:19:25 +0100 Subject: alsa-api-pcm: added support of quirks Adds an optional array of quirks in the parameters of playback and captures. For now, the only known quirk is a needed workarround for writing sound output on the minnow board. Change-Id: I6c65d110a1f9333ccb77cd8f4eeb9c088d0d2eca Signed-off-by: Thierry Bultel --- plugins/alsa/alsa-api-pcm.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'plugins/alsa/alsa-api-pcm.c') diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c index ce74982..50246e1 100644 --- a/plugins/alsa/alsa-api-pcm.c +++ b/plugins/alsa/alsa-api-pcm.c @@ -536,7 +536,7 @@ fail: PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm_stream_t direction, json_object * argsJ) { - json_object *sourceJ = NULL, *paramsJ = NULL, *sinkJ = NULL, *targetJ = NULL; + json_object *sourceJ = NULL, *paramsJ = NULL, *sinkJ = NULL, *targetJ = NULL, *quirksJ = NULL; char *apiVerb = NULL, *apiInfo = NULL; apiVerbHandleT *handle = NULL; int error; @@ -554,7 +554,7 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm } CDS_INIT_LIST_HEAD(&pcm->sndcard->registryList); - error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?s,s?i,s?i,s?o,s?o,s?o !}" + error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?s,s?i,s?i,s?o,s?o,s?o,s?o !}" , "uid", &pcm->uid , "pcmplug_params", &pcm->sndcard->cid.pcmplug_params , "path", &pcm->sndcard->cid.devpath @@ -564,9 +564,10 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm , "sink", &sinkJ , "source", &sourceJ , "params", ¶msJ + , "quirks", &quirksJ ); if (error) { - AFB_ApiError(mixer->api, "%s: hal=%s missing 'uid|path|cardid|device|sink|source|params' error=%s args=%s", +(??) AFB_ApiError(mixer->api, "%s: hal=%s missing 'uid|path|cardid|device|sink|source|params|quirks' error=%s args=%s", __func__, uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); goto fail_pcm_sndcard; } @@ -579,8 +580,10 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm // try to open sound card control interface pcm->sndcard->ctl = AlsaByPathOpenCtl(mixer, pcm->uid, pcm->sndcard); if (!pcm->sndcard->ctl) { + AFB_ApiError(mixer->api, "%s: hal=%s Fail to open sndcard uid=%s devpath=%s cardid=%s", __func__, uid, pcm->uid, pcm->sndcard->cid.devpath, pcm->sndcard->cid.cardid); + goto fail_pcm_sndcard; } @@ -658,6 +661,29 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm pcm->sndcard->params->channels = pcm->nbChannels; + if (quirksJ) { + int nbQuirks = (int) json_object_array_length(quirksJ); + + for (int idx = 0; idx < nbQuirks; idx++) { + json_object * quirkJ = json_object_array_get_idx(quirksJ, idx); + + if (!json_object_is_type(quirkJ, json_type_string)) { + AFB_API_ERROR(mixer->api, "%s: hal=%s quirk must be of type string, arg=%s", + __func__, uid, json_object_get_string(quirkJ)); + goto fail_pcm_channels; + } + const char * quirk = json_object_get_string(quirkJ); + +#define QUIRK_CHECK(quirkS, quirk) \ + if (!strcmp(quirkS, #quirk)) { \ + pcm->quirks |= quirk; \ + AFB_API_INFO(mixer->api, "%s: PCM=%s has quirk %s",__func__, uid, #quirk);\ + } + + QUIRK_CHECK(quirk, QUIRK_BOGUS_POLL_REVENTS_DEMANGLING); + } + } + if (controlsJ) { json_object *volJ = NULL, *muteJ = NULL; error = wrap_json_unpack(controlsJ, "{s?o,s?o !}" @@ -741,7 +767,7 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm goto fail_pcm_uid; } } - +done: return pcm; fail_pcm_uid: -- cgit 1.2.3-korg From eb45566268d0bbb7df9e30f733a95d79275eb3a7 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Wed, 13 Feb 2019 11:44:02 +0100 Subject: alsa-api-pcm: added an 'optional' parameter This adds a boolean 'optional' parameter for both playback and capture devices. When the device is not detected, the stream(s) that use is are not created, without leading to the exit of the softmixer. Change-Id: I3effbd61bfe1d1d4a7cde573354b9db791f759cc Signed-off-by: Thierry Bultel --- plugins/alsa/alsa-api-pcm.c | 20 +++++++++++++++++--- plugins/alsa/alsa-api-streams.c | 21 +++++++++++++++++++-- plugins/alsa/alsa-softmixer.h | 5 +++++ 3 files changed, 41 insertions(+), 5 deletions(-) (limited to 'plugins/alsa/alsa-api-pcm.c') diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c index 50246e1..0421119 100644 --- a/plugins/alsa/alsa-api-pcm.c +++ b/plugins/alsa/alsa-api-pcm.c @@ -392,6 +392,9 @@ PUBLIC void ApiPcmParamsShow(SoftMixerT * mixer, const char *msg, const AlsaPcmH PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json_object * paramsJ) { const char *format = NULL, *access = NULL; + + AFB_API_NOTICE(mixer->api, "%s for %s: params are %s", __func__, uid, json_object_get_string(paramsJ)); + AlsaPcmHwInfoT *params = calloc(1, sizeof (AlsaPcmHwInfoT)); if (params == NULL) { SOFTMIXER_NOMEM(mixer->api); @@ -502,7 +505,9 @@ PUBLIC void ApiPcmDelete(SoftMixerT * mixer, AlsaSndPcmT * pcm) { pcmChannelsDestroy(mixer, pcm); - snd_ctl_close(card->ctl); + if (card->ctl) + snd_ctl_close(card->ctl); + free(card); free ((char*)pcm->mute.name); free ((char*)pcm->volume.name); @@ -554,7 +559,7 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm } CDS_INIT_LIST_HEAD(&pcm->sndcard->registryList); - error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?s,s?i,s?i,s?o,s?o,s?o,s?o !}" + error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?s,s?i,s?i,s?o,s?o,s?o,s?o,s?b !}" , "uid", &pcm->uid , "pcmplug_params", &pcm->sndcard->cid.pcmplug_params , "path", &pcm->sndcard->cid.devpath @@ -565,9 +570,10 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm , "source", &sourceJ , "params", ¶msJ , "quirks", &quirksJ + , "optional", &pcm->optional ); if (error) { -(??) AFB_ApiError(mixer->api, "%s: hal=%s missing 'uid|path|cardid|device|sink|source|params|quirks' error=%s args=%s", + AFB_ApiError(mixer->api, "%s: hal=%s missing 'uid|path|cardid|device|sink|source|params|quirks|optional' error=%s args=%s", __func__, uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); goto fail_pcm_sndcard; } @@ -577,9 +583,17 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm else pcm->isPcmPlug = false; + pcm->sndcard->optional = pcm->optional; + // try to open sound card control interface pcm->sndcard->ctl = AlsaByPathOpenCtl(mixer, pcm->uid, pcm->sndcard); if (!pcm->sndcard->ctl) { + if (pcm->optional) { + + AFB_API_INFO(mixer->api, "%s: hal=%s Fail to open OPTIONAL sndcard uid=%s devpath=%s cardid=%s", + __func__, uid, pcm->uid, pcm->sndcard->cid.devpath, pcm->sndcard->cid.cardid); + goto done; + } AFB_ApiError(mixer->api, "%s: hal=%s Fail to open sndcard uid=%s devpath=%s cardid=%s", __func__, uid, pcm->uid, pcm->sndcard->cid.devpath, pcm->sndcard->cid.cardid); diff --git a/plugins/alsa/alsa-api-streams.c b/plugins/alsa/alsa-api-streams.c index 7241f41..43c14da 100644 --- a/plugins/alsa/alsa-api-streams.c +++ b/plugins/alsa/alsa-api-streams.c @@ -284,6 +284,14 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT } } + stream->optional = captureCard->optional; + + if (!captureCard->ctl && captureCard->optional) { + stream->noHwDetected = true; + AFB_API_INFO(mixer->api,"%s: no detected capture device", __func__); + goto done; + } + // check PCM is valid and get its full name AlsaPcmCtlT *capturePcm = AlsaByPathOpenPcmCtl(mixer, captureDev, SND_PCM_STREAM_CAPTURE); if (!capturePcm) { @@ -532,7 +540,7 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT AFB_ApiNotice(mixer->api, "%s: mixer=%s stream=%s CREATED", __func__, mixer->uid, stream->uid); - +done: return 0; OnErrorExit: @@ -668,6 +676,9 @@ static void streamDestroy(SoftMixerT * mixer, void * arg) { int error = 0; AFB_ApiDebug(mixer->api, "%s... %s", __func__, stream->uid); + if (stream->noHwDetected) + goto freemem; + error = afb_api_del_verb(mixer->api, stream->uid, (void**)stream->verbApiHandle); if (error) { AFB_ApiDebug(mixer->api, "%s: failed to remove verb %s", __func__, stream->uid); @@ -675,6 +686,7 @@ static void streamDestroy(SoftMixerT * mixer, void * arg) { AlsaPcmCopyStop(mixer, stream->copy); +freemem: if (stream->softvolConfig) { AFB_ApiDebug(mixer->api, "%s... %s delete softvol config", __func__, stream->uid); snd_config_delete(stream->softvolConfig); @@ -744,6 +756,8 @@ PUBLIC int ApiStreamAttach(SoftMixerT *mixer, AFB_ReqT request, const char * uid AFB_ReqFailF(request, "bad-stream", "mixer=%s invalid stream= %s", mixer->uid, json_object_get_string(argsJ)); goto fail; } + if (newStream->noHwDetected) + AlsaMixerTransactionObjectDelete(mixer->transaction, newStream, true); break; @@ -766,7 +780,10 @@ PUBLIC int ApiStreamAttach(SoftMixerT *mixer, AFB_ReqT request, const char * uid "%s: mixer=%s invalid stream= %s", __func__, mixer->uid, json_object_get_string(streamJ)); goto fail; - } + } + if (newStream->noHwDetected) + AlsaMixerTransactionObjectDelete(mixer->transaction, newStream, true); + } break; default: diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h index c73dd0e..d895cef 100644 --- a/plugins/alsa/alsa-softmixer.h +++ b/plugins/alsa/alsa-softmixer.h @@ -211,6 +211,7 @@ typedef struct AlsaSndCtlT_ { long nbRegistry; struct cds_list_head registryList; struct SubscribeHandleT_ * eventSubscribeHandle; + bool optional; } AlsaSndCtlT; @@ -244,6 +245,7 @@ typedef struct { bool isPcmPlug; void * apiVerbHandle; unsigned int quirks; + bool optional; } AlsaSndPcmT; typedef struct { @@ -283,9 +285,12 @@ typedef struct AlsaStreamAudioT_ { AlsaPcmCopyHandleT *copy; struct cds_list_head list; /* link to the global list*/ AlsaPcmCtlT * softvol; + snd_config_t * softvolConfig; snd_config_t * rateConfig; void * verbApiHandle; + bool optional; + bool noHwDetected; } AlsaStreamAudioT; typedef struct SoftMixerT_{ -- cgit 1.2.3-korg From 7520fbf30159a02366c56d0e91e5262a6b88fd37 Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Wed, 13 Feb 2019 14:37:01 +0100 Subject: core-pcm: fixed channels setting issues Recent tries on the minnow board have show that the setting of channels on a PCM must be done -after- the setting of the rate. When not doing that, there can be issues (really, complicated to find) around the boundaries values (open intervals) on the period bytes. Additionally, the number of channels can now be forced in the json file. Change-Id: I2c20853daadf9ccab06be6e04d1a185440f57780 Signed-off-by: Thierry Bultel --- plugins/alsa/alsa-api-pcm.c | 12 ++++++++---- plugins/alsa/alsa-core-pcm.c | 25 ++++++++++++++++--------- 2 files changed, 24 insertions(+), 13 deletions(-) (limited to 'plugins/alsa/alsa-api-pcm.c') diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c index 0421119..464a725 100644 --- a/plugins/alsa/alsa-api-pcm.c +++ b/plugins/alsa/alsa-api-pcm.c @@ -384,8 +384,8 @@ PUBLIC void ApiPcmDelParams(SoftMixerT* mixer, AlsaPcmHwInfoT* params) { } PUBLIC void ApiPcmParamsShow(SoftMixerT * mixer, const char *msg, const AlsaPcmHwInfoT * params) { - AFB_ApiInfo(mixer->api, "%s PARAMS: rate=%d, format=%d, formatString=%s", - msg, params->rate, params->format, params->formatString); + AFB_ApiInfo(mixer->api, "%s PARAMS: rate=%d, format=%d, formatString=%s, channels %d", + msg, params->rate, params->format, params->formatString, params->channels); } @@ -408,10 +408,11 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json if (paramsJ) { int error = - wrap_json_unpack(paramsJ, "{s?i,s?s,s?s !}", + wrap_json_unpack(paramsJ, "{s?i,s?s,s?s,s?i !}", "rate", ¶ms->rate, "format", &format, - "access", &access); + "access", &access, + "channels", ¶ms->channels); if (error) { AFB_ApiError(mixer->api, "%s: sndcard=%s invalid params=%s", __func__, uid, json_object_get_string(paramsJ)); @@ -419,6 +420,9 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json } } + AFB_API_NOTICE(mixer->api, "%s:%s rate set to %d", __func__, uid, params->rate); + AFB_API_NOTICE(mixer->api, "%s:%s channels set to %d", __func__, uid, params->channels); + // default format if (!format) { params->format = SND_PCM_FORMAT_S16_LE; diff --git a/plugins/alsa/alsa-core-pcm.c b/plugins/alsa/alsa-core-pcm.c index 9d46dcc..0e8f86f 100644 --- a/plugins/alsa/alsa-core-pcm.c +++ b/plugins/alsa/alsa-core-pcm.c @@ -136,7 +136,22 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) { } } - if (opts->rate > 0 ) { + unsigned int * channels = &opts->channels; + + if (*channels) { + AFB_API_DEBUG(mixer->api, "%s: Attempt to set %d channels", __func__, *channels); + if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, *channels)) < 0) { + AFB_API_ERROR(mixer->api, + "%s (%s): mixer=%s Set_Channels=%d Fail error=%s", + __func__, card, mixer->uid, *channels, snd_strerror(error)); + + AlsaDumpPcmParams(mixer, pxmHwParams); + goto OnErrorExit; + }; + AFB_API_DEBUG(mixer->api, "%s: CHANNELS SET TO %d", __func__, *channels); + } + + if (opts->rate > 0 ) { AFB_ApiDebug(mixer->api,"%s (%s): set rate to %d", __func__, card, opts->rate); unsigned int pcmRate = opts->rate; @@ -158,14 +173,6 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) { } } - if (opts->channels) { - if ((error = snd_pcm_hw_params_set_channels(pcm->handle, pxmHwParams, opts->channels)) < 0) { - AFB_ApiError(mixer->api, - "%s (%s): mixer=%s Set_Channels=%d Fail error=%s", - __func__, card, mixer->uid, opts->channels, snd_strerror(error)); - goto OnErrorExit; - }; - } /* The following code, that * 1) sets period time/size; buffer time/size hardware params -- cgit 1.2.3-korg