summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2018-05-17 23:52:28 +0200
committerFulup Ar Foll <fulup@iot.bzh>2018-05-17 23:52:28 +0200
commite4d8efb814307bfeec227f72c77a4cf0bdf135bf (patch)
tree0f2d60dd85b926c44765f721583996178c5e124a
parent253df14bd84f535a54f4d12c95399899e1343c20 (diff)
Implemented sub API for stream with volume/pause/toggle/...
-rw-r--r--conf.d/cmake/config.cmake2
-rw-r--r--conf.d/project/htdocs/index.html5
-rw-r--r--plugins/alsa/alsa-api-frontend.c21
-rw-r--r--plugins/alsa/alsa-api-mixer.c60
-rw-r--r--plugins/alsa/alsa-api-streams.c38
-rw-r--r--plugins/alsa/alsa-core-ctl.c2
-rw-r--r--plugins/alsa/alsa-softmixer.h1
7 files changed, 104 insertions, 25 deletions
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
index 5f5bc23..536d4b5 100644
--- a/conf.d/cmake/config.cmake
+++ b/conf.d/cmake/config.cmake
@@ -199,7 +199,7 @@ set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
# Print a helper message when every thing is finished
# ----------------------------------------------------
-set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --name ${PROJECT_NAME}-afbd --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR} --binding=package/lib/softmixer-binding.so --roothttp=package/htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
+set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --name ${PROJECT_NAME}-afbd --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR} --ldpath=/dev/null --binding=package/lib/softmixer-binding.so --roothttp=package/htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
# Optional schema validator about now only XML, LUA and JSON
diff --git a/conf.d/project/htdocs/index.html b/conf.d/project/htdocs/index.html
index 600f7e0..22ec2a2 100644
--- a/conf.d/project/htdocs/index.html
+++ b/conf.d/project/htdocs/index.html
@@ -8,14 +8,15 @@
<body onload="init('hal_registry','alsacore', 'hallist')">
- <h1>Simple Control Test</h1>
+ <h1>Simple Mixer Test</h1>
<button id="connected" onclick="init()">Binder WS Fail</button>
<button id="mnitoring" onclick="window.open('/monitoring/monitor.html','_monitor_ctl')">Debug/Monitoring</a></button>
<br><br>
<h2>V3 API CALL</h2>
<ol>
- <li><button onclick="callbinder('softmixer','mixer-config');">Mixer Config</button></li>
+ <li><button onclick="callbinder('softmixer','simple_mixer',{list:{streams:true}});">Streams List</button></li>
+ <li><button onclick="callbinder('softmixer','simple_mixer/multimedia',{toggle: true});">Stream Multimedia pause/resume</button></li>
</ol>
<div id="main" style="visibility:hidden">
diff --git a/plugins/alsa/alsa-api-frontend.c b/plugins/alsa/alsa-api-frontend.c
index c01a88b..91ce63f 100644
--- a/plugins/alsa/alsa-api-frontend.c
+++ b/plugins/alsa/alsa-api-frontend.c
@@ -92,10 +92,23 @@ STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT *
loopDefParams->sampleSize=0;
}
- // make sure useful information will not be removed
- loop->uid = strdup(loop->uid);
- if (loop->cardid) loop->cardid = strdup(loop->cardid);
- if (loop->devpath) loop->cardid = strdup(loop->devpath);
+ // Fake a sound card to check if loop is a valid Alsa snd driver
+ AlsaPcmInfoT sndLoop;
+ sndLoop.uid = loop->uid;
+ sndLoop.devpath = loop->devpath;
+ sndLoop.cardid = loop->cardid;
+ sndLoop.device = 0;
+ sndLoop.subdev = 0;
+ error = AlsaByPathDevid(source, &sndLoop);
+ if (error) {
+ AFB_ApiError(source->api, "ProcessOneLoop: loop=%s not found config=%s", loop->uid, json_object_get_string(loopJ));
+ goto OnErrorExit;
+ }
+ loop->uid= sndLoop.uid;
+ loop->devpath= sndLoop.devpath;
+ loop->cardid=sndLoop.cardid;
+ loop->cardidx=sndLoop.cardidx;
+
// Default devices is payback=0 capture=1
if (!devicesJ) {
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c
index f1619c2..31854b0 100644
--- a/plugins/alsa/alsa-api-mixer.c
+++ b/plugins/alsa/alsa-api-mixer.c
@@ -27,9 +27,11 @@ extern Lua2cWrapperT Lua2cWrap;
// API
static void MixerApiVerbCB(AFB_ReqT request) {
- json_object *responseJ, *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL;
+ json_object *valueJ, *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL, *listJ = NULL;
// retrieve action handle from request and execute the request
json_object *argsJ = afb_request_json(request);
+ json_object *responseJ = json_object_new_object();
+
SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) afb_request_get_vcbdata(request);
int error;
int close = 0;
@@ -40,24 +42,74 @@ static void MixerApiVerbCB(AFB_ReqT request) {
source->request = request;
source->context = mixerHandle;
- error = wrap_json_unpack(argsJ, "{s?b s?o,s?o,s?o,s?o !}"
+ error = wrap_json_unpack(argsJ, "{s?b,s?o,s?o,s?o,s?o,s?o !}"
, "close", &close
+ , "list", &listJ
, "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));
+ 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, "MixerApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ));
+ AFB_ReqFailF(request, "not implemented", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ));
goto OnErrorExit;
}
+ if (listJ) {
+ int streams = 0, quiet = 0, backend = 0, frontend = 0, zones = 0;
+
+ error = wrap_json_unpack(listJ, "{s?b,s?b,s?b,s?b,s?b !}"
+ , "quiet", &quiet
+ , "streams", &streams
+ , "backend", &backend
+ , "frontend", &frontend
+ , "zones", &zones
+ );
+ if (error) {
+ 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();
+
+ AlsaSndStreamT *streams = mixerHandle->streams;
+ for (int idx = 0; streams[idx].uid; idx++) {
+ if (quiet) {
+ json_object_array_add(streamsJ, json_object_new_string(streams[idx].uid));
+ } else {
+ json_object *numidJ;
+ wrap_json_pack(&numidJ, "{si,si}"
+ , "volume", streams[idx].volume
+ , "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));
+ }
+
+ }
+ 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;
+ }
+
+ AFB_ReqSucess(request, responseJ, NULL);
+ return;
+ }
+
if (backendJ) {
error = SndBackend(source, backendJ);
if (error) goto OnErrorExit;
diff --git a/plugins/alsa/alsa-api-streams.c b/plugins/alsa/alsa-api-streams.c
index 42d8ade..bc5008b 100644
--- a/plugins/alsa/alsa-api-streams.c
+++ b/plugins/alsa/alsa-api-streams.c
@@ -36,8 +36,8 @@ typedef struct {
} apiHandleT;
static void StreamApiVerbCB(AFB_ReqT request) {
- int close=0, error=0, quiet=0;
- long volume=-1, mute=-1;
+ int error, doClose=0, doQuiet=0, doToggle=0, doMute=-1;
+ long mute, volume=-1;
json_object *responseJ, *argsJ= afb_request_json(request);
apiHandleT *handle = (apiHandleT*) afb_request_get_vcbdata(request);
@@ -47,10 +47,11 @@ static void StreamApiVerbCB(AFB_ReqT request) {
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
+ error = wrap_json_unpack(argsJ, "{s?b s?b,s?b,s?b,s?i !}"
+ , "quiet", &doQuiet
+ , "close", &doClose
+ , "mute", &doMute
+ , "toggle", &doToggle
, "volume", &volume
);
if (error) {
@@ -64,11 +65,16 @@ static void StreamApiVerbCB(AFB_ReqT request) {
goto OnErrorExit;
}
- if (close) {
+ if (doClose) {
AFB_ReqFailF(request, "StreamApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ));
goto OnErrorExit;
}
+ if (doToggle) {
+ error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->mute, &mute);
+ error+= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->mute, !mute);
+ }
+
if (volume != -1) {
error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, volume);
if (error) {
@@ -77,8 +83,8 @@ static void StreamApiVerbCB(AFB_ReqT request) {
}
}
- if (mute != -1) {
- error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, !mute);
+ if (doMute != -1) {
+ error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->mute, !mute);
if (error) {
AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%d", handle->streams->volume, !mute);
goto OnErrorExit;
@@ -86,7 +92,7 @@ static void StreamApiVerbCB(AFB_ReqT request) {
}
// if not in quiet mode return effective selected control values
- if (quiet) responseJ=NULL;
+ if (doQuiet) responseJ=NULL;
else {
error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->volume, &volume);
error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->mute, &mute);
@@ -94,13 +100,15 @@ static void StreamApiVerbCB(AFB_ReqT request) {
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);
+ wrap_json_pack (&responseJ,"{si,sb}", "volume",volume, "mute",!mute);
}
+ snd_ctl_close (ctlDev);
AFB_ReqSucess(request, responseJ, handle->verb);
return;
OnErrorExit:
+ if(ctlDev) snd_ctl_close (ctlDev);
return;
}
@@ -317,14 +325,16 @@ PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **resp
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);
+ error = afb_dynapi_add_verb(source->api, apiHandle->verb, sndStream[idx].info, StreamApiVerbCB, apiHandle, 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
+ // free temporary resources
snd_ctl_close(ctlDev);
+ sndStream[idx].volume= volNumid;
+ sndStream[idx].mute= runNumid;
// Debug Alsa Config
//AlsaDumpElemConfig (source, "\n\nAlsa_Config\n------------\n", "pcm");
@@ -333,6 +343,8 @@ PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **resp
AFB_ApiNotice(source->api, "SndStreams: mixer=%s stream=%s OK reponse=%s\n", mixerHandle->uid, streamPcm->uid, json_object_get_string(streamJ));
}
+ // save handle for further use
+ mixerHandle->streams = sndStream;
return 0;
OnErrorExit:
diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c
index f224f92..1749679 100644
--- a/plugins/alsa/alsa-core-ctl.c
+++ b/plugins/alsa/alsa-core-ctl.c
@@ -156,7 +156,7 @@ PUBLIC snd_ctl_t *AlsaCtlOpenCtl(CtlSourceT *source, const char *cardid) {
int error;
snd_ctl_t *ctlDev;
- if (cardid) goto OnErrorExit;
+ if (!cardid) goto OnErrorExit;
if ((error = snd_ctl_open(&ctlDev, cardid, SND_CTL_READONLY)) < 0) {
cardid = "Not Defined";
diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h
index 7146e78..f5a82f0 100644
--- a/plugins/alsa/alsa-softmixer.h
+++ b/plugins/alsa/alsa-softmixer.h
@@ -122,6 +122,7 @@ typedef struct {
AlsaPcmInfoT *backend;
AlsaPcmInfoT *multiPcm;
AlsaPcmInfoT **routes;
+ AlsaSndStreamT *streams;
} SoftMixerHandleT;
// alsa-utils-bypath.c