summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-api-zones.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/alsa/alsa-api-zones.c')
-rw-r--r--plugins/alsa/alsa-api-zones.c196
1 files changed, 116 insertions, 80 deletions
diff --git a/plugins/alsa/alsa-api-zones.c b/plugins/alsa/alsa-api-zones.c
index 8f383df..32af733 100644
--- a/plugins/alsa/alsa-api-zones.c
+++ b/plugins/alsa/alsa-api-zones.c
@@ -16,7 +16,7 @@
*
*/
-#define _GNU_SOURCE // needed for vasprintf
+#define _GNU_MIXER // needed for vasprintf
#include "alsa-softmixer.h"
#include <string.h>
@@ -24,133 +24,169 @@
// Fulup need to be cleanup with new controller version
extern Lua2cWrapperT Lua2cWrap;
-STATIC int ProcessOneChannel(CtlSourceT *source, const char* uid, json_object *channelJ, AlsaPcmChannelT *channel) {
- const char*channelUid;
+PUBLIC AlsaSndZoneT *ApiZoneGetByUid(SoftMixerT *mixer, const char *target) {
- int error = wrap_json_unpack(channelJ, "{ss,si,s?i !}", "target", &channelUid, "channel", &channel->port);
+ assert(mixer->zones[0]);
+
+ // search for subdev into every registered loop
+ for (int idx = 0; mixer->zones[idx]; idx++) {
+ if (mixer->zones[idx]->uid && !strcasecmp(mixer->zones[idx]->uid, target)) {
+ return mixer->zones[idx];
+ }
+ }
+ AFB_ApiError(mixer->api, "ApiZoneGetByUid mixer=%s fail to find zone=%s", mixer->uid, target);
+ return NULL;
+}
+
+STATIC AlsaPcmChannelT* ProcessOneChannel(SoftMixerT *mixer, const char* uid, json_object *channelJ) {
+ AlsaPcmChannelT *channel = calloc(1, sizeof (AlsaPcmChannelT));
+
+ int error = wrap_json_unpack(channelJ, "{ss,si !}"
+ , "target", &channel->uid
+ , "channel", &channel->port
+ );
if (error) goto OnErrorExit;
- channel->uid = strdup(channelUid);
- return 0;
+ channel->uid = strdup(channel->uid);
+ return channel;
OnErrorExit:
- AFB_ApiError(source->api, "ProcessOneChannel: zone=%s channel: missing (target||channel) json=%s", uid, json_object_get_string(channelJ));
- return -1;
+ AFB_ApiError(mixer->api, "ProcessOneChannel: zone=%s channel: missing (target|channel) json=%s", uid, json_object_get_string(channelJ));
+ return NULL;
}
-STATIC int ProcessOneZone(CtlSourceT *source, json_object *zoneJ, AlsaSndZoneT *zone) {
- json_object *mappingJ;
+STATIC AlsaSndZoneT *AttacheOneZone(SoftMixerT *mixer, const char *uid, json_object *zoneJ) {
+ AlsaSndZoneT *zone = calloc(1, sizeof (AlsaSndZoneT));
+ json_object *sinkJ = NULL, *sourceJ = NULL;
size_t count;
- const char* streamType;
int error;
- error = wrap_json_unpack(zoneJ, "{ss,s?s,so !}"
+ error = wrap_json_unpack(zoneJ, "{ss,s?o,s?o !}"
, "uid", &zone->uid
- , "type", &streamType
- , "mapping", &mappingJ
+ , "sink", &sinkJ
+ , "source", &sourceJ
);
- if (error) {
- AFB_ApiNotice(source->api, "ProcessOneZone missing 'uid|type|mapping' zone=%s", json_object_get_string(zoneJ));
+ if (error || (!sinkJ && sourceJ)) {
+ AFB_ApiNotice(mixer->api, "AttacheOneZone missing 'uid|sink|source' error=%s zone=%s", wrap_json_get_error_string(error), json_object_get_string(zoneJ));
goto OnErrorExit;
}
- if (!streamType) zone->type = SND_PCM_STREAM_PLAYBACK;
- else {
- if (!strcasecmp(streamType, "capture")) zone->type = SND_PCM_STREAM_CAPTURE;
- else if (!strcasecmp(streamType, "playback")) zone->type = SND_PCM_STREAM_PLAYBACK;
- else {
- AFB_ApiError(source->api, "ProcessOneZone:%s invalid stream type !(playback||capture) json=%s", zone->uid, json_object_get_string(zoneJ));
- goto OnErrorExit;
- }
- }
-
// make sure remain valid even when json object is removed
zone->uid = strdup(zone->uid);
- switch (json_object_get_type(mappingJ)) {
- case json_type_object:
- count = 1;
- zone->channels = calloc(count + 1, sizeof (AlsaPcmChannelT));
- error = ProcessOneChannel(source, zone->uid, mappingJ, &zone->channels[0]);
- if (error) goto OnErrorExit;
- break;
- case json_type_array:
- count = json_object_array_length(mappingJ);
- zone->channels = calloc(count + 1, sizeof (AlsaPcmChannelT));
- for (int idx = 0; idx < count; idx++) {
- json_object *channelJ = json_object_array_get_idx(mappingJ, idx);
- error = ProcessOneChannel(source, zone->uid, channelJ, &zone->channels[idx]);
- if (error) goto OnErrorExit;
- }
- break;
- default:
- AFB_ApiError(source->api, "ProcessOneZone:%s invalid mapping=%s", zone->uid, json_object_get_string(mappingJ));
- goto OnErrorExit;
+ if (sinkJ) {
+
+ switch (json_object_get_type(sinkJ)) {
+ case json_type_object:
+ zone->sinks = calloc(2, sizeof (void*));
+ zone->sinks[0] = ProcessOneChannel(mixer, zone->uid, sinkJ);
+ if (!zone->sinks[0]) goto OnErrorExit;
+
+ break;
+ case json_type_array:
+ count = json_object_array_length(sinkJ);
+ zone->sinks = calloc(count + 1, sizeof (void*));
+ for (int idx = 0; idx < count; idx++) {
+ json_object *subdevJ = json_object_array_get_idx(sinkJ, idx);
+ zone->sinks[idx] = ProcessOneChannel(mixer, zone->uid, subdevJ);
+ if (error) goto OnErrorExit;
+ }
+ break;
+ default:
+ AFB_ApiError(mixer->api, "AttacheOneZone: Mixer=%s Hal=%s zone=%s invalid mapping=%s", mixer->uid, uid, zone->uid, json_object_get_string(sinkJ));
+ goto OnErrorExit;
+ }
+
}
- return 0;
+ if (sourceJ) {
+ switch (json_object_get_type(sourceJ)) {
+ case json_type_object:
+ zone->sources = calloc(2, sizeof (void*));
+ zone->sources[0] = ProcessOneChannel(mixer, zone->uid, sourceJ);
+ if (!zone->sources[0]) goto OnErrorExit;
+ break;
+ case json_type_array:
+ count = json_object_array_length(sourceJ);
+ zone->sources = calloc(count + 1, sizeof (void*));
+ for (int idx = 0; idx < count; idx++) {
+ json_object *subdevJ = json_object_array_get_idx(sourceJ, idx);
+ zone->sources[idx] = ProcessOneChannel(mixer, zone->uid, subdevJ);
+ if (error) goto OnErrorExit;
+ }
+ break;
+ default:
+ AFB_ApiError(mixer->api, "AttacheOneZone:Mixer=%s Hal=%s zone=%s mapping=%s", mixer->uid, uid, zone->uid, json_object_get_string(sourceJ));
+ goto OnErrorExit;
+ }
+ }
+
+ return zone;
OnErrorExit:
- return -1;
+ return NULL;
}
-PUBLIC int SndZones(CtlSourceT *source, json_object *argsJ) {
- SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
- AlsaSndZoneT *zones=NULL;
- int error;
- size_t count;
+PUBLIC int ApiZoneAttach(SoftMixerT *mixer, AFB_ReqT request, const char *uid, json_object * argsJ) {
- assert(mixerHandle);
+ int index;
+ for (index = 0; index < mixer->max.zones; index++) {
+ if (!mixer->zones[index]) break;
+ }
- if (mixerHandle->routes) {
- AFB_ApiError(source->api, "SndZones: mixer=%s Zones already Registryed %s", mixerHandle->uid, json_object_get_string(argsJ));
+ if (index == mixer->max.zones) {
+ AFB_ReqFailF(request, "too-small", "mixer=%s max zone=%d argsJ= %s", mixer->uid, mixer->max.zones, json_object_get_string(argsJ));
goto OnErrorExit;
}
switch (json_object_get_type(argsJ)) {
+ long count;
+
case json_type_object:
- count = 1;
- zones = calloc(count + 1, sizeof (AlsaSndZoneT));
- error = ProcessOneZone(source, argsJ, &zones[0]);
- if (error) {
- AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(argsJ));
+ mixer->zones[index] = AttacheOneZone(mixer, uid, argsJ);
+ if (!mixer->zones[index]) {
+ AFB_ReqFailF(request, "invalid-syntax", "mixer=%s invalid zone= %s", mixer->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
+
+ AlsaPcmCtlT *routeConfig = AlsaCreateRoute(mixer, mixer->zones[index], 0);
+ if (!routeConfig) {
+ AFB_ApiError(mixer->api, "AttacheOneZone: Mixer=%s Hal=%s zone=%s Fail to attach PCM Route", mixer->uid, uid, mixer->zones[index]->uid);
+ goto OnErrorExit;
+ }
+
break;
case json_type_array:
count = json_object_array_length(argsJ);
- zones = calloc(count + 1, sizeof (AlsaSndZoneT));
+ if (count > (mixer->max.zones - count)) {
+ AFB_ReqFailF(request, "too-small", "mixer=%s max zone=%d argsJ= %s", mixer->uid, mixer->max.zones, json_object_get_string(argsJ));
+ goto OnErrorExit;
+
+ }
+
for (int idx = 0; idx < count; idx++) {
- json_object *sndZoneJ = json_object_array_get_idx(argsJ, idx);
- error = ProcessOneZone(source, sndZoneJ, &zones[idx]);
- if (error) {
- AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(sndZoneJ));
+ json_object *zoneJ = json_object_array_get_idx(argsJ, idx);
+ mixer->zones[index + idx] = AttacheOneZone(mixer, uid, zoneJ);
+ if (!mixer->zones[index + idx]) {
+ AFB_ReqFailF(request, "invalid-syntax", "mixer=%s invalid zone= %s", mixer->uid, json_object_get_string(zoneJ));
+ goto OnErrorExit;
+ }
+
+ AlsaPcmCtlT *routeConfig = AlsaCreateRoute(mixer, mixer->zones[idx], 0);
+ if (!routeConfig) {
+ AFB_ApiError(mixer->api, "AttacheOneZone: Mixer=%s Hal=%s zone=%s Fail to attach PCM Route", mixer->uid, uid, mixer->zones[idx]->uid);
goto OnErrorExit;
}
}
break;
default:
- AFB_ApiError(source->api, "SndZones: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ));
+ AFB_ReqFailF(request, "invalid-syntax", "mixer=%s zones invalid argsJ= %s", mixer->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
- // Registry routed into global softmixer handle
- mixerHandle->routes= calloc(count + 1, sizeof (AlsaPcmInfoT*));
-
- // instantiate one route PCM per zone with multi plugin as slave
- for (int idx = 0; zones[idx].uid != NULL; idx++) {
- mixerHandle->routes[idx] = AlsaCreateRoute(source, &zones[idx], 0);
- if (!mixerHandle->routes[idx]) {
- AFB_ApiNotice(source->api, "SndZones: mixer=%s fail to create route zone=%s", mixerHandle->uid, zones[idx].uid);
- goto OnErrorExit;
- }
- }
-
- free (zones);
return 0;
OnErrorExit:
- if (zones) free(zones);
return -1;
} \ No newline at end of file