diff options
Diffstat (limited to 'plugins/alsa/alsa-api-mixer.c')
-rw-r--r-- | plugins/alsa/alsa-api-mixer.c | 123 |
1 files changed, 96 insertions, 27 deletions
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c index db5f129..b910b9f 100644 --- a/plugins/alsa/alsa-api-mixer.c +++ b/plugins/alsa/alsa-api-mixer.c @@ -20,6 +20,8 @@ #include "alsa-softmixer.h" #include <string.h> +#include <pthread.h> + // Fulup need to be cleanup with new controller version extern Lua2cWrapperT Lua2cWrap; @@ -32,18 +34,18 @@ static void MixerApiVerbCB(AFB_ReqT request) { json_object *argsJ = afb_request_json(request); json_object *responseJ = json_object_new_object(); - SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) afb_request_get_vcbdata(request); + SoftMixerHandleT *mixer = (SoftMixerHandleT*) afb_request_get_vcbdata(request); int error; - int close = 0; + int delete = 0; CtlSourceT *source = alloca(sizeof (CtlSourceT)); - source->uid = mixerHandle->uid; + source->uid = mixer->uid; source->api = request->dynapi; source->request = request; - source->context = mixerHandle; + source->context = mixer; error = wrap_json_unpack(argsJ, "{s?b,s?o,s?o,s?o,s?o,s?o !}" - , "close", &close + , "delete", &delete , "list", &listJ , "backend", &backendJ , "frontend", &frontendJ @@ -51,14 +53,57 @@ static void MixerApiVerbCB(AFB_ReqT request) { , "streams", &streamsJ ); if (error) { - AFB_ReqFailF(request, "invalid syntax", "request missing 'uid|list|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ)); + AFB_ReqFailF(request, "invalid-syntax", "request missing 'uid|list|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ)); goto OnErrorExit; } // Free attached resources and free mixer - if (close) { - AFB_ReqFailF(request, "not implemented", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ)); - goto OnErrorExit; + if (delete) { + for (int idx; mixer->streams[idx].uid; idx++) { + AlsaLoopStreamT *stream = &mixer->streams[idx]; + + AFB_ApiNotice(source->api, "cleaning mixer=%s stream=%s", mixer->uid, stream->uid); + + error = pthread_cancel(stream->copy.thread); + if (error) { + AFB_ReqFailF(request, "internal-error", "Fail to kill audio-stream threads mixer=%s", mixer->uid); + goto OnErrorExit; + } + + char apiStreamVerb[128]; + error = snprintf(apiStreamVerb, sizeof (apiStreamVerb), "%s/%s", mixer->uid, stream->uid); + if (error == sizeof (apiStreamVerb)) { + AFB_ApiError(source->api, "LoopStreams mixer=%s fail to Registry Stream API too long %s/%s", mixer->uid, mixer->uid, stream->uid); + goto OnErrorExit; + } + + error = afb_dynapi_sub_verb(source->api, apiStreamVerb); + if (error) { + AFB_ApiError(source->api, "fail to Clean API verb=%s", apiStreamVerb); + goto OnErrorExit; + } + + // 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); + + } + + // registry is attached to frontend + if (mixer->frontend->registry)free(mixer->frontend->registry); + + error = afb_dynapi_sub_verb(source->api, mixer->uid); + if (error) { + AFB_ApiError(source->api, "fail to Clean API verb=%s", mixer->uid); + goto OnErrorExit; + } + + // finally free mixer handle + free(mixer); + responseJ = json_object_new_string("Fulup: delete might not clean everything properly"); + goto OnSuccessExit; } if (listJ) { @@ -72,14 +117,14 @@ static void MixerApiVerbCB(AFB_ReqT request) { , "zones", &zones ); if (error) { - AFB_ReqFailF(request, "invalid syntax", "list missing 'uid|backend|frontend|zones|streams' list=%s", json_object_get_string(listJ)); + AFB_ReqFailF(request, "invalid-syntax", "list missing 'uid|backend|frontend|zones|streams' list=%s", json_object_get_string(listJ)); goto OnErrorExit; } if (streams) { streamsJ = json_object_new_array(); - AlsaLoopStreamT *streams = mixerHandle->streams; + AlsaLoopStreamT *streams = mixer->streams; for (int idx = 0; streams[idx].uid; idx++) { if (quiet) { json_object_array_add(streamsJ, json_object_new_string(streams[idx].uid)); @@ -87,20 +132,20 @@ static void MixerApiVerbCB(AFB_ReqT request) { json_object *numidJ; wrap_json_pack(&numidJ, "{si,si}" , "volume", streams[idx].volume - , "mute", streams[idx].mute + , "mute", streams[idx].mute ); wrap_json_pack(&valueJ, "{ss,so}" , "uid", streams[idx].uid , "numid", numidJ ); json_object_array_add(streamsJ, valueJ); - AFB_ApiWarning (request->dynapi, "stream=%s", json_object_get_string(streamsJ)); + AFB_ApiWarning(request->dynapi, "stream=%s", json_object_get_string(streamsJ)); } - + } json_object_object_add(responseJ, "streams", streamsJ); } - + if (backend || frontend || zones) { AFB_ReqFailF(request, "not implemented", "(Fulup) list action Still To Be Done"); goto OnErrorExit; @@ -109,7 +154,7 @@ static void MixerApiVerbCB(AFB_ReqT request) { AFB_ReqSucess(request, responseJ, NULL); return; } - + if (backendJ) { error = SndBackend(source, backendJ); if (error) goto OnErrorExit; @@ -130,8 +175,8 @@ static void MixerApiVerbCB(AFB_ReqT request) { if (error) goto OnErrorExit; } - - AFB_ReqSucess(request, responseJ, mixerHandle->uid); +OnSuccessExit: + AFB_ReqSucess(request, responseJ, mixer->uid); return; OnErrorExit: @@ -139,7 +184,7 @@ OnErrorExit: } CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) { - SoftMixerHandleT *mixerHandle = calloc(1, sizeof (SoftMixerHandleT)); + SoftMixerHandleT *mixer = calloc(1, sizeof (SoftMixerHandleT)); json_object *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL; int error; assert(source->api); @@ -150,8 +195,8 @@ CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) { } error = wrap_json_unpack(argsJ, "{ss,s?s,s?o,s?o,s?o,s?o !}" - , "uid", &mixerHandle->uid - , "info", &mixerHandle->info + , "uid", &mixer->uid + , "info", &mixer->info , "backend", &backendJ , "frontend", &frontendJ , "zones", &zonesJ @@ -162,18 +207,18 @@ CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) { } // make sure string do not get deleted - mixerHandle->uid = strdup(mixerHandle->uid); - if (mixerHandle->info)mixerHandle->info = strdup(mixerHandle->info); + mixer->uid = strdup(mixer->uid); + if (mixer->info)mixer->info = strdup(mixer->info); // create mixer verb within API. - error = afb_dynapi_add_verb(source->api, mixerHandle->uid, mixerHandle->info, MixerApiVerbCB, mixerHandle, NULL, 0); + error = afb_dynapi_add_verb(source->api, mixer->uid, mixer->info, MixerApiVerbCB, mixer, NULL, 0); if (error) { - AFB_ApiError(source->api, "_mixer_new_ mixer=%s fail to Registry API verb", mixerHandle->uid); + AFB_ApiError(source->api, "_mixer_new_ mixer=%s fail to Registry API verb", mixer->uid); return -1; } // make sure sub command get access to mixer handle - source->context = mixerHandle; + source->context = mixer; if (backendJ) { error = SndBackend(source, backendJ); @@ -199,4 +244,28 @@ CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) { OnErrorExit: return -1; -}
\ No newline at end of file +} + +// provide a similar command but for API + +CTLP_CAPI(mixer_new, source, argsJ, queryJ) { + json_object * responseJ; + + // merge static config args with dynamic one coming from the request + if (argsJ && json_object_get_type(argsJ) == json_type_object) { + + json_object_object_foreach(argsJ, key, val) { + json_object_get(val); + json_object_object_add(queryJ, key, val); + } + } + + int error = _mixer_new_(source, queryJ, &responseJ); + + if (error) + AFB_ReqFailF(source->request, "fail-create", "invalid arguments"); + else + AFB_ReqSucess(source->request, responseJ, NULL); + + return error; +} |