aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alsa/core-binding/AlsaAfbBinding.c4
-rw-r--r--Alsa/core-binding/AlsaLibMapping.c32
-rw-r--r--Alsa/core-binding/AlsaLibMapping.h3
-rw-r--r--Alsa/core-binding/README.md2
-rw-r--r--AudioLogic/AudioLogicBinding.c (renamed from BusinessLogic/AudioLogicBinding.c)26
-rw-r--r--AudioLogic/AudioLogicLib.c (renamed from BusinessLogic/AudioLogicMapping.c)13
-rw-r--r--AudioLogic/AudioLogicLib.h (renamed from BusinessLogic/AudioLogicMapping.h)4
-rw-r--r--AudioLogic/CMakeLists.txt (renamed from BusinessLogic/CMakeLists.txt)2
-rw-r--r--AudioLogic/README.md (renamed from BusinessLogic/README.md)4
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md31
-rw-r--r--htdocs/CMakeLists.txt25
-rw-r--r--htdocs/alsa-core.html3
-rw-r--r--htdocs/audio-logic.html40
-rw-r--r--htdocs/index.html1
15 files changed, 142 insertions, 53 deletions
diff --git a/Alsa/core-binding/AlsaAfbBinding.c b/Alsa/core-binding/AlsaAfbBinding.c
index 012b6c8..95d5e8d 100644
--- a/Alsa/core-binding/AlsaAfbBinding.c
+++ b/Alsa/core-binding/AlsaAfbBinding.c
@@ -30,7 +30,7 @@
#include "AlsaLibMapping.h"
#include <afb/afb-service-itf.h>
-PUBLIC const struct afb_binding_interface *binderIface;
+PUBLIC const struct afb_binding_interface *afbIface;
static void localping(struct afb_req request) {
json_object *query = afb_req_json(request);
@@ -71,7 +71,7 @@ extern int afbBindingV1ServiceInit(struct afb_service service) {
* activation function for registering the binding called by afb-daemon
*/
const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) {
- binderIface= itf;
+ afbIface= itf;
return &binding_description; /* returns the description of the binding */
}
diff --git a/Alsa/core-binding/AlsaLibMapping.c b/Alsa/core-binding/AlsaLibMapping.c
index 797f9ba..59ce8ff 100644
--- a/Alsa/core-binding/AlsaLibMapping.c
+++ b/Alsa/core-binding/AlsaLibMapping.c
@@ -270,13 +270,13 @@ STATIC json_object* alsaCardProbe (const char *rqtSndId) {
snd_ctl_card_info_alloca(&cardinfo);
if ((err = snd_ctl_open(&handle, rqtSndId, 0)) < 0) {
- INFO (binderIface, "SndCard [%s] Not Found", rqtSndId);
+ INFO (afbIface, "SndCard [%s] Not Found", rqtSndId);
return NULL;
}
if ((err = snd_ctl_card_info(handle, cardinfo)) < 0) {
snd_ctl_close(handle);
- WARNING (binderIface, "SndCard [%s] info error: %s", rqtSndId, snd_strerror(err));
+ WARNING (afbIface, "SndCard [%s] info error: %s", rqtSndId, snd_strerror(err));
return NULL;
}
@@ -288,13 +288,13 @@ STATIC json_object* alsaCardProbe (const char *rqtSndId) {
name = snd_ctl_card_info_get_name(cardinfo);
json_object_object_add (sndcard, "name", json_object_new_string (name));
- if (binderIface->verbosity > 1) {
+ if (afbIface->verbosity > 1) {
json_object_object_add (sndcard, "devid", json_object_new_string(rqtSndId));
driver= snd_ctl_card_info_get_driver(cardinfo);
json_object_object_add (sndcard, "driver" , json_object_new_string(driver));
info = strdup(snd_ctl_card_info_get_longname (cardinfo));
json_object_object_add (sndcard, "info" , json_object_new_string (info));
- INFO (binderIface, "AJG: Soundcard Devid=%-5s Cardid=%-7s Name=%s\n", rqtSndId, devid, info);
+ INFO (afbIface, "AJG: Soundcard Devid=%-5s Cardid=%-7s Name=%s\n", rqtSndId, devid, info);
}
// free card handle and return info
@@ -565,6 +565,7 @@ PUBLIC void alsaGetCtl(struct afb_req request) {
return;
}
+// This routine is called when ALSA event are fired
STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* userData) {
int err;
evtHandleT *evtHandle = (evtHandleT*)userData;
@@ -579,7 +580,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void*
int index;
if ((revents & EPOLLHUP) != 0) {
- NOTICE (binderIface, "SndCtl hanghup [car disconnected]");
+ NOTICE (afbIface, "SndCtl hanghup [car disconnected]");
goto ExitOnSucess;
}
@@ -604,7 +605,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void*
devname= snd_ctl_event_elem_get_name(ctlEvent);
index = snd_ctl_event_elem_get_index(ctlEvent);
- fprintf(stdout, "*** Debug (%i,%i,%i,%i,%s,%i)", numid, iface, device, subdev, devname, index);
+ DEBUG(afbIface, "sndCtlEventCB: (%i,%i,%i,%i,%s,%i)", numid, iface, device, subdev, devname, index);
// proxy ctlevent as a binder event
ctlEventJson = json_object_new_object();
@@ -617,13 +618,12 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void*
afb_event_push(evtHandle->afbevt, ctlEventJson);
}
-
- ExitOnError:
- WARNING (binderIface, "sndCtlEventCB: ignored unsupported event type");
- return (0);
-
ExitOnSucess:
return 0;
+
+ ExitOnError:
+ WARNING (afbIface, "sndCtlEventCB: ignored unsupported event type");
+ return (0);
}
// Loop on every potential Sound card and register active one
@@ -688,7 +688,7 @@ PUBLIC void alsaSubCtl (struct afb_req request) {
snd_ctl_poll_descriptors(evtHandle->ctl, &evtHandle->pfds, 1);
// register sound event to binder main loop
- err = sd_event_add_io(afb_daemon_get_event_loop(binderIface->daemon), &evtHandle->src, evtHandle->pfds.fd, EPOLLIN, sndCtlEventCB, evtHandle);
+ err = sd_event_add_io(afb_daemon_get_event_loop(afbIface->daemon), &evtHandle->src, evtHandle->pfds.fd, EPOLLIN, sndCtlEventCB, evtHandle);
if (err < 0) {
afb_req_fail_f (request, "register-mainloop", "Cannot hook events to mainloop devid=%s err=%d", devid, err);
snd_ctl_close(ctlHandle);
@@ -696,13 +696,13 @@ PUBLIC void alsaSubCtl (struct afb_req request) {
}
// create binder event attached to devid name
- evtHandle->afbevt = afb_daemon_make_event (binderIface->daemon, devid);
+ evtHandle->afbevt = afb_daemon_make_event (afbIface->daemon, devid);
if (!afb_event_is_valid (evtHandle->afbevt)) {
afb_req_fail_f (request, "register-event", "Cannot register new binder event name=%s", devid);
snd_ctl_close(ctlHandle);
goto ExitOnError;
}
-
+
// everything looks OK let's move forward
idx=idxFree;
}
@@ -714,6 +714,10 @@ PUBLIC void alsaSubCtl (struct afb_req request) {
goto ExitOnError;
}
+ json_object *ctlEventJson = json_object_new_object();
+ json_object_object_add(ctlEventJson, "test",json_object_new_string ("done"));
+ afb_event_push(evtHandle->afbevt, ctlEventJson );
+
// increase usage count and return success
sndHandles[idx].ucount ++;
afb_req_success(request, NULL, NULL);
diff --git a/Alsa/core-binding/AlsaLibMapping.h b/Alsa/core-binding/AlsaLibMapping.h
index 9e23051..5fc1b98 100644
--- a/Alsa/core-binding/AlsaLibMapping.h
+++ b/Alsa/core-binding/AlsaLibMapping.h
@@ -37,8 +37,7 @@ typedef int BOOL;
// import from AlsaAfbBinding
-extern const struct afb_binding_interface *binderIface;
-extern struct sd_event *afb_common_get_event_loop();
+extern const struct afb_binding_interface *afbIface;
// import from AlsaAfbMapping
PUBLIC void alsaGetInfo (struct afb_req request);
diff --git a/Alsa/core-binding/README.md b/Alsa/core-binding/README.md
index 4cce341..5f0c562 100644
--- a/Alsa/core-binding/README.md
+++ b/Alsa/core-binding/README.md
@@ -3,7 +3,7 @@
------------------------------------------------------------------------
Testing: (from project directory bindings)
- * start binder: ~/opt/bin/afb-daemon --ldpaths=./Alsa/src/low-level-binding:./BusinessLogic/audiologic-afb.so --roothttp=htdocs
+ * start binder: ~/opt/bin/afb-daemon --ldpaths=./build --roothttp=htdocs
* connect browser on http://localhost:1234
# List Avaliable Sound cards
diff --git a/BusinessLogic/AudioLogicBinding.c b/AudioLogic/AudioLogicBinding.c
index 4d7dc35..65943c0 100644
--- a/BusinessLogic/AudioLogicBinding.c
+++ b/AudioLogic/AudioLogicBinding.c
@@ -27,11 +27,11 @@
#include <sys/types.h>
#define _GNU_SOURCE // needed for vasprintf
-#include "AudioLogicMapping.h"
+#include "AudioLogicLib.h"
-PUBLIC const struct afb_binding_interface *binderIface;
+PUBLIC const struct afb_binding_interface *afbIface;
-static void localping(struct afb_req request) {
+STATIC void localping(struct afb_req request) {
json_object *query = afb_req_json(request);
afb_req_success(request, query, NULL);
}
@@ -39,19 +39,19 @@ static void localping(struct afb_req request) {
/*
* array of the verbs exported to afb-daemon
*/
-static const struct afb_verb_desc_v1 binding_verbs[] = {
+STATIC const struct afb_verb_desc_v1 binding_verbs[] = {
/* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */
{ .name= "ping" , .session= AFB_SESSION_NONE, .callback= localping, .info= "Ping Binding" },
{ .name= "setvolume", .session= AFB_SESSION_NONE, .callback= audioLogicSetVol, .info= "Set Volume" },
{ .name= "getvolume", .session= AFB_SESSION_NONE, .callback= audioLogicGetVol, .info= "Get Volume" },
- { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= audioLogicSubscribe, .info= "Get Volume" },
+ { .name= "monitor", .session= AFB_SESSION_NONE, .callback= audioLogicMonitor, .info= "Subscribe Volume Events" },
{ .name= NULL } /* marker for end of the array */
};
/*
* description of the binding for afb-daemon
*/
-static const struct afb_binding binding_description = {
+STATIC const struct afb_binding binding_description = {
/* description conforms to VERSION 1 */
.type= AFB_BINDING_VERSION_1,
.v1= {
@@ -61,8 +61,14 @@ static const struct afb_binding binding_description = {
}
};
-extern int afbBindingV1ServiceInit(struct afb_service service) {
- // this is call when after all bindings are loaded
+// This receive all event this binding subscribe to
+PUBLIC void afbBindingV1ServiceEvent(const char *evtname, struct json_object *object) {
+
+ NOTICE (afbIface, "afbBindingV1ServiceEvent evtname=%s [msg=%s]", evtname, json_object_to_json_string(object));
+}
+
+// this is call when after all bindings are loaded
+PUBLIC int afbBindingV1ServiceInit(struct afb_service service) {
return (audioLogicInit(service));
};
@@ -70,8 +76,8 @@ extern int afbBindingV1ServiceInit(struct afb_service service) {
/*
* activation function for registering the binding called by afb-daemon
*/
-const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) {
- binderIface= itf;
+PUBLIC const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) {
+ afbIface= itf;
return &binding_description; /* returns the description of the binding */
}
diff --git a/BusinessLogic/AudioLogicMapping.c b/AudioLogic/AudioLogicLib.c
index 8e0b773..ebe241c 100644
--- a/BusinessLogic/AudioLogicMapping.c
+++ b/AudioLogic/AudioLogicLib.c
@@ -26,7 +26,7 @@
#include <sys/time.h>
#include <sys/types.h>
-#include "AudioLogicMapping.h"
+#include "AudioLogicLib.h"
static struct afb_service srvitf;
#define _GNU_SOURCE // needed for vasprintf
@@ -37,13 +37,14 @@ PUBLIC int audioLogicInit (struct afb_service service) {
return 0;
}
+// This callback is fired when afb_service_call for api/alsacore/subctl returns
STATIC void alsaSubcribeCB (void *handle, int iserror, struct json_object *result) {
struct afb_req request = afb_req_unstore(handle);
struct json_object *x, *resp = NULL;
const char *info = NULL;
if (result) {
- fprintf (stdout, "result=[%s]\n", json_object_to_json_string (result));
+ INFO (afbIface, "result=[%s]\n", json_object_to_json_string (result));
if (json_object_object_get_ex(result, "request", &x) && json_object_object_get_ex(x, "info", &x))
info = json_object_get_string(x);
if (!json_object_object_get_ex(result, "response", &resp)) resp = NULL;
@@ -57,8 +58,8 @@ STATIC void alsaSubcribeCB (void *handle, int iserror, struct json_object *resul
afb_req_unref(request);
}
-
-PUBLIC void audioLogicSubscribe(struct afb_req request) {
+// Create and subscribe to alsacore ctl events
+PUBLIC void audioLogicMonitor(struct afb_req request) {
// save request in session as it might be used after return by callback
struct afb_req *handle = afb_req_store(request);
@@ -67,12 +68,12 @@ PUBLIC void audioLogicSubscribe(struct afb_req request) {
if (!handle) afb_req_fail(request, "error", "out of memory");
else afb_service_call(srvitf, "alsacore", "subctl", json_object_get(afb_req_json(request)), alsaSubcribeCB, handle);
- // success/failure message will be position from callback
+ // success/failure messages return from callback
}
+// Call when all bindings are loaded and ready to accept request
PUBLIC void audioLogicGetVol(struct afb_req request) {
-
afb_req_success (request, NULL, NULL);
return;
diff --git a/BusinessLogic/AudioLogicMapping.h b/AudioLogic/AudioLogicLib.h
index e1033f7..21513fd 100644
--- a/BusinessLogic/AudioLogicMapping.h
+++ b/AudioLogic/AudioLogicLib.h
@@ -38,12 +38,12 @@ typedef int BOOL;
// import from AlsaAfbBinding
-extern const struct afb_binding_interface *binderIface;
+extern const struct afb_binding_interface *afbIface;
// import from AlsaAfbMapping
PUBLIC void audioLogicSetVol (struct afb_req request);
PUBLIC void audioLogicGetVol(struct afb_req request);
-PUBLIC void audioLogicSubscribe(struct afb_req request);
+PUBLIC void audioLogicMonitor(struct afb_req request);
PUBLIC int audioLogicInit (struct afb_service service);
#endif /* AUDIOLIBMAPPING_H */
diff --git a/BusinessLogic/CMakeLists.txt b/AudioLogic/CMakeLists.txt
index 7ae760b..0b72b5c 100644
--- a/BusinessLogic/CMakeLists.txt
+++ b/AudioLogic/CMakeLists.txt
@@ -22,7 +22,7 @@ INCLUDE_DIRECTORIES(${include_dirs})
##################################################
# AudioLogicBinding
##################################################
-ADD_LIBRARY(audiologic-afb MODULE AudioLogicBinding.c AudioLogicMapping.c)
+ADD_LIBRARY(audiologic-afb MODULE AudioLogicBinding.c AudioLogicLib.c)
SET_TARGET_PROPERTIES(audiologic-afb PROPERTIES
PREFIX ""
diff --git a/BusinessLogic/README.md b/AudioLogic/README.md
index a07f752..399f905 100644
--- a/BusinessLogic/README.md
+++ b/AudioLogic/README.md
@@ -3,11 +3,11 @@
------------------------------------------------------------------------
Testing: (from project directory bindings)
- * start binder: ~/opt/bin/afb-daemon --ldpaths=./Alsa/src/low-level-binding:./BusinessLogic/audiologic-afb.so --roothttp=htdocs
+ * start binder: ~/opt/bin/afb-daemon --ldpaths=./build --roothttp=htdocs
* connect browser on http://localhost:1234
# Subscribe event for a given board
- http://localhost:1234/api/audio/subscribe&devid=hw:0
+ http://localhost:1234/api/audio/subscribe?devid=hw:0
# Increase Volume
http://localhost:1234/api/audio/setvol?devid=hw:0&pcm=master&vol=50%
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a5fe3d2..3f120e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,7 @@ INCLUDE(CheckLibraryExists)
INCLUDE(GNUInstallDirs)
-SET(binding_install_dir ${CMAKE_INSTALL_FULL_LIBDIR}/afb)
+SET(binding_install_dir ${CMAKE_INSTALL_FULL_LIBDIR}/audio)
# Generic useful macro
###########################################################
@@ -111,4 +111,5 @@ SET(link_libraries
# Bindings to compile
# --------------------
add_subdirectory(Alsa)
-add_subdirectory(BusinessLogic)
+add_subdirectory(AudioLogic)
+add_subdirectory(htdocs)
diff --git a/README.md b/README.md
index bbc7b9c..b33f843 100644
--- a/README.md
+++ b/README.md
@@ -8,21 +8,34 @@ AFB_daemon dependency on Standard Linux Distributions
# handle dependencies > (OpenSuse-42.2, Fedora-25, Ubuntu 16.04.2LTS)
gcc > 4.8
libsystemd-dev>=222
- libmicrohttpd-dev>=0.9.48
openssl-dev
uuid-dev
+ libmicrohttpd with AGL patches http://iot.bzh/download/public/2016/appfw/libmicrohttpd-0.9.49-agl.tgz
+ afb-daemon from AGL Gerrit git clone https://gerrit.automotivelinux.org/gerrit/src/app-framework-binder
+
```
# Might want to add following variables into ~/.bashrc
- export CC=gcc-5; export CXX=g++-5 # if using gcc5
- export DEST=$HOME/opt
- export LD_LIBRARY_PATH=$DEST/lib64
- export LIBRARY_PATH=$DEST/lib64
- export PKG_CONFIG_PATH=$DEST/lib64/pkgconfig
- export PATH=$DEST/bin:$PATH
+ # export CC=gcc-5; export CXX=g++-5 # if using gcc5
+ echo "export DEST=$HOME/opt" >>~/.bashrc
+ echo "export LD_LIBRARY_PATH=$DEST/lib64" >>~/.bashrc
+ echo "export LIBRARY_PATH=$DEST/lib64" >>~/.bashrc
+ echo "export PKG_CONFIG_PATH=$DEST/lib64/pkgconfig" >>~/.bashrc
+ echo "export PATH=$DEST/bin:$PATH" >>~/.bashrc
+ source ~/.bashrc
+
+ # install AGL pached version of LibMicroHttpd
+ wget http://iot.bzh/download/public/2016/appfw/libmicrohttpd-0.9.49-agl.tgz
+ tar -xzf libmicrohttpd-0.9.49-agl.tgz
+ cd libmicrohttpd-0.9.49-agl
+ ./configure --prefix=$DEST
+ make
+ make install-strip
+
+ # retreive last AFB_daemon from AGL
+ git clone https://gerrit.automotivelinux.org/gerrit/src/app-framework-binder
# Warning: previous GCC options should be set before initial cmake (clean Build/*)
- source ~/.bashrc
cd app-framework-binder; mkdir build; cd build
cmake -DCMAKE_INSTALL_PREFIX=$DEST ..
make
@@ -48,7 +61,7 @@ make install
ls
# Start the binder
-afb-daemon --token=x --ldpaths=$INSTALL_DIR/lib --port=1234 --roothttp=$INSTALL_DIR/htdocs/audio-bindings --verbose
+afb-daemon --token=x --ldpaths=$INSTALL_DIR/lib/audio --port=1234 --roothttp=$INSTALL_DIR/htdocs/audio-bindings --verbose
```
diff --git a/htdocs/CMakeLists.txt b/htdocs/CMakeLists.txt
new file mode 100644
index 0000000..22a4d63
--- /dev/null
+++ b/htdocs/CMakeLists.txt
@@ -0,0 +1,25 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 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.
+###########################################################################
+
+
+
+
+##################################################
+# HTML Testing Files
+##################################################
+install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DESTINATION . FILES_MATCHING PATTERN "*.html" PATTERN "*.js" PATTERN "*.jpg")
diff --git a/htdocs/alsa-core.html b/htdocs/alsa-core.html
index e408a01..0969b6f 100644
--- a/htdocs/alsa-core.html
+++ b/htdocs/alsa-core.html
@@ -15,7 +15,7 @@
document.getElementById("connected").innerHTML = "Connected Closed";
}
function init() {
- ws = new AfbWsItf("api", onopen, onabort, new AfbCtxItf("hello"));
+ ws = new AfbWsItf("api", onopen, onabort, new AfbCtxItf("mysecret"));
}
function replyok(obj) {
document.getElementById("output").innerHTML = "OK: "+JSON.stringify(obj);
@@ -38,6 +38,5 @@
<li><a href="api/alsacore/getctl?devid=hw:0&numid=1&quiet=0">return control numid=1 for hw:0</a>
<li><button id="connected" onclick="subscribe('hw:0')">Click to Connected</button></li>
<div id="main" style="visibility:hidden">
- <p>Event Output</p>
Server says... <div id="output"></div>
</div>
diff --git a/htdocs/audio-logic.html b/htdocs/audio-logic.html
new file mode 100644
index 0000000..ff806ad
--- /dev/null
+++ b/htdocs/audio-logic.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+ <title>Hello world test</title>
+
+ <script type="text/javascript" src="websock.js"></script>
+ <script type="text/javascript">
+ var ws;
+
+ function onopen() {
+ document.getElementById("main").style.visibility = "visible";
+ document.getElementById("connected").innerHTML = "WebSocket Open";
+ }
+ function onabort() {
+ document.getElementById("main").style.visibility = "hidden";
+ document.getElementById("connected").innerHTML = "Connected Closed";
+ }
+ function init() {
+ ws = new AfbWsItf("api", onopen, onabort, new AfbCtxItf("mysecret"));
+ }
+ function replyok(obj) {
+ document.getElementById("output").innerHTML = "OK: "+JSON.stringify(obj);
+ }
+ function replyerr(obj) {
+ document.getElementById("output").innerHTML = "ERROR: "+JSON.stringify(obj);
+ }
+ function subscribe(devid) {
+ ws.call("alsacore", "subctl", {devid:devid}, replyok, replyerr);
+ }
+ </script>
+
+<body onload="init();">
+ <h1>Hello world test</h1>
+ <ol>
+ <li><a href="api/audio/setvol?devid=hw:0&pcm=master&vol=50%">Set Master PCM volume to 50%</a>
+ <li><a href="api/audio/getvol?devid=hw:0&pcm=master">Get Master PCM volume</a>
+ <li><a href="api/alsacore/monitor?devid=hw:0">Activate devid=hw:0 monitoring</a>
+ <li><button id="connected" onclick="subscribe('hw:0')">Click to Subscribe</button></li>
+ <div id="main" style="visibility:hidden">
+ Server says... <div id="output"></div>
+ </div>
diff --git a/htdocs/index.html b/htdocs/index.html
index dfb3c71..330ef4d 100644
--- a/htdocs/index.html
+++ b/htdocs/index.html
@@ -5,3 +5,4 @@
<h1>audio-bindings test</h1>
<ol>
<li><a href="alsa-core.html">AlsaCore Low Level Binding</a>
+ <li><a href="audio-logic.html">AudioLogic High level business API</a>