summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-api-mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/alsa/alsa-api-mixer.c')
-rw-r--r--plugins/alsa/alsa-api-mixer.c123
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;
+}