diff options
author | Stephane Desneux <stephane.desneux@iot.bzh> | 2018-12-22 11:51:54 +0100 |
---|---|---|
committer | Stephane Desneux <stephane.desneux@iot.bzh> | 2018-12-22 11:51:54 +0100 |
commit | c85fd2f131c73e8c21e05e1ea80b55d6a787dda6 (patch) | |
tree | 248aca4a75556e3546a3c89cac43bcffe3ccf634 /plugins/alsa | |
parent | e0f57e523112e1bc73a04e8615d7a21355f0ce0e (diff) |
Implemented the bug cleanup at application exit
Fixes most memory leaks in softmixer.
The concept of 'transaction' for dynamic streams has
been generalized to the objects created at startup.
The cleanup is done via a handle set through a atexit()
call.
Also added a missing strdup in alsa-api-loop, that fixes
a double free.
Warning, the bluez-alsa PCM are not closed in this
version. This is intentional due to a BUG in the
bluealsa ioplug PCM, that crashes upon close
(pthread_cancel is used to terminate the io_thread
and things get very bad. I have a pending fix for
that, relying on a cancellation pipe, but deeper
testing must be done).
As an effect, only one phone call can be made,
else 4a needs to be restarted
Change-Id: Idb84cafe15f17c0ef02fcc70296d541dc55a2dcf
Signed-off-by: Thierry Bultel <thierry.bultel@iot.bzh>
Signed-off-by: Stephane Desneux <stephane.desneux@iot.bzh>
Diffstat (limited to 'plugins/alsa')
-rw-r--r-- | plugins/alsa/alsa-api-loop.c | 62 | ||||
-rw-r--r-- | plugins/alsa/alsa-api-mixer.c | 50 | ||||
-rw-r--r-- | plugins/alsa/alsa-api-pcm.c | 45 | ||||
-rw-r--r-- | plugins/alsa/alsa-api-streams.c | 24 | ||||
-rw-r--r-- | plugins/alsa/alsa-core-ctl.c | 99 | ||||
-rw-r--r-- | plugins/alsa/alsa-core-pcm.c | 24 | ||||
-rw-r--r-- | plugins/alsa/alsa-effect-ramp.c | 17 | ||||
-rw-r--r-- | plugins/alsa/alsa-plug-dmix.c | 2 | ||||
-rw-r--r-- | plugins/alsa/alsa-plug-rate.c | 2 | ||||
-rw-r--r-- | plugins/alsa/alsa-plug-route.c | 12 | ||||
-rw-r--r-- | plugins/alsa/alsa-softmixer.c | 5 | ||||
-rw-r--r-- | plugins/alsa/alsa-softmixer.h | 17 | ||||
-rw-r--r-- | plugins/alsa/alsa-transaction.c | 62 | ||||
-rw-r--r-- | plugins/alsa/alsa-transaction.h | 7 | ||||
-rw-r--r-- | plugins/alsa/alsa-utils-bypath.c | 16 |
15 files changed, 312 insertions, 132 deletions
diff --git a/plugins/alsa/alsa-api-loop.c b/plugins/alsa/alsa-api-loop.c index 16491a0..ffab6bc 100644 --- a/plugins/alsa/alsa-api-loop.c +++ b/plugins/alsa/alsa-api-loop.c @@ -40,20 +40,25 @@ PUBLIC AlsaLoopSubdevT *ApiLoopFindSubdev(SoftMixerT *mixer, const char *streamU AlsaLoopSubdevT * subdev; cds_list_for_each_entry(subdev, &_loop->subdevs.list, list) { if (!subdev->uid) { - subdev->uid = streamUid; + subdev->uid = strdup(streamUid); + if (!subdev->uid) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } *loop = _loop; return subdev; } } } } +fail: return NULL; } STATIC AlsaLoopSubdevT *ProcessOneSubdev(SoftMixerT *mixer, AlsaSndLoopT *loop, json_object *subdevJ) { - AFB_ApiDebug(mixer->api, "%s", __func__); + AFB_ApiDebug(mixer->api, "%s : %s", __func__, json_object_get_string(subdevJ)); AlsaLoopSubdevT *subdev = calloc(1, sizeof (AlsaLoopSubdevT)); if (subdev == NULL) { @@ -69,7 +74,7 @@ STATIC AlsaLoopSubdevT *ProcessOneSubdev(SoftMixerT *mixer, AlsaSndLoopT *loop, if (error) { AFB_ApiError(mixer->api, "%s: loop=%s missing (uid|subdev|numid) error=%s json=%s", - __func__, loop->uid, wrap_json_get_error_string(error),json_object_get_string(subdevJ)); + __func__, loop->uid, wrap_json_get_error_string(error), json_object_get_string(subdevJ)); goto fail_subdev; } @@ -100,6 +105,7 @@ STATIC AlsaLoopSubdevT *ProcessOneSubdev(SoftMixerT *mixer, AlsaSndLoopT *loop, pcmCtl->closeAtDeletion = true; // free PCM as we only open loop to assert it's a valid capture device + AlsaMixerTransactionObjectForget(mixer->transaction, pcmCtl); AlsaPcmCtlDelete(mixer, pcmCtl); AFB_ApiDebug(mixer->api, "%s DONE", __func__); @@ -114,9 +120,8 @@ fail: return NULL; } -static void freeSubdev(AlsaLoopSubdevT * subdev) { - if (subdev->uid) - free((char*)subdev->uid); +static void freeSubdev(SoftMixerT* mixer, AlsaLoopSubdevT * subdev) { + free(subdev->uid); free(subdev); } @@ -219,7 +224,7 @@ fail_loop_subdev: { AlsaLoopSubdevT * subdev, *tmp; cds_list_for_each_entry_safe(subdev, tmp, &loop->subdevs.list, list) { cds_list_del(&subdev->list); - freeSubdev(subdev); + freeSubdev(mixer, subdev); } } @@ -235,37 +240,38 @@ fail: static void loopDestroy(SoftMixerT * mixer, void* arg) { AlsaSndLoopT * loop = (AlsaSndLoopT*) arg; - AFB_ApiDebug(mixer->api, "%s... %s not implemented", __func__, loop->uid); - return; - - if (loop->sndcard) { - if (loop->sndcard->ctl) { - snd_ctl_close(loop->sndcard->ctl); - free(loop->sndcard->ctl); - } - free(loop->sndcard); - } + AFB_ApiDebug(mixer->api, "%s... %s", __func__, loop->uid); AlsaLoopSubdevT * subdev, *tmp; cds_list_for_each_entry_safe(subdev, tmp, &loop->subdevs.list, list) { cds_list_del(&subdev->list); - freeSubdev(subdev); + freeSubdev(mixer, subdev); } + + if (loop->sndcard->ctl) + snd_ctl_close(loop->sndcard->ctl); + mixer->nbLoops--; + cds_list_del(&loop->list); free(loop); + AFB_ApiDebug(mixer->api, "DONE !"); } static AlsaSndLoopT * loopCreate(SoftMixerT *mixer, const char *uid, json_object *argsJ) { + AlsaSndLoopT * newLoop = AttachOneLoop(mixer, uid, argsJ); if (!newLoop) { goto fail; } mixer->nbLoops++; - cds_list_add_tail(&newLoop->list, &mixer->loops.list); + cds_list_add(&newLoop->list, &mixer->loops.list); AlsaMixerTransactionObjectAdd(mixer->transaction, newLoop, loopDestroy); + loopsDisplay(mixer); + + fail: return newLoop; } @@ -315,3 +321,21 @@ fail_loop: fail: return -1; } + + +static void subdevDisplay(SoftMixerT *mixer, AlsaLoopSubdevT * subdev) { + AFB_ApiInfo(mixer->api, "\t\tsubdev id %d, uid %s", subdev->numid, subdev->uid); +} + +PUBLIC void loopsDisplay(SoftMixerT *mixer) { + AlsaSndLoopT * loop; + AFB_ApiInfo(mixer->api, "Mixer %s LOOPS:", mixer->uid); + cds_list_for_each_entry(loop, &mixer->loops.list, list) { + AFB_ApiInfo(mixer->api, "\tLOOP %s", loop->uid); + AlsaLoopSubdevT * subdev; + cds_list_for_each_entry(subdev, &loop->subdevs.list, list) { + subdevDisplay(mixer, subdev); + } + } + AFB_ApiInfo(mixer->api, "--------------"); +} diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c index ae08461..6d80b55 100644 --- a/plugins/alsa/alsa-api-mixer.c +++ b/plugins/alsa/alsa-api-mixer.c @@ -23,6 +23,38 @@ #include <string.h> #include <pthread.h> +static struct cds_list_head mixerList; + +static void MixerDelete(SoftMixerT * mixer); + +static void MixerExit() { + SoftMixerT *mixer, *tmp; + printf("%s !\n", __func__); + + cds_list_for_each_entry_safe(mixer, tmp, &mixerList, list) { + // remove this mixer from the global mixer list + cds_list_del(&mixer->list); + AFB_ApiInfo(mixer->api, "Terminating mixer %s", mixer->uid); + + AlsaMixerTransaction * transaction, * tmp_trans; + cds_list_for_each_entry_safe(transaction, tmp_trans, &mixer->transactionList, transaction_node) { + cds_list_del(&transaction->transaction_node); + AlsaMixerTransactionDoCleanup(transaction); + AlsaMixerTransactionDelete(transaction); + } + MixerDelete(mixer); + } + printf("%s DONE ! Bye !\n", __func__); +} + +CTLP_ONLOAD(plugin, callbacks){ + + AFB_ApiInfo(plugin->api, "MIXER INIT"); + CDS_INIT_LIST_HEAD(&mixerList); + + atexit(MixerExit); + return 0; +} static void MixerRemoveVerb(AFB_ReqT request) { @@ -249,7 +281,7 @@ STATIC json_object *MixerInfoOneZone(AlsaSndZoneT *zone, int verbose) { json_object *paramsJ; wrap_json_pack(¶msJ, "{si,ss,si}" , "rate", zone->params->rate - , "format", zone->params->formatS + , "format", zone->params->formatString , "channels", zone->params->channels ); json_object_object_add(responseJ, "params", paramsJ); @@ -514,6 +546,8 @@ STATIC void MixerAttachVerb(AFB_ReqT request) { int error; AlsaMixerTransaction * transaction = NULL; + AFB_ApiInfo(mixer->api, "%s: %s", __func__, json_object_get_string(argsJ)); + error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?o,s?o,s?o,s?o,s?o,s?o !}" , "uid", &uid , "prefix", &prefix @@ -688,6 +722,8 @@ CTLP_CAPI(MixerAttach, source, argsJ, responseJ) { goto OnErrorExit; } + mixer->transaction = transaction; + if (playbackJ) { error = ApiSinkAttach(mixer, NULL, uid, playbackJ); if (error) goto OnErrorExit; @@ -718,6 +754,8 @@ CTLP_CAPI(MixerAttach, source, argsJ, responseJ) { if (error) goto OnErrorExit; } + mixer->transaction = NULL; + // return mixer info data after attach return 0; @@ -725,7 +763,14 @@ OnErrorExit: return -1; } +static void MixerDelete(SoftMixerT * mixer) { + free((char*)mixer->info); + free((char*)mixer->uid); + free(mixer); +} + CTLP_CAPI(MixerCreate, source, argsJ, responseJ) { + SoftMixerT *mixer = calloc(1, sizeof (SoftMixerT)); if (mixer == NULL) { SOFTMIXER_NOMEM(source->api); @@ -790,6 +835,7 @@ CTLP_CAPI(MixerCreate, source, argsJ, responseJ) { CDS_INIT_LIST_HEAD(&mixer->zones.list); CDS_INIT_LIST_HEAD(&mixer->streams.list); CDS_INIT_LIST_HEAD(&mixer->ramps.list); + CDS_INIT_LIST_HEAD(&mixer->transactionList); mixer->sdLoop = AFB_GetEventLoop(source->api); mixer->api = source->api; @@ -799,6 +845,8 @@ CTLP_CAPI(MixerCreate, source, argsJ, responseJ) { if (error) goto fail_info; + cds_list_add_tail(&mixer->list, &mixerList); + return 0; fail_info: diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c index 85e3c3a..036f158 100644 --- a/plugins/alsa/alsa-api-pcm.c +++ b/plugins/alsa/alsa-api-pcm.c @@ -372,11 +372,23 @@ OnErrorExit: return; } +PUBLIC AlsaPcmHwInfoT* ApiPcmParamsDup(SoftMixerT* mixer, AlsaPcmHwInfoT* params) { + AlsaPcmHwInfoT* _params = (AlsaPcmHwInfoT*) malloc(sizeof(AlsaPcmHwInfoT)); + if (params) + memcpy(_params, params, sizeof(AlsaPcmHwInfoT)); + return _params; +} + PUBLIC void ApiPcmDelParams(SoftMixerT* mixer, AlsaPcmHwInfoT* params) { - free((char*)params->formatS); free(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); + +} + PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json_object * paramsJ) { const char *format = NULL, *access = NULL; @@ -404,20 +416,14 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json } } + // default format if (!format) { params->format = SND_PCM_FORMAT_S16_LE; - params->formatS = strdup("S16_LE"); - if (params->formatS == NULL) { - SOFTMIXER_NOMEM(mixer->api); - goto fail_params; - } + strcpy(params->formatString, SND_FORMAT_DEFAULT); goto check_access; } - params->formatS = strdup(format); - if (params->formatS == NULL) { - SOFTMIXER_NOMEM(mixer->api); - goto fail_params; - } + strncpy(params->formatString, format, SND_FORMAT_STRING_LEN); + #define FORMAT_CHECK(arg) if (!strcmp(format,#arg)) { params->format = SND_PCM_FORMAT_##arg; goto check_access; } FORMAT_CHECK(S16_LE); @@ -441,7 +447,7 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json goto fail_params; check_access: - AFB_ApiNotice(mixer->api, "%s: %s format set to SND_PCM_FORMAT_%s", __func__, uid, params->formatS); + AFB_ApiNotice(mixer->api, "%s: %s format set to SND_PCM_FORMAT_%s", __func__, uid, params->formatString); #define ACCESS_CHECK(arg) if (!strcmp(access,#arg)) { params->access = SND_PCM_ACCESS_##arg; goto success;} @@ -466,33 +472,33 @@ success: return params; fail_params: - free(params); + ApiPcmDelParams(mixer, params); fail: return NULL; } static void pcmChannelsDestroy(SoftMixerT * mixer, AlsaSndPcmT * pcm) { - AFB_ApiDebug(mixer->api, "%s: pcm %s (%d channels)", __func__, pcm->uid, pcm->nbChannels); + AFB_ApiDebug(mixer->api, "\t%s: pcm %s (%d channels)", __func__, pcm->uid, pcm->nbChannels); AlsaPcmChannelT * channel, *tmp; cds_list_for_each_entry_safe(channel, tmp, &pcm->channels.list, list) { cds_list_del(&channel->list); - AFB_ApiDebug(mixer->api, "%s: del channel %s", __func__, channel->uid); free((char *)channel->uid); free(channel); } - AFB_ApiDebug(mixer->api, "%s: pcm %s DONE", __func__, pcm->uid); + AFB_ApiDebug(mixer->api, "\t%s: pcm %s DONE", __func__, pcm->uid); } PUBLIC void ApiPcmDelete(SoftMixerT * mixer, AlsaSndPcmT * pcm) { - AFB_ApiDebug(mixer->api, "%s: pcm %s", __func__, pcm->uid); + AFB_ApiDebug(mixer->api, "%s: pcm %s\n", __func__, pcm->uid); free(pcm->apiVerbHandle); AlsaSndCtlT * card = pcm->sndcard; - if (card->cid.pcmplug_params) + if (card->cid.pcmplug_params) { free((char*)card->cid.pcmplug_params); + } pcmChannelsDestroy(mixer, pcm); @@ -503,10 +509,11 @@ PUBLIC void ApiPcmDelete(SoftMixerT * mixer, AlsaSndPcmT * pcm) { if (pcm->verb && (strcmp(pcm->verb, SOFTMIXER_VERB_NONE)!=0)) { - int error = afb_api_del_verb(mixer->api, pcm->verb, (void**)&pcm->apiVerbHandle); + int error = afb_api_del_verb(mixer->api, pcm->verb, (void**)NULL); if (error) { AFB_ApiError(mixer->api, "Failed to remove verb %s", pcm->verb); } + free((char*)pcm->verb); } free((char*)pcm->uid); diff --git a/plugins/alsa/alsa-api-streams.c b/plugins/alsa/alsa-api-streams.c index e35a8b7..80609bc 100644 --- a/plugins/alsa/alsa-api-streams.c +++ b/plugins/alsa/alsa-api-streams.c @@ -196,7 +196,7 @@ static void paramsOverride(SoftMixerT *mixer, AlsaStreamAudioT * destStream, con if (dest->format != src->format) { AFB_ApiNotice(mixer->api, "Stream %s overrides format to %d", destStream->uid, src->format); dest->format = src->format; - dest->formatS = strdup(src->formatS); + strncpy(dest->formatString, src->formatString, SND_FORMAT_STRING_LEN ); } if (dest->access != src->access) { @@ -334,11 +334,14 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT // create a fake zone for rate converter selection zone=alloca(sizeof(AlsaSndZoneT)); - zone->uid= playback->uid; - zone->params = playback->sndcard->params; + zone->uid = playback->uid; + + ApiPcmParamsShow(mixer,"PLAYBACK to FAKE ZONE", playback->sndcard->params); + + zone->params = ApiPcmParamsDup(mixer, playback->sndcard->params); zone->ccount = playback->nbChannels; - } + } // create mute control and Registry it as pause/resume ctl) if (asprintf(&runName, "pause-%s", stream->uid) == -1) { @@ -379,6 +382,9 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT AFB_ApiDebug(mixer->api,"%s: create softvol control", __func__); + ApiPcmParamsShow(mixer, "Stream ", stream->params); + ApiPcmParamsShow(mixer, "Zone", zone->params); + // create volume control before softvol pcm is opened volNumid = AlsaCtlCreateControl(mixer, captureCard, @@ -396,14 +402,14 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT if ((zone->params->rate != stream->params->rate) || (zone->params->format != stream->params->format)) { AFB_ApiNotice(mixer->api, - "%s: Instanciate a RATE CONVERTER (stream [%d,%s(%d),%d channels], zone [%d,%s(%d), %d channels])", + "%s: Instanciate a RATE CONVERTER (stream [rate %d,%s(%d),%d channels], zone [rate %d,%s(%d), %d channels])", __func__, stream->params->rate, - stream->params->formatS, + stream->params->formatString, stream->params->format, stream->params->channels, zone->params->rate, - zone->params->formatS, + zone->params->formatString, zone->params->format, zone->params->channels); @@ -423,9 +429,9 @@ STATIC int CreateOneStream(SoftMixerT *mixer, const char * uid, AlsaStreamAudioT playbackName = (char*) streamPcm->cid.cardid; } - streamPcm->isPcmPlug = zone->isPcmPlug; + streamPcm->isPcmPlug = zone->isPcmPlug; - AFB_ApiDebug(mixer->api, "%s: Opening PCM PLAYBACK name %s", __func__, playbackName); + AFB_ApiDebug(mixer->api, "%s: Opening PCM PLAYBACK name %s", __func__, playbackName); // everything is now ready to open playback pcm in BLOCKING mode this time error = snd_pcm_open(&streamPcm->handle, playbackName, SND_PCM_STREAM_PLAYBACK, 0 /* will block*/ ); diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c index dcfd860..020c13c 100644 --- a/plugins/alsa/alsa-core-ctl.c +++ b/plugins/alsa/alsa-core-ctl.c @@ -42,7 +42,7 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT * int error; int index; snd_ctl_elem_list_t *ctlList = NULL; - snd_ctl_elem_id_t *elemId; + snd_ctl_elem_id_t *elemId = NULL; snd_ctl_elem_list_alloca(&ctlList); @@ -50,14 +50,14 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT * AFB_ApiError(mixer->api, "%s [%s] fail retrieve controls", __func__, ALSA_CTL_UID(sndcard->ctl, string)); - goto OnErrorExit; + goto fail; } if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) { AFB_ApiError(mixer->api, "%s [%s] fail retrieve count", __func__, ALSA_CTL_UID(sndcard->ctl, string)); - goto OnErrorExit; + goto fail; } // Fulup: do not understand why snd_ctl_elem_list should be call twice to get a valid ctlCount @@ -65,7 +65,7 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT * AFB_ApiError(mixer->api, "%s [%s] fail retrieve controls", __func__, ALSA_CTL_UID(sndcard->ctl, string)); - goto OnErrorExit; + goto fail_space; } // loop on control to find the right one @@ -83,23 +83,25 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNumidElemId(SoftMixerT *mixer, AlsaSndCtlT * AFB_ApiNotice(mixer->api, "%s [%s] fail get numid=%i count", __func__, ALSA_CTL_UID(sndcard->ctl, string), numid); - goto OnErrorExit; + goto fail_space; } - // clear ctl list and return elemid - snd_ctl_elem_list_clear(ctlList); - return elemId; + snd_ctl_elem_list_free_space(ctlList); + return elemId; -OnErrorExit: - if (ctlList) snd_ctl_elem_list_clear(ctlList); +fail_space: + snd_ctl_elem_list_free_space(ctlList); +fail: return NULL; + + } PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const char *ctlName) { int error; int index; snd_ctl_elem_list_t *ctlList = NULL; - snd_ctl_elem_id_t *elemId; + snd_ctl_elem_id_t *elemId = NULL; snd_ctl_elem_list_alloca(&ctlList); @@ -107,14 +109,14 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *s AFB_ApiError(mixer->api, "%s cardid='%s' cardname='%s' fail retrieve controls", __func__, sndcard->cid.cardid, sndcard->cid.name); - goto OnErrorExit; + goto fail; } if ((error = snd_ctl_elem_list_alloc_space(ctlList, snd_ctl_elem_list_get_count(ctlList))) < 0) { AFB_ApiError(mixer->api, "%s cardid='%s' cardname='%s' fail retrieve count", __func__, sndcard->cid.cardid, sndcard->cid.name); - goto OnErrorExit; + goto fail; } // Fulup: do not understand why snd_ctl_elem_list should be call twice to get a valid ctlCount @@ -122,7 +124,7 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *s AFB_ApiError(mixer->api, "%s cardid='%s' cardname='%s' fail retrieve controls", __func__, sndcard->cid.cardid, sndcard->cid.name); - goto OnErrorExit; + goto fail_space; } // loop on control to find the right one @@ -138,16 +140,17 @@ PUBLIC snd_ctl_elem_id_t *AlsaCtlGetNameElemId(SoftMixerT *mixer, AlsaSndCtlT *s if (index == ctlCount) { AFB_ApiNotice(mixer->api, "AlsaCtlGetNameElemId cardid='%s' cardname='%s' ctl not found name=%s", sndcard->cid.cardid, sndcard->cid.name, ctlName); - goto OnErrorExit; + goto fail_space; } - // clear ctl list and return elemid - snd_ctl_elem_list_clear(ctlList); - return elemId; + snd_ctl_elem_list_free_space(ctlList); + return elemId; + +fail_space: + snd_ctl_elem_list_free_space(ctlList); +fail: + return NULL; -OnErrorExit: - if (ctlList) snd_ctl_elem_list_clear(ctlList); - return NULL; } @@ -317,7 +320,7 @@ PUBLIC int AlsaCtlNumidSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi AFB_ApiError(mixer->api, "%s cardid=%s cardname=%s fail to find numid=%d", __func__, sndcard->cid.cardid, sndcard->cid.longname, numid); - goto OnErrorExit; + goto fail; } int error = CtlElemIdSetLong(mixer, sndcard, elemId, value); @@ -325,11 +328,15 @@ PUBLIC int AlsaCtlNumidSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi 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; + goto fail_elemId; } + free(elemId); return 0; -OnErrorExit: + +fail_elemId: + free(elemId); +fail: return -1; } @@ -340,7 +347,7 @@ PUBLIC int AlsaCtlNumidGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi AFB_ApiError(mixer->api, "%s cardid=%s cardname=%s fail to find numid=%d", __func__, sndcard->cid.cardid, sndcard->cid.longname, numid); - goto OnErrorExit; + goto fail; } int error = CtlElemIdGetLong(mixer, sndcard, elemId, value); @@ -348,12 +355,16 @@ PUBLIC int AlsaCtlNumidGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, int numi 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; + goto fail_elemId; } + free(elemId); return 0; -OnErrorExit: - return -1; + +fail_elemId: + free(elemId); +fail: + return -1; } PUBLIC int AlsaCtlNameSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const char *ctlName, long value) { @@ -363,7 +374,7 @@ PUBLIC int AlsaCtlNameSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha AFB_ApiError(mixer->api, "%s cardid=%s cardname=%s fail to find crlName=%s", __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName); - goto OnErrorExit; + goto fail; } int error = CtlElemIdSetLong(mixer, sndcard, elemId, value); @@ -371,11 +382,15 @@ PUBLIC int AlsaCtlNameSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha 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; + goto fail_elemId; } + free(elemId); return 0; -OnErrorExit: + +fail_elemId: + free(elemId); +fail: return -1; } @@ -386,7 +401,7 @@ PUBLIC int AlsaCtlNameGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha AFB_ApiError(mixer->api, "%s cardid=%s cardname=%s fail to find crlName=%s", __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName); - goto OnErrorExit; + goto fail; } int error = CtlElemIdGetLong(mixer, sndcard, elemId, value); @@ -394,11 +409,15 @@ PUBLIC int AlsaCtlNameGetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, const cha 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; + goto fail_elemId; } + free(elemId); return 0; -OnErrorExit: + +fail_elemId: + free(elemId); +fail: return -1; } @@ -462,7 +481,7 @@ PUBLIC int AlsaCtlCreateControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, char* c AFB_ApiError(mixer->api, "%s cardid=%s cardname=%s fail to create ctlName=%s", __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName); - goto OnErrorExit; + goto fail; } elemId = AlsaCtlGetNumidElemId(mixer, sndcard, numid); @@ -473,15 +492,17 @@ PUBLIC int AlsaCtlCreateControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, char* c 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; + goto fail; } 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); + + __func__, sndcard->cid.cardid, sndcard->cid.longname, ctlName, numid, value); +fail: + free(elemId); return numid; -OnErrorExit: - return -1; + } STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, void* userData) { diff --git a/plugins/alsa/alsa-core-pcm.c b/plugins/alsa/alsa-core-pcm.c index adceebc..a45d463 100644 --- a/plugins/alsa/alsa-core-pcm.c +++ b/plugins/alsa/alsa-core-pcm.c @@ -29,6 +29,9 @@ for the specific language governing permissions and #include <sys/syscall.h> #include <sched.h> +#include <signal.h> +#include <poll.h> + #include "time_utils.h" static int xrun(snd_pcm_t * pcm, int error); @@ -127,7 +130,7 @@ PUBLIC int AlsaPcmConf(SoftMixerT *mixer, AlsaPcmCtlT *pcm, int mode) { if ((error = snd_pcm_hw_params_set_format(pcm->handle, pxmHwParams, opts->format)) < 0) { AFB_ApiError(mixer->api, "%s (%s) mixer=%s Set_Format=%s (%d) FAILED current=%d error=%s", - __func__, card, mixer->uid, opts->formatS, opts->format, format, snd_strerror(error)); + __func__, card, mixer->uid, opts->formatString, opts->format, format, snd_strerror(error)); AlsaDumpFormats(mixer, pcm->handle); goto OnErrorExit; } @@ -483,6 +486,7 @@ static void *readThreadEntry(void *handle) { if (muted) readSuspend(pcmCopyHandle); + /* loop until end */ for (;;) { @@ -531,7 +535,7 @@ static void *readThreadEntry(void *handle) { continue; } - unsigned short revents; + unsigned short revents = 0; int res = snd_pcm_poll_descriptors_revents(pcmCopyHandle->pcmIn->handle, framePfds, pcmCopyHandle->nbPcmFds, &revents); @@ -549,6 +553,7 @@ static void *readThreadEntry(void *handle) { } done: pthread_exit(0); + return NULL; } @@ -689,9 +694,14 @@ PUBLIC int AlsaPcmCopyStop(SoftMixerT *mixer, AlsaPcmCopyHandleT * handle) { if (pthread_join(handle->rthread, NULL) != 0) AFB_ApiDebug(mixer->api, "%s: Failed to join read thread", __func__); + AFB_ApiDebug(mixer->api, "%s: Copy threads of %s are STOPPED", __func__, handle->stream->uid); + sem_destroy(&handle->sem); - AFB_ApiDebug(mixer->api, "%s: Copy threads of %s are STOPPED", __func__, handle->stream->uid); + alsa_ringbuf_free(handle->rbuf); + + free(handle->pollFds); + free(handle); return 0; @@ -709,9 +719,17 @@ PUBLIC int AlsaPcmCopyStart(SoftMixerT *mixer, AlsaStreamAudioT *stream, AlsaPcm /* remember configuration of capture */ pcmIn->params = (AlsaPcmHwInfoT*)malloc(sizeof(AlsaPcmHwInfoT)); + if (!pcmIn->params) { + SOFTMIXER_NOMEM(mixer->api); + goto OnErrorExit; + } memcpy(pcmIn->params, opts, sizeof(AlsaPcmHwInfoT)); pcmOut->params = (AlsaPcmHwInfoT*)malloc(sizeof(AlsaPcmHwInfoT)); + if (!pcmOut->params) { + SOFTMIXER_NOMEM(mixer->api); + goto OnErrorExit; + } memcpy(pcmOut->params, opts, sizeof(AlsaPcmHwInfoT)); pcmIn->mixer = mixer; diff --git a/plugins/alsa/alsa-effect-ramp.c b/plugins/alsa/alsa-effect-ramp.c index e51879d..a3bf54b 100644 --- a/plugins/alsa/alsa-effect-ramp.c +++ b/plugins/alsa/alsa-effect-ramp.c @@ -125,12 +125,12 @@ PUBLIC int AlsaVolRampApply(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaStreamA if (newvol < 0) newvol = curvol - newvol; else newvol = curvol + newvol; } - + if (count != 1) { AFB_ApiError(mixer->api, "%s: mixer=%s stream=%s invalid-numeric expect {uid:%s, vol:[+,-,=]value} get vol:%s", __func__, mixer->uid, stream->uid, uid, json_object_get_string(volJ)); - goto OnErrorExit; + goto OnErrorExit; } break; case json_type_int: @@ -152,21 +152,22 @@ PUBLIC int AlsaVolRampApply(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaStreamA __func__, mixer->uid, stream->uid, uid, stream->volume); goto OnErrorExit; } - + // search for ramp uid in mixer AlsaVolRampT * ramp; bool found = false; cds_list_for_each_entry(ramp, &mixer->ramps.list, list) { if (ramp->uid && !strcasecmp(ramp->uid, uid)) { - break; - } - } - + found=true; + break; + } + } + if (!found) { AFB_ApiError(mixer->api, "%s: mixer=%s stream=%s ramp=%s does not exit", __func__, mixer->uid, stream->uid, uid); - goto OnErrorExit; + goto OnErrorExit; } VolRampHandleT *rHandle = calloc(1, sizeof (VolRampHandleT)); diff --git a/plugins/alsa/alsa-plug-dmix.c b/plugins/alsa/alsa-plug-dmix.c index d63b79f..9aaf866 100644 --- a/plugins/alsa/alsa-plug-dmix.c +++ b/plugins/alsa/alsa-plug-dmix.c @@ -86,7 +86,7 @@ PUBLIC AlsaPcmCtlT* AlsaCreateDmix(SoftMixerT *mixer, const char* pcmName, AlsaS } if (sndSlave->params->format) { - error += snd_config_imake_string(&elemConfig, "format", sndSlave->params->formatS); + error += snd_config_imake_string(&elemConfig, "format", sndSlave->params->formatString); if (error) goto OnErrorExit; error += snd_config_add(slaveConfig, elemConfig); if (error) goto OnErrorExit; diff --git a/plugins/alsa/alsa-plug-rate.c b/plugins/alsa/alsa-plug-rate.c index b2c43d2..d4a3068 100644 --- a/plugins/alsa/alsa-plug-rate.c +++ b/plugins/alsa/alsa-plug-rate.c @@ -55,7 +55,7 @@ PUBLIC AlsaPcmCtlT* AlsaCreateRate(SoftMixerT *mixer, AlsaStreamAudioT * stream, error += snd_config_add(slaveConfig, elemConfig); } if (params->format) { - error += snd_config_imake_string(&elemConfig, "format", params->formatS); + error += snd_config_imake_string(&elemConfig, "format", params->formatString); error += snd_config_add(slaveConfig, elemConfig); } if (error) goto OnErrorExit; diff --git a/plugins/alsa/alsa-plug-route.c b/plugins/alsa/alsa-plug-route.c index c00c0cf..ebc7074 100644 --- a/plugins/alsa/alsa-plug-route.c +++ b/plugins/alsa/alsa-plug-route.c @@ -113,7 +113,17 @@ PUBLIC AlsaPcmCtlT* AlsaCreateRoute(SoftMixerT *mixer, AlsaSndZoneT *zone, int o goto fail_nodump; } - zone->params = pcmRoute->params; + pcmRoute->params = ApiPcmParamsDup(mixer, pcmRoute->params); + if (!pcmRoute->params) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_nodump; + } + + zone->params = ApiPcmParamsDup(mixer, pcmRoute->params); + if (!zone->params) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_nodump; + } // use 1st zone channel to retrieve sound card name + channel count. diff --git a/plugins/alsa/alsa-softmixer.c b/plugins/alsa/alsa-softmixer.c index c8b50a0..f0d280e 100644 --- a/plugins/alsa/alsa-softmixer.c +++ b/plugins/alsa/alsa-softmixer.c @@ -24,9 +24,4 @@ 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); - return 0; -} diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h index a8cc6de..346964a 100644 --- a/plugins/alsa/alsa-softmixer.h +++ b/plugins/alsa/alsa-softmixer.h @@ -101,10 +101,13 @@ typedef struct { int subdev; } AlsaDevInfoT; +#define SND_FORMAT_STRING_LEN 16 +#define SND_FORMAT_DEFAULT "S16_LE" + typedef struct { unsigned int rate; unsigned int channels; - const char *formatS; + char formatString[SND_FORMAT_STRING_LEN]; snd_pcm_format_t format; snd_pcm_access_t access; size_t sampleSize; @@ -238,7 +241,7 @@ typedef struct { } AlsaSndPcmT; typedef struct { - const char*uid; + char * uid; int index; int numid; struct cds_list_head list; @@ -305,7 +308,11 @@ typedef struct SoftMixerT_{ unsigned int nbRamps; AlsaVolRampT ramps; - AlsaMixerTransaction * transaction; + AlsaMixerTransaction * transaction; // current transaction + + struct cds_list_head list; // node to list of all mixers + + struct cds_list_head transactionList; // all transactions of this mixer } SoftMixerT; // alsa-utils-bypath.c @@ -368,12 +375,16 @@ PUBLIC int ApiStreamAttach(SoftMixerT *mixer, AFB_ReqT request, const char * uid PUBLIC int ApiZoneAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object * argsJ); PUBLIC int ApiRampAttach(SoftMixerT *mixer, AFB_ReqT request, const char *, json_object *argsJ); +PUBLIC void loopsDisplay(SoftMixerT * mixer); + // helper used for attach verb,and also by the streams API for fake zones PUBLIC AlsaSndZoneT * zoneCreate(SoftMixerT* mixer, const char * uid, json_object * argsJ); PUBLIC AlsaLoopSubdevT *ApiLoopFindSubdev(SoftMixerT *mixer, const char *streamUid, const char *targetUid, AlsaSndLoopT **loop); PUBLIC AlsaPcmHwInfoT *ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json_object *paramsJ); +PUBLIC AlsaPcmHwInfoT* ApiPcmParamsDup(SoftMixerT* mixer, AlsaPcmHwInfoT* params); +PUBLIC void ApiPcmParamsShow(SoftMixerT * mixer, const char * msg, const AlsaPcmHwInfoT * params); PUBLIC void ApiPcmDelParams(SoftMixerT*, AlsaPcmHwInfoT*); PUBLIC AlsaSndPcmT *ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm_stream_t direction, json_object *argsJ); diff --git a/plugins/alsa/alsa-transaction.c b/plugins/alsa/alsa-transaction.c index bd32603..1958c87 100644 --- a/plugins/alsa/alsa-transaction.c +++ b/plugins/alsa/alsa-transaction.c @@ -5,23 +5,30 @@ #include "alsa-transaction.h" #include "wrap-json.h" + +void AlsaMixerTransactionDelete(AlsaMixerTransaction * transaction) { + free((char*)transaction->uid); + free(transaction); +} + AlsaMixerTransaction * AlsaMixerTransactionNew(struct SoftMixerT_ * mixer, const char * uid) { - AlsaMixerTransaction * newList = (AlsaMixerTransaction *) malloc(sizeof(AlsaMixerTransaction)); - if (newList == NULL) + AlsaMixerTransaction * transaction = (AlsaMixerTransaction *) malloc(sizeof(AlsaMixerTransaction)); + if (transaction == NULL) goto fail; - CDS_INIT_LIST_HEAD(&newList->list); - newList->uid = strdup(uid); - if (newList->uid == NULL) { + CDS_INIT_LIST_HEAD(&transaction->item_list); + transaction->uid = strdup(uid); + if (transaction->uid == NULL) { goto fail_list; } - newList->mixer = mixer; + transaction->mixer = mixer; + cds_list_add(&transaction->transaction_node, &mixer->transactionList); - return newList; + return transaction; fail_list: - free(newList); + free(transaction); fail: return NULL; } @@ -30,6 +37,15 @@ void AlsaMixerTransactionDataListDestroy(AlsaMixerTransaction* list) { free(list); } +void AlsaMixerTransactionObjectForget(AlsaMixerTransaction* list, void * object) { + AlsaMixerTransactionDataItem *item, *tmp; + cds_list_for_each_entry_safe(item, tmp, &list->item_list, list_entry) + if (item->object == object) { + cds_list_del(&item->list_entry); + free(item); + } + } + bool AlsaMixerTransactionObjectAdd(AlsaMixerTransaction* list, void* object, AlsaTransactionDestructor destructor) { bool ret = false; AlsaMixerTransactionDataItem * newItem = NULL; @@ -43,7 +59,7 @@ bool AlsaMixerTransactionObjectAdd(AlsaMixerTransaction* list, void* object, Als CDS_INIT_LIST_HEAD(&newItem->list_entry); newItem->object = object; newItem->destructor = destructor; - cds_list_add(&newItem->list_entry, &list->list); + cds_list_add(&newItem->list_entry, &list->item_list); ret = true; fail: @@ -54,13 +70,17 @@ fail: void AlsaMixerTransactionDoCleanup(AlsaMixerTransaction* transaction) { AlsaMixerTransactionDataItem * item, *sav; - cds_list_for_each_entry_safe(item, sav, &transaction->list, list_entry) { + AFB_ApiInfo(transaction->mixer->api, "%s for transaction %s", __func__, transaction->uid); + + cds_list_for_each_entry_safe(item, sav, &transaction->item_list, list_entry) { if (item->destructor) item->destructor(transaction->mixer, item->object); cds_list_del(&item->list_entry); free(item); } + + AFB_ApiInfo(transaction->mixer->api, "%s for transaction %s .. DONE !", __func__, transaction->uid); } void AlsaMixerTransactionVerbCB(AFB_ReqT request) { @@ -69,43 +89,47 @@ void AlsaMixerTransactionVerbCB(AFB_ReqT request) { json_object *argsJ = afb_req_json(request); int error; char * action = NULL; - const char * uid; + const char * uid = NULL; error = wrap_json_unpack(argsJ, "{ss!}", "action", &action); if (error) { AFB_ReqFailF(request, "missing action", "%s: missing 'action' field: %s", transaction->uid, json_object_get_string(argsJ)); - goto OnErrorExit; + goto fail; } uid = strdup(transaction->uid); if (!uid) { SOFTMIXER_NOMEM(transaction->mixer->api); - goto OnErrorExit; + goto fail; } if (strcmp(action, "remove") == 0) { AlsaMixerTransactionDoCleanup(transaction); - error = afb_api_del_verb(transaction->mixer->api, transaction->uid, (void**)transaction); + + // remove this transaction for the list of mixer + cds_list_del(&transaction->transaction_node); + + error = afb_api_del_verb(transaction->mixer->api, transaction->uid, (void**)NULL); if (error) { AFB_ReqFail(request, "verb deletion" , "verb was not removed"); - goto OnErrorExit; + goto fail; } + AlsaMixerTransactionDelete(transaction); + } else { AFB_ReqFailF(request, "unsupported action", "%s: unsupported action %s (supported ones are ['remove']", transaction->uid, action); - goto OnErrorExit; + goto fail; } responseJ=json_object_new_object(); json_object_object_add(responseJ, "result", json_object_new_string("OK")); AFB_ReqSuccess(request, responseJ, uid); +fail: free((char*)uid); return; -OnErrorExit: - return; - } diff --git a/plugins/alsa/alsa-transaction.h b/plugins/alsa/alsa-transaction.h index a0af0ae..dd6e91b 100644 --- a/plugins/alsa/alsa-transaction.h +++ b/plugins/alsa/alsa-transaction.h @@ -13,7 +13,8 @@ typedef void (*AlsaTransactionDestructor) (struct SoftMixerT_ *, void*); typedef struct { const char * uid; struct SoftMixerT_* mixer; - struct cds_list_head list; + struct cds_list_head item_list; // list of items + struct cds_list_head transaction_node; // node in a list of transactions } AlsaMixerTransaction; typedef struct { @@ -24,10 +25,14 @@ typedef struct { extern AlsaMixerTransaction * AlsaMixerTransactionNew(struct SoftMixerT_ * api, const char*); +extern void AlsaMixerTransactionDelete(AlsaMixerTransaction * transaction); + extern void AlsaMixerTransactionDataListDestroy(AlsaMixerTransaction*); extern bool AlsaMixerTransactionObjectAdd(AlsaMixerTransaction*, void * object, AlsaTransactionDestructor destructor); +extern void AlsaMixerTransactionObjectForget(AlsaMixerTransaction* list, void * object); + extern void AlsaMixerTransactionDoCleanup(AlsaMixerTransaction*); extern bool AlsaMixerTransactionVerbCreate(AlsaMixerTransaction*); diff --git a/plugins/alsa/alsa-utils-bypath.c b/plugins/alsa/alsa-utils-bypath.c index 908d247..49f89e4 100644 --- a/plugins/alsa/alsa-utils-bypath.c +++ b/plugins/alsa/alsa-utils-bypath.c @@ -91,15 +91,18 @@ PUBLIC void AlsaPcmCtlDelete(SoftMixerT* mixer, void * arg) { AlsaPcmCtlT * pcmCtl = (AlsaPcmCtlT *) arg; + AFB_ApiDebug(mixer->api, "%s of %s (plug: %d)", __func__, pcmCtl->name, pcmCtl->isPcmPlug); + if (!pcmCtl->closeAtDeletion) goto done; + // TODO REMOVE THIS ONCE THE BUG IN BLUEZ-ALSA IS CORRECTED. Else Closing it make SIGSEGV if (pcmCtl->isPcmPlug) { - AFB_ApiDebug(mixer->api, "%s: Wont' close '%s' PCM, its slave is a plug", __func__, pcmCtl->cid.cardid); + AFB_ApiDebug(mixer->api, "%s: Wont' close '%s' PCM, it uses is a plug", __func__, pcmCtl->cid.cardid); goto done; } - AFB_ApiDebug(mixer->api, "%s: Closing %s",__func__, pcmCtl->cid.cardid); + AFB_ApiDebug(mixer->api, "%s: Closing %s", __func__, pcmCtl->cid.cardid); error = snd_pcm_close(pcmCtl->handle); if (error) { // It's safe to ignore this error. In case of ioplug PCM, the device may have already disappeared @@ -109,8 +112,13 @@ PUBLIC void AlsaPcmCtlDelete(SoftMixerT* mixer, void * arg) { done: + ApiPcmDelParams(mixer, pcmCtl->params); + free((char*) pcmCtl->cid.cardid); free(pcmCtl); + + AFB_ApiDebug(mixer->api, "%s DONE", __func__); + } PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcmCtl(SoftMixerT *mixer, AlsaDevInfoT *pcmDev, snd_pcm_stream_t direction) { @@ -156,7 +164,6 @@ PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcmCtl(SoftMixerT *mixer, AlsaDevInfoT *pcmDev goto fail_cardid; } - // inherit CID from pcmDev pcmCtl->cid.cardid = pcmDev->cardid; pcmCtl->cid.cardidx = pcmDev->cardidx; @@ -165,6 +172,9 @@ PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcmCtl(SoftMixerT *mixer, AlsaDevInfoT *pcmDev pcmCtl->cid.name=NULL; pcmCtl->cid.longname=NULL; + if (pcmDev->pcmplug_params) + pcmCtl->isPcmPlug = true; + AFB_ApiDebug(mixer->api, "%s OPEN PCM '%s', direction %s", __func__, pcmDev->cardid, direction==SND_PCM_STREAM_PLAYBACK?"playback":"capture"); |