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.c262
1 files changed, 201 insertions, 61 deletions
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c
index 8616384..ca90649 100644
--- a/plugins/alsa/alsa-api-mixer.c
+++ b/plugins/alsa/alsa-api-mixer.c
@@ -62,7 +62,7 @@ static void MixerRemoveVerb(AFB_ReqT request) {
// finally free mixer handle
free(mixer);
- AFB_ReqSucess(request, NULL, "Fulup: delete might not clean everything properly");
+ AFB_ReqSuccess(request, NULL, "Fulup: delete might not clean everything properly");
return;
@@ -70,21 +70,124 @@ OnErrorExit:
AFB_ReqFail(request, "internal-error", "fail to delete mixer");
}
-STATIC void MixerInfoAction(AFB_ReqT request, json_object *argsJ) {
+STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ, int verbose) {
+ const char * key;
+ json_object *valueJ;
+ json_object *responseJ = json_object_new_array();
+ AlsaStreamAudioT **streams = mixer->streams;
+
+ switch (json_object_get_type(streamsJ)) {
+
+ case json_type_null:
+ case json_type_boolean:
+
+ for (int idx = 0; streams[idx]; idx++) {
+ json_object *alsaJ;
+
+ if (!verbose) {
+ wrap_json_pack(&alsaJ, "{ss}", "alsa", streams[idx]->source);
+ json_object_array_add(responseJ, alsaJ);
+ } else {
+
+ wrap_json_pack(&alsaJ, "{ss,si,si}"
+ , "cardid", streams[idx]->source
+ , "volume", streams[idx]->volume
+ , "mute", streams[idx]->mute
+ );
+ wrap_json_pack(&valueJ, "{ss,ss,so}"
+ , "uid", streams[idx]->uid
+ , "verb", streams[idx]->verb
+ , "alsa", alsaJ
+ );
+ json_object_array_add(responseJ, valueJ);
+ }
+ }
+ break;
+
+ case json_type_string:
+
+ key = json_object_get_string(streamsJ);
+ for (int idx = 0; streams[idx]; idx++) {
+ json_object *alsaJ;
+
+ if (!strcasestr(streams[idx]->uid, key)) continue;
+
+ if (!verbose) {
+ wrap_json_pack(&alsaJ, "{ss}", "alsa", streams[idx]->source);
+ json_object_array_add(responseJ, alsaJ);
+ } else {
+
+ wrap_json_pack(&alsaJ, "{ss,si,si}"
+ , "cardid", streams[idx]->source
+ , "volume", streams[idx]->volume
+ , "mute", streams[idx]->mute
+ );
+ wrap_json_pack(&valueJ, "{ss,ss,so}"
+ , "uid", streams[idx]->uid
+ , "verb", streams[idx]->verb
+ , "alsa", alsaJ
+ );
+ json_object_array_add(responseJ, valueJ);
+ }
+ }
+ break;
+
+ case json_type_array:
+
+ for (int idx=0; idx < json_object_array_length(streamsJ); idx++) {
+ json_object *streamJ = json_object_array_get_idx(streamsJ, idx);
+ valueJ= MixerInfoStreams (mixer, streamJ, verbose);
+ json_object_array_add(responseJ, valueJ);
+ }
+
+ default:
+ goto OnErrorExit;
+ }
+ return (responseJ);
+
+OnErrorExit:
+ return NULL;
+}
+
+STATIC json_object * MixerInfoRamps(SoftMixerT *mixer, int verbose) {
+
+ json_object *rampsJ = json_object_new_array();
+ json_object *valueJ;
+
+ AlsaVolRampT **ramps = mixer->ramps;
+ for (int idx = 0; ramps[idx]; idx++) {
+ if (!verbose) {
+ json_object_array_add(rampsJ, json_object_new_string(ramps[idx]->uid));
+ } else {
+ wrap_json_pack(&valueJ, "{ss,si,si,si}"
+ , "uid", ramps[idx]->uid
+ , "delay", ramps[idx]->delay
+ , "step_down", ramps[idx]->stepDown
+ , "step_up", ramps[idx]->stepUp
+ );
+ json_object_array_add(rampsJ, valueJ);
+ }
+ }
+
+ return (rampsJ);
+}
+
+STATIC void MixerInfoAction(AFB_ReqT request, json_object * argsJ) {
SoftMixerT *mixer = (SoftMixerT*) afb_request_get_vcbdata(request);
- int error, streams = 0, quiet = 0, ramps = 0, zones = 0, captures = 0, playbacks = 0;
+ int error, verbose = 0, ramps = 0, zones = 0, captures = 0, playbacks = 0;
+ json_object *streamsJ = NULL;
if (json_object_get_type(argsJ) == json_type_null) {
- streams = 1;
+ streamsJ = json_object_new_boolean(1);
ramps = 1;
zones = 0;
captures = 0;
playbacks = 0;
} else {
- error = wrap_json_unpack(argsJ, "{s?b,s?b,s?b,s?b,s?b,s?b !}"
- , "quiet", &quiet
- , "streams", &streams
+ error = wrap_json_unpack(argsJ, "{s?b,s?o,s?b,s?b,s?b,s?b !}"
+ , "verbose", &verbose
+ , "streams", &streamsJ
, "ramps", &ramps
, "captures", &captures
, "playbacks", &playbacks
@@ -97,48 +200,17 @@ STATIC void MixerInfoAction(AFB_ReqT request, json_object *argsJ) {
}
json_object *responseJ = json_object_new_object();
- if (streams) {
- json_object *streamsJ = json_object_new_array();
- json_object *valueJ;
-
- AlsaStreamAudioT **streams = mixer->streams;
- for (int idx = 0; streams[idx]; idx++) {
- if (quiet) {
- json_object_array_add(streamsJ, json_object_new_string(streams[idx]->uid));
- } else {
- wrap_json_pack(&valueJ, "{ss,ss?,s{si,si}}"
- , "uid", streams[idx]->uid
- , "alsa", streams[idx]->source
- , "numid"
- , "volume", streams[idx]->volume
- , "mute", streams[idx]->mute
- );
- json_object_array_add(streamsJ, valueJ);
- }
-
+ if (streamsJ) {
+ json_object *resultJ = MixerInfoStreams(mixer, streamsJ, verbose);
+ if (!resultJ) {
+ AFB_ReqFailF(request, "invalid-object", "streams should be boolean or string argsJ=%s", json_object_get_string(streamsJ));
+ goto OnErrorExit;
}
- json_object_object_add(responseJ, "streams", streamsJ);
+ json_object_object_add(responseJ, "streams", resultJ);
}
if (ramps) {
- json_object *rampsJ = json_object_new_array();
- json_object *valueJ;
-
- AlsaVolRampT **ramps = mixer->ramps;
- for (int idx = 0; ramps[idx]; idx++) {
- if (quiet) {
- json_object_array_add(rampsJ, json_object_new_string(ramps[idx]->uid));
- } else {
- wrap_json_pack(&valueJ, "{ss,si,si,si}"
- , "uid", ramps[idx]->uid
- , "delay", ramps[idx]->delay
- , "step_down", ramps[idx]->stepDown
- , "step_up", ramps[idx]->stepUp
- );
- json_object_array_add(rampsJ, valueJ);
- }
-
- }
+ json_object *rampsJ = MixerInfoRamps (mixer, verbose);
json_object_object_add(responseJ, "ramps", rampsJ);
}
@@ -147,7 +219,7 @@ STATIC void MixerInfoAction(AFB_ReqT request, json_object *argsJ) {
AlsaSndZoneT **zones = mixer->zones;
for (int idx = 0; zones[idx]; idx++) {
- if (quiet) {
+ if (!verbose) {
json_object_array_add(zonesJ, json_object_new_string(zones[idx]->uid));
} else {
json_object *zoneJ = json_object_new_object();
@@ -198,7 +270,7 @@ STATIC void MixerInfoAction(AFB_ReqT request, json_object *argsJ) {
goto OnErrorExit;
}
- AFB_ReqSucess(request, responseJ, NULL);
+ AFB_ReqSuccess(request, responseJ, NULL);
return;
OnErrorExit:
@@ -206,19 +278,21 @@ OnErrorExit:
}
STATIC void MixerInfoVerb(AFB_ReqT request) {
- json_object *argsJ = afb_request_json(request);
- MixerInfoAction (request, argsJ);
+ json_object *argsJ = afb_request_json(request);
+ MixerInfoAction(request, argsJ);
}
STATIC void MixerAttachVerb(AFB_ReqT request) {
SoftMixerT *mixer = (SoftMixerT*) afb_request_get_vcbdata(request);
- const char *uid = NULL;
+ const char *uid = NULL, *prefix = NULL;
json_object *playbackJ = NULL, *captureJ = NULL, *zonesJ = NULL, *streamsJ = NULL, *rampsJ = NULL, *loopsJ = NULL;
json_object *argsJ = afb_request_json(request);
+ json_object *responseJ = json_object_new_object();
int error;
- error = wrap_json_unpack(argsJ, "{ss,s?o,s?o,s?o,s?o,s?o,s?o !}"
+ error = wrap_json_unpack(argsJ, "{ss,s?s,s?o,s?o,s?o,s?o,s?o,s?o !}"
, "uid", &uid
+ , "prefix", &prefix
, "ramps", &rampsJ
, "playbacks", &playbackJ
, "captures", &captureJ
@@ -227,7 +301,6 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
, "streams", &streamsJ
);
if (error) {
- AFB_ApiError(mixer->api, "MixerAttachVerb: invalid-syntax mixer=%s error=%s args=%s", mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
AFB_ReqFailF(request, "invalid-syntax", "mixer=%s missing 'uid|ramps|playbacks|captures|zones|streams' error=%s args=%s", mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
goto OnErrorExit;
}
@@ -255,15 +328,22 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
if (rampsJ) {
error = ApiRampAttach(mixer, request, uid, rampsJ);
if (error) goto OnErrorExit;
+
+ json_object *resultJ = MixerInfoStreams(mixer, streamsJ, 0);
+ json_object_object_add(responseJ, "ramps", resultJ);
}
if (streamsJ) {
- error = ApiStreamAttach(mixer, request, uid, streamsJ);
+ error = ApiStreamAttach(mixer, request, uid, prefix, streamsJ);
if (error) goto OnErrorExit;
+
+ json_object *resultJ = MixerInfoStreams(mixer, streamsJ, 0);
+ json_object_object_add(responseJ, "streams", resultJ);
}
- // return mixer info data after attach
- return (MixerInfoAction(request,NULL));
+ AFB_ReqSuccess(request, responseJ, NULL);
+
+ return;
OnErrorExit:
return;
@@ -273,7 +353,7 @@ STATIC void MixerPingVerb(AFB_ReqT request) {
static int count = 0;
count++;
AFB_ReqNotice(request, "Controller:ping count=%d", count);
- AFB_ReqSucess(request, json_object_new_int(count), NULL);
+ AFB_ReqSuccess(request, json_object_new_int(count), NULL);
return;
}
@@ -289,7 +369,7 @@ STATIC AFB_ApiVerbs CtrlApiVerbs[] = {
{ .verb = NULL} /* marker for end of the array */
};
-STATIC int LoadStaticVerbs(SoftMixerT *mixer, AFB_ApiVerbs *verbs) {
+STATIC int LoadStaticVerbs(SoftMixerT *mixer, AFB_ApiVerbs * verbs) {
int errcount = 0;
for (int idx = 0; verbs[idx].verb; idx++) {
@@ -299,8 +379,68 @@ STATIC int LoadStaticVerbs(SoftMixerT *mixer, AFB_ApiVerbs *verbs) {
return errcount;
};
-CTLP_CAPI(CreateMixer, source, argsJ, responseJ) {
+CTLP_CAPI(MixerAttach, source, argsJ, responseJ) {
+ SoftMixerT *mixer = source->context;
+ json_object *playbackJ = NULL, *captureJ = NULL, *zonesJ = NULL, *streamsJ = NULL, *rampsJ = NULL, *loopsJ = NULL;
+ const char* uid = source->uid, *prefix = NULL;
+
+ int error;
+
+ error = wrap_json_unpack(argsJ, "{s?s, s?o,s?o,s?o,s?o,s?o,s?o !}"
+ , "prefix", &rampsJ
+ , "ramps", &rampsJ
+ , "playbacks", &playbackJ
+ , "captures", &captureJ
+ , "loops", &loopsJ
+ , "zones", &zonesJ
+ , "streams", &streamsJ
+ );
+ if (error) {
+ AFB_ApiError(mixer->api, "MixerAttachVerb: invalid-syntax mixer=%s error=%s args=%s", mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ if (playbackJ) {
+ error = ApiSinkAttach(mixer, NULL, uid, playbackJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (captureJ) {
+ error = ApiSourceAttach(mixer, NULL, uid, captureJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (loopsJ) {
+ error = ApiLoopAttach(mixer, NULL, uid, loopsJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (zonesJ) {
+ error = ApiZoneAttach(mixer, NULL, uid, zonesJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (rampsJ) {
+ error = ApiRampAttach(mixer, NULL, uid, rampsJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (streamsJ) {
+ error = ApiStreamAttach(mixer, NULL, uid, prefix, streamsJ);
+ if (error) goto OnErrorExit;
+ }
+
+ // return mixer info data after attach
+ return 0;
+
+OnErrorExit:
+ return -1;
+}
+
+CTLP_CAPI(MixerCreate, source, argsJ, responseJ) {
SoftMixerT *mixer = calloc(1, sizeof (SoftMixerT));
+ source->context = mixer;
+
int error;
mixer->max.loops = SMIXER_DEFLT_RAMPS;
mixer->max.sinks = SMIXER_DEFLT_SINKS;
@@ -339,14 +479,14 @@ CTLP_CAPI(CreateMixer, source, argsJ, responseJ) {
mixer->zones = calloc(mixer->max.zones + 1, sizeof (void*));
mixer->streams = calloc(mixer->max.streams + 1, sizeof (void*));
mixer->ramps = calloc(mixer->max.ramps + 1, sizeof (void*));
-
+
mixer->sdLoop = AFB_GetEventLoop(source->api);
- mixer->api= source->api;
+ mixer->api = source->api;
afb_dynapi_set_userdata(source->api, mixer);
error = LoadStaticVerbs(mixer, CtrlApiVerbs);
if (error) goto OnErrorExit;
-
+
return 0;
OnErrorExit: