diff options
-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"); |