diff options
Diffstat (limited to 'plugins/alsa/alsa-api-zones.c')
-rw-r--r-- | plugins/alsa/alsa-api-zones.c | 196 |
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 |