summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2018-05-17 21:43:24 +0200
committerFulup Ar Foll <fulup@iot.bzh>2018-05-17 21:43:24 +0200
commit253df14bd84f535a54f4d12c95399899e1343c20 (patch)
tree16093cc86d2874afb3311124613e69e23e74acbc /plugins
parent29f5fc4e093b8793eaeeef056d0b998182269718 (diff)
Initial version with dynamic APIs
Diffstat (limited to 'plugins')
-rw-r--r--plugins/alsa/CMakeLists.txt2
-rw-r--r--plugins/alsa/alsa-api-backend.c (renamed from plugins/alsa/alsa-api-sndcards.c)78
-rw-r--r--plugins/alsa/alsa-api-frontend.c (renamed from plugins/alsa/alsa-api-sndloops.c)39
-rw-r--r--plugins/alsa/alsa-api-mixer.c150
-rw-r--r--plugins/alsa/alsa-api-streams.c (renamed from plugins/alsa/alsa-api-sndstreams.c)145
-rw-r--r--plugins/alsa/alsa-api-zones.c (renamed from plugins/alsa/alsa-api-sndzones.c)58
-rw-r--r--plugins/alsa/alsa-core-ctl.c1
-rw-r--r--plugins/alsa/alsa-plug-multi.c8
-rw-r--r--plugins/alsa/alsa-plug-route.c11
-rw-r--r--plugins/alsa/alsa-plug-vol.c24
-rw-r--r--plugins/alsa/alsa-softmixer.c5
-rw-r--r--plugins/alsa/alsa-softmixer.h30
12 files changed, 426 insertions, 125 deletions
diff --git a/plugins/alsa/CMakeLists.txt b/plugins/alsa/CMakeLists.txt
index 51f4639..687ccb2 100644
--- a/plugins/alsa/CMakeLists.txt
+++ b/plugins/alsa/CMakeLists.txt
@@ -17,7 +17,7 @@
###########################################################################
-PROJECT_TARGET_ADD(alsa-router)
+PROJECT_TARGET_ADD(alsa-softmixer)
file(GLOB SOURCE_FILES "alsa-*.c")
diff --git a/plugins/alsa/alsa-api-sndcards.c b/plugins/alsa/alsa-api-backend.c
index daa996a..948d30d 100644
--- a/plugins/alsa/alsa-api-sndcards.c
+++ b/plugins/alsa/alsa-api-backend.c
@@ -38,16 +38,16 @@ OnErrorExit:
}
PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params) {
- const char *format=NULL, *access=NULL;
+ const char *format = NULL, *access = NULL;
// some default values
- params->rate= ALSA_DEFAULT_PCM_RATE;
- params->channels= 2;
- params->sampleSize=0;
+ params->rate = ALSA_DEFAULT_PCM_RATE;
+ params->channels = 2;
+ params->sampleSize = 0;
- int error = wrap_json_unpack(paramsJ, "{s?i,s?i, s?s, s?s !}", "rate",&params->rate,"channels", &params->channels, "format",&format, "access",&access);
+ int error = wrap_json_unpack(paramsJ, "{s?i,s?i, s?s, s?s !}", "rate", &params->rate, "channels", &params->channels, "format", &format, "access", &access);
if (error) goto OnErrorExit;
-
+
if (!format) params->format = SND_PCM_FORMAT_S16_LE;
else if (!strcasecmp(format, "S16_LE")) params->format = SND_PCM_FORMAT_S16_LE;
else if (!strcasecmp(format, "S16_BE")) params->format = SND_PCM_FORMAT_S16_BE;
@@ -69,8 +69,8 @@ PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *pa
AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported format 'S16_LE|S32_L|...' format=%s", uid, format);
goto OnErrorExit;
}
-
- if (!access) params->access = SND_PCM_ACCESS_RW_INTERLEAVED;
+
+ if (!access) params->access = SND_PCM_ACCESS_RW_INTERLEAVED;
else if (!strcasecmp(access, "MMAP_INTERLEAVED")) params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
else if (!strcasecmp(access, "MMAP_NONINTERLEAVED")) params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
else if (!strcasecmp(access, "MMAP_COMPLEX")) params->access = SND_PCM_ACCESS_MMAP_COMPLEX;
@@ -78,7 +78,7 @@ PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *pa
else if (!strcasecmp(access, "RW_NONINTERLEAVED")) params->access = SND_PCM_ACCESS_RW_NONINTERLEAVED;
else {
- AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s",uid, access);
+ AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s", uid, access);
goto OnErrorExit;
}
@@ -89,11 +89,19 @@ OnErrorExit:
}
STATIC int ProcessOneSndCard(CtlSourceT *source, json_object *sndcardJ, AlsaPcmInfoT *snd) {
- json_object *sinkJ=NULL, *paramsJ = NULL;
+ json_object *sinkJ = NULL, *paramsJ = NULL;
int error;
- error = wrap_json_unpack(sndcardJ, "{ss,s?s,s?s,s?i,s?i,s?i,so,s?o !}", "uid", &snd->uid, "devpath", &snd->devpath, "cardid", &snd->cardid
- , "cardidx", &snd->cardidx, "device", &snd->device, "subdev", &snd->subdev, "sink", &sinkJ, "params", &paramsJ);
+ error = wrap_json_unpack(sndcardJ, "{ss,s?s,s?s,s?i,s?i,s?i,so,s?o !}"
+ , "uid", &snd->uid
+ , "devpath", &snd->devpath
+ , "cardid", &snd->cardid
+ , "cardidx", &snd->cardidx
+ , "device", &snd->device
+ , "subdev", &snd->subdev
+ , "sink", &sinkJ
+ , "params", &paramsJ
+ );
if (error || !snd->uid || !sinkJ || (!snd->devpath && !snd->cardid && snd->cardidx)) {
AFB_ApiNotice(source->api, "ProcessOneSndCard missing 'uid|path|cardid|cardidx|channels|device|subdev|numid|params' devin=%s", json_object_get_string(sndcardJ));
goto OnErrorExit;
@@ -106,10 +114,10 @@ STATIC int ProcessOneSndCard(CtlSourceT *source, json_object *sndcardJ, AlsaPcmI
goto OnErrorExit;
}
} else {
- snd->params.rate= ALSA_DEFAULT_PCM_RATE;
- snd->params.access= SND_PCM_ACCESS_RW_INTERLEAVED;
- snd->params.format=SND_PCM_FORMAT_S16_LE;
- snd->params.channels=2;
+ snd->params.rate = ALSA_DEFAULT_PCM_RATE;
+ snd->params.access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ snd->params.format = SND_PCM_FORMAT_S16_LE;
+ snd->params.channels = 2;
}
// check snd card is accessible
@@ -157,54 +165,54 @@ OnErrorExit:
return -1;
}
-CTLP_LUA2C(snd_cards, source, argsJ, responseJ) {
- AlsaPcmInfoT *sndcards;
-
+PUBLIC int SndBackend(CtlSourceT *source, json_object *argsJ) {
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
int error;
size_t count;
+ assert(mixerHandle);
+
+ if (mixerHandle->backend) {
+ AFB_ApiError(source->api, "SndBackend: mixer=%s backend already declared %s", mixerHandle->uid, json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
switch (json_object_get_type(argsJ)) {
case json_type_object:
count = 1;
- sndcards = calloc(count + 1, sizeof (AlsaPcmInfoT));
- error = ProcessOneSndCard(source, argsJ, &sndcards[0]);
+ mixerHandle->backend = calloc(count + 1, sizeof (AlsaPcmInfoT));
+ error = ProcessOneSndCard(source, argsJ, &mixerHandle->backend[0]);
if (error) goto OnErrorExit;
break;
case json_type_array:
count = json_object_array_length(argsJ);
- sndcards = calloc(count + 1, sizeof (AlsaPcmInfoT));
+ mixerHandle->backend = calloc(count + 1, sizeof (AlsaPcmInfoT));
for (int idx = 0; idx < count; idx++) {
json_object *sndcardJ = json_object_array_get_idx(argsJ, idx);
- error = ProcessOneSndCard(source, sndcardJ, &sndcards[idx]);
+ error = ProcessOneSndCard(source, sndcardJ, &mixerHandle->backend[idx]);
if (error) goto OnErrorExit;
}
break;
default:
- AFB_ApiError(source->api, "L2C:sndcards: invalid argsJ= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndBackend: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
- // register Sound card and multi when needed
- Softmixer->sndcardCtl = sndcards;
if (count == 1) {
-
// only one sound card we multi would be useless
- Softmixer->multiPcm = &sndcards[0];
+ mixerHandle->multiPcm = &mixerHandle->backend[0];
} else {
- AlsaPcmInfoT *pcmMulti;
-
+
// instantiate an alsa multi plugin
- pcmMulti = AlsaCreateMulti(source, "PcmMulti", 0);
- if (!pcmMulti) goto OnErrorExit;
+ mixerHandle->multiPcm = AlsaCreateMulti(source, "PcmMulti", 0);
+ if (!mixerHandle->multiPcm) goto OnErrorExit;
- Softmixer->multiPcm = pcmMulti;
}
-
return 0;
OnErrorExit:
- AFB_ApiNotice(source->api, "L2C:sndcards fail to process: %s", json_object_get_string(argsJ));
+ AFB_ApiNotice(source->api, "SndBackend mixer=%s fail to process: %s", mixerHandle->uid, json_object_get_string(argsJ));
return -1;
}
diff --git a/plugins/alsa/alsa-api-sndloops.c b/plugins/alsa/alsa-api-frontend.c
index cf7bf55..c01a88b 100644
--- a/plugins/alsa/alsa-api-sndloops.c
+++ b/plugins/alsa/alsa-api-frontend.c
@@ -126,7 +126,7 @@ STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT *
}
break;
default:
- AFB_ApiError(source->api, "L2C:ProcessOneLoop=%s invalid subdevs= %s", loop->uid, json_object_get_string(subdevsJ));
+ AFB_ApiError(source->api, "ProcessOneLoop=%s invalid subdevs= %s", loop->uid, json_object_get_string(subdevsJ));
goto OnErrorExit;
}
@@ -136,25 +136,42 @@ OnErrorExit:
return -1;
}
-CTLP_LUA2C(snd_loops, source, argsJ, responseJ) {
+PUBLIC int SndFrontend (CtlSourceT *source, json_object *argsJ) {
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
int error;
- AlsaSndLoopT *sndLoop = calloc(1, sizeof (AlsaSndLoopT));
-
- if (json_object_get_type(argsJ) != json_type_object) {
- AFB_ApiError(source->api, "L2C:sndloops: invalid object type= %s", json_object_get_string(argsJ));
+ assert (mixerHandle);
+
+ if (mixerHandle->loop) {
+ AFB_ApiError(source->api, "SndFrontend: mixer=%s SndFrontend already declared %s", mixerHandle->uid, json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ mixerHandle->loop= calloc(1, sizeof (AlsaSndLoopT));
+
+ // or syntax purpose array is accepted but frontend should have a single driver entry
+ json_type type= json_object_get_type(argsJ);
+ if (type == json_type_array) {
+ size_t count= json_object_array_length(argsJ);
+ if (count != 1) {
+ AFB_ApiError(source->api, "SndFrontend: mixer=%s frontend only support on input driver args=%s", mixerHandle->uid, json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+ argsJ= json_object_array_get_idx(argsJ,0);
+ }
+
+ type= json_object_get_type(argsJ);
+ if (type != json_type_object) {
+ AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object type= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
- error = ProcessOneLoop(source, argsJ, sndLoop);
+ error = ProcessOneLoop(source, argsJ, mixerHandle->loop);
if (error) {
- AFB_ApiError(source->api, "L2C:sndloops: invalid object= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
- // register routed into global softmixer handle
- Softmixer->loopCtl = sndLoop;
-
return 0;
OnErrorExit:
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c
new file mode 100644
index 0000000..f1619c2
--- /dev/null
+++ b/plugins/alsa/alsa-api-mixer.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2018 "IoT.bzh"
+ * Author Fulup Ar Foll <fulup@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE // needed for vasprintf
+
+#include "alsa-softmixer.h"
+#include <string.h>
+
+// Fulup need to be cleanup with new controller version
+extern Lua2cWrapperT Lua2cWrap;
+
+// API
+
+static void MixerApiVerbCB(AFB_ReqT request) {
+ json_object *responseJ, *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL;
+ // retrieve action handle from request and execute the request
+ json_object *argsJ = afb_request_json(request);
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) afb_request_get_vcbdata(request);
+ int error;
+ int close = 0;
+
+ CtlSourceT *source = alloca(sizeof (CtlSourceT));
+ source->uid = mixerHandle->uid;
+ source->api = request->dynapi;
+ source->request = request;
+ source->context = mixerHandle;
+
+ error = wrap_json_unpack(argsJ, "{s?b s?o,s?o,s?o,s?o !}"
+ , "close", &close
+ , "backend", &backendJ
+ , "frontend", &frontendJ
+ , "zones", &zonesJ
+ , "streams", &streamsJ
+ );
+ if (error) {
+ AFB_ReqFailF(request, "MixerApiVerbCB", "missing 'uid|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ // Free attached resources and free mixer
+ if (close) {
+ AFB_ReqFailF(request, "MixerApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ if (backendJ) {
+ error = SndBackend(source, backendJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (frontendJ) {
+ error = SndFrontend(source, frontendJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (zonesJ) {
+ error = SndZones(source, zonesJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (streamsJ) {
+ error = SndStreams(source, streamsJ, &responseJ);
+ if (error) goto OnErrorExit;
+ }
+
+
+ AFB_ReqSucess(request, responseJ, mixerHandle->uid);
+ return;
+
+OnErrorExit:
+ return;
+}
+
+CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) {
+ SoftMixerHandleT *mixerHandle = calloc(1, sizeof (SoftMixerHandleT));
+ json_object *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL;
+ int error;
+ assert(source->api);
+
+ if (json_object_get_type(argsJ) != json_type_object) {
+ AFB_ApiError(source->api, "_mixer_new_: invalid object type= %s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ error = wrap_json_unpack(argsJ, "{ss,s?s,s?o,s?o,s?o,s?o !}"
+ , "uid", &mixerHandle->uid
+ , "info", &mixerHandle->info
+ , "backend", &backendJ
+ , "frontend", &frontendJ
+ , "zones", &zonesJ
+ , "streams", &streamsJ);
+ if (error) {
+ AFB_ApiNotice(source->api, "_mixer_new_ missing 'uid|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ // make sure string do not get deleted
+ mixerHandle->uid = strdup(mixerHandle->uid);
+ if (mixerHandle->info)mixerHandle->info = strdup(mixerHandle->info);
+
+ // create mixer verb within API.
+ error = afb_dynapi_add_verb(source->api, mixerHandle->uid, mixerHandle->info, MixerApiVerbCB, mixerHandle, NULL, 0);
+ if (error) {
+ AFB_ApiError(source->api, "_mixer_new_ mixer=%s fail to register API verb", mixerHandle->uid);
+ return -1;
+ }
+
+ // make sure sub command get access to mixer handle
+ source->context = mixerHandle;
+
+ if (backendJ) {
+ error = SndBackend(source, backendJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (frontendJ) {
+ error = SndFrontend(source, frontendJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (zonesJ) {
+ error = SndZones(source, zonesJ);
+ if (error) goto OnErrorExit;
+ }
+
+ if (streamsJ) {
+ error = SndStreams(source, streamsJ, responseJ);
+ if (error) goto OnErrorExit;
+ }
+
+ return 0;
+
+OnErrorExit:
+ return -1;
+} \ No newline at end of file
diff --git a/plugins/alsa/alsa-api-sndstreams.c b/plugins/alsa/alsa-api-streams.c
index e55aeff..42d8ade 100644
--- a/plugins/alsa/alsa-api-sndstreams.c
+++ b/plugins/alsa/alsa-api-streams.c
@@ -29,6 +29,82 @@
// Fulup need to be cleanup with new controller version
extern Lua2cWrapperT Lua2cWrap;
+typedef struct {
+ const char* verb;
+ AlsaSndStreamT *streams;
+ SoftMixerHandleT *mixer;
+} apiHandleT;
+
+static void StreamApiVerbCB(AFB_ReqT request) {
+ int close=0, error=0, quiet=0;
+ long volume=-1, mute=-1;
+ json_object *responseJ, *argsJ= afb_request_json(request);
+ apiHandleT *handle = (apiHandleT*) afb_request_get_vcbdata(request);
+
+ CtlSourceT *source = alloca(sizeof (CtlSourceT));
+ source->uid = handle->verb;
+ source->api = request->dynapi;
+ source->request = NULL;
+ source->context = NULL;
+
+ error = wrap_json_unpack(argsJ, "{s?b s?b,s?b, s?i !}"
+ , "quiet", &quiet
+ , "close", &close
+ , "mute", &mute
+ , "volume", &volume
+ );
+ if (error) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Missing 'close|mute|volume|quiet' args=%s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ snd_ctl_t *ctlDev= AlsaCtlOpenCtl (source, handle->mixer->loop->cardid);
+ if (!ctlDev) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to open sndcard=%s", handle->mixer->loop->cardid);
+ goto OnErrorExit;
+ }
+
+ if (close) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
+ if (volume != -1) {
+ error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, volume);
+ if (error) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%ld", handle->streams->volume, volume);
+ goto OnErrorExit;
+ }
+ }
+
+ if (mute != -1) {
+ error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, !mute);
+ if (error) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%d", handle->streams->volume, !mute);
+ goto OnErrorExit;
+ }
+ }
+
+ // if not in quiet mode return effective selected control values
+ if (quiet) responseJ=NULL;
+ else {
+ error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->volume, &volume);
+ error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->mute, &mute);
+ if (error) {
+ AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to get stream numids volume=%ld mute=%ld",volume, mute);
+ goto OnErrorExit;
+ }
+ wrap_json_pack (&responseJ,"{volume:si, mute:sb}", volume, mute);
+ }
+
+ AFB_ReqSucess(request, responseJ, handle->verb);
+ return;
+
+OnErrorExit:
+ return;
+
+}
+
STATIC int ProcessOneStream(CtlSourceT *source, json_object *streamJ, AlsaSndStreamT *stream) {
int error;
json_object *paramsJ = NULL;
@@ -36,11 +112,17 @@ STATIC int ProcessOneStream(CtlSourceT *source, json_object *streamJ, AlsaSndStr
// Make sure default runs
stream->volume = ALSA_DEFAULT_PCM_VOLUME;
stream->mute = 0;
-
- error = wrap_json_unpack(streamJ, "{ss,ss,s?i,s?b,s?o !}", "uid", &stream->uid, "zone", &stream->zone, "volume", &stream->volume
- , "mute", stream->mute, "params", &paramsJ);
+ stream->info = NULL;
+
+ error = wrap_json_unpack(streamJ, "{ss,s?s,ss,s?i,s?b,s?o !}"
+ , "uid", &stream->uid
+ , "info", &stream->info
+ , "zone", &stream->zone
+ , "volume", &stream->volume
+ , "mute", stream->mute
+ , "params", &paramsJ);
if (error) {
- AFB_ApiNotice(source->api, "ProcessOneStream missing 'uid|zone|volume|rate|mute|params' stream=%s", json_object_get_string(streamJ));
+ AFB_ApiNotice(source->api, "ProcessOneStream missing 'uid|[info]|zone|[volume]|[mute]|[params]' stream=%s", json_object_get_string(streamJ));
goto OnErrorExit;
}
@@ -67,16 +149,19 @@ OnErrorExit:
return -1;
}
-CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
+PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **responseJ) {
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
AlsaSndStreamT *sndStream;
int error;
long value;
size_t count;
+ assert(mixerHandle);
+
// assert static/global softmixer handle get requited info
- AlsaSndLoopT *ctlLoop = Softmixer->loopCtl;
+ AlsaSndLoopT *ctlLoop = mixerHandle->loop;
if (!ctlLoop) {
- AFB_ApiError(source->api, "L2C:sndstreams: No Loop found [should register snd_loop first]");
+ AFB_ApiError(source->api, "SndStreams: mixer=%s No Loop found [should register snd_loop first]", mixerHandle->uid);
goto OnErrorExit;
}
@@ -86,7 +171,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
sndStream = calloc(count + 1, sizeof (AlsaSndStreamT));
error = ProcessOneStream(source, argsJ, &sndStream[0]);
if (error) {
- AFB_ApiError(source->api, "L2C:sndstreams: invalid stream= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndStreams: mixer=%s invalid stream= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
break;
@@ -98,13 +183,13 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
json_object *sndStreamJ = json_object_array_get_idx(argsJ, idx);
error = ProcessOneStream(source, sndStreamJ, &sndStream[idx]);
if (error) {
- AFB_ApiError(source->api, "sndstreams: invalid stream= %s", json_object_get_string(sndStreamJ));
+ AFB_ApiError(source->api, "sndstreams: mixer=%s invalid stream= %s", mixerHandle->uid, json_object_get_string(sndStreamJ));
goto OnErrorExit;
}
}
break;
default:
- AFB_ApiError(source->api, "L2C:sndstreams: invalid argsJ= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndStreams: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
@@ -116,10 +201,10 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
json_object *streamJ, *paramsJ;
// Search for a free loop capture device
- AFB_ApiNotice(source->api, "L2C:sndstreams stream=%s Start", (char*) sndStream[idx].uid);
+ AFB_ApiNotice(source->api, "SndStreams: mixer=%s stream=%s Start", mixerHandle->uid, (char*) sndStream[idx].uid);
ctlLoop->scount--;
if (ctlLoop->scount < 0) {
- AFB_ApiError(source->api, "L2C:sndstreams no more subdev avaliable in loopback=%s", ctlLoop->uid);
+ AFB_ApiError(source->api, "SndStreams: mixer=%s stream=%s no more subdev avaliable in loopback=%s", mixerHandle->uid, sndStream[idx].uid, ctlLoop->uid);
goto OnErrorExit;
}
@@ -144,7 +229,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
// Try to create/setup volume control.
snd_ctl_t* ctlDev = AlsaCrlFromPcm(source, captureDev->handle);
if (!ctlDev) {
- AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail attache sndcard", captureDev->cardid);
+ AFB_ApiError(source->api, "SndStreams: mixer=%s [pcm=%s] fail attache sndcard", mixerHandle->uid, captureDev->cardid);
goto OnErrorExit;
}
@@ -163,9 +248,9 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
// create stream and delay pcm openning until vol control is created
char volName[ALSA_CARDID_MAX_LEN];
snprintf(volName, sizeof (volName), "vol-%s", sndStream[idx].uid);
- AlsaPcmInfoT *streamPcm = AlsaCreateStream(source, &sndStream[idx], captureDev, volName, VOL_CONTROL_MAX, 0);
+ AlsaPcmInfoT *streamPcm = AlsaCreateSoftvol(source, &sndStream[idx], captureDev, volName, VOL_CONTROL_MAX, 0);
if (!streamPcm) {
- AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to create stream", sndStream[idx].uid);
+ AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to create stream", mixerHandle->uid, sndStream[idx].uid);
goto OnErrorExit;
}
@@ -179,14 +264,14 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
// snprintf(rateName, sizeof (rateName), "rate-%s", sndStream[idx].uid);
// AlsaPcmInfoT *ratePcm= AlsaCreateRate(source, rateName, streamPcm, 1);
// if (!ratePcm) {
- // AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to create rate converter", sndStream[idx].uid);
+ // AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to create rate converter", sndStream[idx].uid);
// goto OnErrorExit;
// }
// everything is not ready to open capture pcm
error = snd_pcm_open(&streamPcm->handle, sndStream[idx].uid, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (error) {
- AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to open capture", sndStream[idx].uid);
+ AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to open capture", mixerHandle->uid, sndStream[idx].uid);
goto OnErrorExit;
}
@@ -204,7 +289,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
// toggle pause/resume (should be done after pcm_start)
if ((error = snd_pcm_pause(captureDev->handle, !value)) < 0) {
- AFB_ApiError(source->api, "L2C:sndstreams [capture=%s] fail to pause error=%s", captureDev->cardid, snd_strerror(error));
+ AFB_ApiError(source->api, "SndStreams: mixer=%s [capture=%s] fail to pause error=%s", mixerHandle->uid, captureDev->cardid, snd_strerror(error));
goto OnErrorExit;
}
@@ -216,16 +301,36 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) {
error += wrap_json_pack(&streamJ, "{ss ss si si so}", "uid", streamPcm->uid, "alsa", playbackDev->cardid, "volid", volNumid, "runid", runNumid, "params", paramsJ);
error += json_object_array_add(*responseJ, streamJ);
if (error) {
- AFB_ApiError(source->api, "L2C:sndstreams:%s(stream) fail to prepare response", captureDev->cardid);
+ AFB_ApiError(source->api, "SndStreams: mixer=%s stream=%s fail to prepare response", mixerHandle->uid, captureDev->cardid);
goto OnErrorExit;
}
+ // create a dedicated verb for this stream compose of mixeruid/streamuid
+ apiHandleT *apiHandle = calloc(1, sizeof (apiHandleT));
+ char apiVerb[128];
+ error = snprintf(apiVerb, sizeof (apiVerb), "%s/%s", mixerHandle->uid, sndStream[idx].uid);
+ if (error == sizeof (apiVerb)) {
+ AFB_ApiError(source->api, "SndStreams mixer=%s fail to register Stream API too long %s/%s", mixerHandle->uid, mixerHandle->uid, sndStream[idx].uid);
+ return -1;
+ }
+
+ apiHandle->mixer = mixerHandle;
+ apiHandle->streams = &sndStream[idx];
+ apiHandle->verb = strdup(apiVerb);
+ error = afb_dynapi_add_verb(source->api, apiHandle->verb, sndStream[idx].info, StreamApiVerbCB, mixerHandle, NULL, 0);
+ if (error) {
+ AFB_ApiError(source->api, "SndStreams mixer=%s fail to register API verb=%s", mixerHandle->uid, apiHandle->verb);
+ return -1;
+ }
+
+ // free tempry resource
snd_ctl_close(ctlDev);
+
// Debug Alsa Config
//AlsaDumpElemConfig (source, "\n\nAlsa_Config\n------------\n", "pcm");
//AlsaDumpPcmInfo(source, "\n\nPcm_config\n-----------\n", streamPcm->handle);
- AFB_ApiNotice(source->api, "L2C:sndstreams:%s(stream) OK reponse=%s\n", streamPcm->uid, json_object_get_string(streamJ));
+ AFB_ApiNotice(source->api, "SndStreams: mixer=%s stream=%s OK reponse=%s\n", mixerHandle->uid, streamPcm->uid, json_object_get_string(streamJ));
}
return 0;
diff --git a/plugins/alsa/alsa-api-sndzones.c b/plugins/alsa/alsa-api-zones.c
index 7ca61ad..de834df 100644
--- a/plugins/alsa/alsa-api-sndzones.c
+++ b/plugins/alsa/alsa-api-zones.c
@@ -26,11 +26,11 @@ extern Lua2cWrapperT Lua2cWrap;
STATIC int ProcessOneChannel(CtlSourceT *source, const char* uid, json_object *channelJ, AlsaPcmChannels *channel) {
const char*channelUid;
-
+
int error = wrap_json_unpack(channelJ, "{ss,si,s?i !}", "target", &channelUid, "channel", &channel->port);
if (error) goto OnErrorExit;
-
- channel->uid=strdup(channelUid);
+
+ channel->uid = strdup(channelUid);
return 0;
OnErrorExit:
@@ -44,9 +44,13 @@ STATIC int ProcessOneZone(CtlSourceT *source, json_object *zoneJ, AlsaSndZoneT *
const char* streamType;
int error;
- error = wrap_json_unpack(zoneJ, "{ss,s?s,so !}", "uid", &zone->uid, "type", &streamType, "mapping", &mappingJ);
+ error = wrap_json_unpack(zoneJ, "{ss,s?s,so !}"
+ , "uid", &zone->uid
+ , "type", &streamType
+ , "mapping", &mappingJ
+ );
if (error) {
- AFB_ApiNotice(source->api, "ProcessOneone missing 'uid|type|mapping' zone=%s", json_object_get_string(zoneJ));
+ AFB_ApiNotice(source->api, "ProcessOneZone missing 'uid|type|mapping' zone=%s", json_object_get_string(zoneJ));
goto OnErrorExit;
}
@@ -59,9 +63,9 @@ STATIC int ProcessOneZone(CtlSourceT *source, json_object *zoneJ, AlsaSndZoneT *
goto OnErrorExit;
}
}
-
+
// make sure remain valid even when json object is removed
- zone->uid= strdup(zone->uid);
+ zone->uid = strdup(zone->uid);
switch (json_object_get_type(mappingJ)) {
case json_type_object:
@@ -90,55 +94,63 @@ OnErrorExit:
return -1;
}
-CTLP_LUA2C(snd_zones, source, argsJ, responseJ) {
- AlsaSndZoneT *sndZone;
+PUBLIC int SndZones(CtlSourceT *source, json_object *argsJ) {
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
+ AlsaSndZoneT *zones=NULL;
int error;
size_t count;
+ assert(mixerHandle);
+
+ if (mixerHandle->routes) {
+ AFB_ApiError(source->api, "SndZones: mixer=%s Zones already registered %s", mixerHandle->uid, json_object_get_string(argsJ));
+ goto OnErrorExit;
+ }
+
switch (json_object_get_type(argsJ)) {
case json_type_object:
count = 1;
- sndZone = calloc(count + 1, sizeof (AlsaSndZoneT));
- error = ProcessOneZone(source, argsJ, &sndZone[0]);
+ zones = calloc(count + 1, sizeof (AlsaSndZoneT));
+ error = ProcessOneZone(source, argsJ, &zones[0]);
if (error) {
- AFB_ApiError(source->api, "L2C:sndzones: invalid zone= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
break;
case json_type_array:
count = json_object_array_length(argsJ);
- sndZone = calloc(count + 1, sizeof (AlsaSndZoneT));
+ zones = calloc(count + 1, sizeof (AlsaSndZoneT));
for (int idx = 0; idx < count; idx++) {
json_object *sndZoneJ = json_object_array_get_idx(argsJ, idx);
- error = ProcessOneZone(source, sndZoneJ, &sndZone[idx]);
+ error = ProcessOneZone(source, sndZoneJ, &zones[idx]);
if (error) {
- AFB_ApiError(source->api, "L2C:sndzones: invalid zone= %s", json_object_get_string(sndZoneJ));
+ AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(sndZoneJ));
goto OnErrorExit;
}
}
break;
default:
- AFB_ApiError(source->api, "L2C:sndzones: invalid argsJ= %s", json_object_get_string(argsJ));
+ AFB_ApiError(source->api, "SndZones: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
// register routed into global softmixer handle
- Softmixer->zonePcms = calloc(count+1, sizeof (AlsaPcmInfoT*));
+ mixerHandle->routes= calloc(count + 1, sizeof (AlsaPcmInfoT*));
// instantiate one route PCM per zone with multi plugin as slave
- for (int idx = 0; sndZone[idx].uid != NULL; idx++) {
- Softmixer->zonePcms[idx] = AlsaCreateRoute(source, &sndZone[idx], 0);
- if (!Softmixer->zonePcms[idx]) {
- AFB_ApiNotice(source->api, "L2C:sndzones fail to create route zone=%s", sndZone[idx].uid);
+ 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;
}
}
- // do not need this handle anymore
- free (sndZone);
+ free (zones);
return 0;
OnErrorExit:
+ if (zones) free(zones);
return -1;
} \ No newline at end of file
diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c
index 9a0b844..f224f92 100644
--- a/plugins/alsa/alsa-core-ctl.c
+++ b/plugins/alsa/alsa-core-ctl.c
@@ -170,6 +170,7 @@ OnErrorExit:
return NULL;
}
+
STATIC int CtlElemIdGetNumid(AFB_ApiT api, snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, int *numid) {
snd_ctl_elem_info_t *elemInfo;
diff --git a/plugins/alsa/alsa-plug-multi.c b/plugins/alsa/alsa-plug-multi.c
index 3e82e1e..0dd417d 100644
--- a/plugins/alsa/alsa-plug-multi.c
+++ b/plugins/alsa/alsa-plug-multi.c
@@ -23,15 +23,17 @@
ALSA_PLUG_PROTO(multi);
PUBLIC AlsaPcmInfoT* AlsaCreateMulti(CtlSourceT *source, const char *pcmUid, int open) {
-
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
snd_config_t *multiConfig, *elemConfig, *slavesConfig, *slaveConfig, *bindingsConfig, *bindingConfig, *pcmConfig;
int error = 0, channelIdx=0;
AlsaPcmInfoT *pcmPlug = calloc(1, sizeof (AlsaPcmInfoT));
pcmPlug->uid = pcmUid;
pcmPlug->cardid = pcmUid;
- AlsaPcmInfoT* pcmSlaves=Softmixer->sndcardCtl;
- if (!Softmixer->sndcardCtl) {
+ assert(mixerHandle);
+
+ AlsaPcmInfoT* pcmSlaves=mixerHandle->backend;
+ if (!pcmSlaves) {
AFB_ApiError(source->api, "AlsaCreateMulti: No Sound Card find [should register snd_cards first]");
goto OnErrorExit;
}
diff --git a/plugins/alsa/alsa-plug-route.c b/plugins/alsa/alsa-plug-route.c
index 8fa5de8..d2ca223 100644
--- a/plugins/alsa/alsa-plug-route.c
+++ b/plugins/alsa/alsa-plug-route.c
@@ -48,17 +48,20 @@ OnErrorExit:
}
PUBLIC AlsaPcmInfoT* AlsaCreateRoute(CtlSourceT *source, AlsaSndZoneT *zone, int open) {
-
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
snd_config_t *routeConfig, *elemConfig, *slaveConfig, *tableConfig, *pcmConfig;
int error = 0;
AlsaPcmInfoT *pcmPlug = calloc(1, sizeof (AlsaPcmInfoT));
pcmPlug->uid = zone->uid;
pcmPlug->cardid = zone->uid;
+
+ assert(mixerHandle);
- AlsaPcmInfoT *pcmBackend = Softmixer->sndcardCtl;
- AlsaPcmInfoT* pcmSlave=Softmixer->multiPcm;
+ AlsaPcmInfoT *pcmBackend = mixerHandle->backend;
+ AlsaPcmInfoT* pcmSlave=mixerHandle->multiPcm;
if (!pcmBackend || !pcmSlave) {
- AFB_ApiError(source->api, "AlsaCreateRoute:zone(%s)(zone) No Sound Card Ctl find [should register snd_cards first]", zone->uid);
+ AFB_ApiError(source->api, "AlsaCreateRoute: mixer=%s zone(%s)(zone) No Sound Card Ctl find [should register snd_cards first]"
+ , mixerHandle->uid, zone->uid);
goto OnErrorExit;
}
diff --git a/plugins/alsa/alsa-plug-vol.c b/plugins/alsa/alsa-plug-vol.c
index dc600f9..09bc51a 100644
--- a/plugins/alsa/alsa-plug-vol.c
+++ b/plugins/alsa/alsa-plug-vol.c
@@ -36,30 +36,32 @@ STATIC AlsaPcmInfoT* SlaveZoneByUid(CtlSourceT *source, AlsaPcmInfoT **pcmZones
return NULL;
}
-PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open) {
-
+PUBLIC AlsaPcmInfoT* AlsaCreateSoftvol(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open) {
+ SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
snd_config_t *streamConfig, *elemConfig, *slaveConfig, *controlConfig,*pcmConfig;
int error = 0;
AlsaPcmInfoT *pcmPlug= calloc(1,sizeof(AlsaPcmInfoT));
+ assert (mixerHandle);
+
// assert static/global softmixer handle get requited info
- AlsaSndLoopT *ctlLoop = Softmixer->loopCtl;
+ AlsaSndLoopT *ctlLoop = mixerHandle->loop;
if (!ctlLoop) {
- AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) No Loop found [should register snd_loop first]",stream->uid);
+ AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) No Loop found [should register snd_loop first]",stream->uid);
goto OnErrorExit;
}
// assert static/global softmixer handle get requited info
- AlsaPcmInfoT **pcmZones = Softmixer->zonePcms;
+ AlsaPcmInfoT **pcmZones = mixerHandle->routes;
if (!pcmZones) {
- AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) No Zone found [should register snd_zones first]", stream->uid);
+ AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) No Zone found [should register snd_zones first]", stream->uid);
goto OnErrorExit;
}
// search for target zone uid
AlsaPcmInfoT *pcmSlave= SlaveZoneByUid (source, pcmZones, stream->zone);
if (!pcmSlave || !pcmSlave->uid) {
- AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to find Zone=%s", stream->uid, stream->zone);
+ AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to find Zone=%s", stream->uid, stream->zone);
goto OnErrorExit;
}
@@ -102,24 +104,24 @@ PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream
if (open) error = _snd_pcm_softvol_open(&pcmPlug->handle, stream->uid, snd_config, streamConfig, SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK);
if (error) {
- AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to create Plug=%s Slave=%s error=%s", stream->uid, pcmPlug->cardid, pcmSlave->cardid, snd_strerror(error));
+ AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to create Plug=%s Slave=%s error=%s", stream->uid, pcmPlug->cardid, pcmSlave->cardid, snd_strerror(error));
goto OnErrorExit;
}
error += snd_config_search(snd_config, "pcm", &pcmConfig);
error += snd_config_add(pcmConfig, streamConfig);
if (error) {
- AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to add config", stream->uid);
+ AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to add config", stream->uid);
goto OnErrorExit;
}
// Debug config & pcm
//AlsaDumpCtlConfig (source, "plug-stream", streamConfig, 1);
- AFB_ApiNotice(source->api, "AlsaCreateStream:%s(stream) done\n", stream->uid);
+ AFB_ApiNotice(source->api, "AlsaCreateSoftvol:%s(stream) done\n", stream->uid);
return pcmPlug;
OnErrorExit:
AlsaDumpCtlConfig(source, "plug-stream", streamConfig, 1);
- AFB_ApiNotice(source->api, "AlsaCreateStream:%s(stream) OnErrorExit\n", stream->uid);
+ AFB_ApiNotice(source->api, "AlsaCreateSoftvol:%s(stream) OnErrorExit\n", stream->uid);
return NULL;
} \ No newline at end of file
diff --git a/plugins/alsa/alsa-softmixer.c b/plugins/alsa/alsa-softmixer.c
index 033e87b..4528087 100644
--- a/plugins/alsa/alsa-softmixer.c
+++ b/plugins/alsa/alsa-softmixer.c
@@ -24,12 +24,9 @@
CTLP_LUA_REGISTER("alsa-softmixer")
-SoftMixerHandleT *Softmixer;
-
// Call at initialisation time
CTLP_ONLOAD(plugin, callbacks) {
- AFB_ApiDebug(plugin->api, "SoftMixer plugin: uid='%s' 'info='%s'", plugin->uid, plugin->info);
- Softmixer = calloc(1, sizeof(SoftMixerHandleT));
+ AFB_ApiDebug(plugin->api, "SoftMixer Plugin Registered: uid='%s' 'info='%s'", plugin->uid, plugin->info);
return NULL;
}
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index e2c9370..7146e78 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -24,13 +24,14 @@
#include <afb/afb-binding.h>
#include <systemd/sd-event.h>
#include <json-c/json_object.h>
-#include <stdio.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <alsa/asoundlib.h>
#include "ctl-plugin.h"
#include "wrap-json.h"
-#include <alsa/asoundlib.h>
#ifndef PUBLIC
#define PUBLIC
@@ -104,10 +105,9 @@ typedef struct {
AlsaPcmInfoT *subdevs;
} AlsaSndLoopT;
-
-
typedef struct {
const char *uid;
+ const char *info;
const char *zone;
int volume;
int mute;
@@ -116,23 +116,20 @@ typedef struct {
} AlsaSndStreamT;
typedef struct {
- AlsaSndLoopT *loopCtl;
- AlsaPcmInfoT *sndcardCtl;
+ const char *uid;
+ const char *info;
+ AlsaSndLoopT *loop;
+ AlsaPcmInfoT *backend;
AlsaPcmInfoT *multiPcm;
- AlsaPcmInfoT **zonePcms;
+ AlsaPcmInfoT **routes;
} SoftMixerHandleT;
-extern SoftMixerHandleT *Softmixer;
-
// alsa-utils-bypath.c
PUBLIC snd_ctl_card_info_t* AlsaByPathInfo(CtlSourceT *source, const char *control);
PUBLIC AlsaPcmInfoT* AlsaByPathOpenPcm(CtlSourceT *source, AlsaPcmInfoT *dev, snd_pcm_stream_t direction);
PUBLIC snd_ctl_t *AlsaByPathOpenCtl(CtlSourceT *source, AlsaPcmInfoT *dev);
PUBLIC int AlsaByPathDevid(CtlSourceT *source, AlsaPcmInfoT *dev);
-// alsa-api-*.c
-PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params);
-
// alsa-utils-dump.c
PUBLIC void AlsaDumpFormats(CtlSourceT *source, snd_pcm_t *pcmHandle);
PUBLIC char *AlsaDumpPcmUid(snd_pcm_t *pcmHandle, char *buffer, size_t len);
@@ -168,7 +165,14 @@ PUBLIC int AlsaPcmCopy(CtlSourceT *source, AlsaPcmInfoT *pcmIn, AlsaPcmInfoT *pc
PUBLIC AlsaPcmInfoT* AlsaCreateDmix(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave, int open);
PUBLIC AlsaPcmInfoT* AlsaCreateMulti(CtlSourceT *source, const char *pcmName, int open);
PUBLIC AlsaPcmInfoT* AlsaCreateRoute(CtlSourceT *source, AlsaSndZoneT *zone, int open);
-PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open);
+PUBLIC AlsaPcmInfoT* AlsaCreateSoftvol(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open);
PUBLIC AlsaPcmInfoT* AlsaCreateRate(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave, int open);
+// alsa-api-*
+PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params);
+PUBLIC int SndFrontend (CtlSourceT *source, json_object *argsJ);
+PUBLIC int SndBackend (CtlSourceT *source, json_object *argsJ);
+PUBLIC int SndZones (CtlSourceT *source, json_object *argsJ);
+PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **responseJ);
+
#endif \ No newline at end of file