aboutsummaryrefslogtreecommitdiffstats
path: root/AudioLogic
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2017-03-08 23:56:40 +0100
committerFulup Ar Foll <fulup@iot.bzh>2017-03-08 23:56:40 +0100
commita237499e8c2e2a045ae3eea0b9a4aaac12032e81 (patch)
tree4971c10f24585fa04f0a414cb319d3b0554c8a85 /AudioLogic
parent1393b5d318e22dbd1625692847a51c27932fd442 (diff)
Late Evening Commit
Diffstat (limited to 'AudioLogic')
-rw-r--r--AudioLogic/AudioLogicBinding.c14
-rw-r--r--AudioLogic/AudioLogicLib.c153
-rw-r--r--AudioLogic/AudioLogicLib.h14
-rw-r--r--AudioLogic/README.md29
4 files changed, 181 insertions, 29 deletions
diff --git a/AudioLogic/AudioLogicBinding.c b/AudioLogic/AudioLogicBinding.c
index 65943c0..1220f29 100644
--- a/AudioLogic/AudioLogicBinding.c
+++ b/AudioLogic/AudioLogicBinding.c
@@ -26,7 +26,7 @@
#include <sys/time.h>
#include <sys/types.h>
-#define _GNU_SOURCE // needed for vasprintf
+#include "AlsaMixerHal.h"
#include "AudioLogicLib.h"
PUBLIC const struct afb_binding_interface *afbIface;
@@ -36,15 +36,19 @@ STATIC void localping(struct afb_req request) {
afb_req_success(request, query, NULL);
}
+
/*
* array of the verbs exported to afb-daemon
*/
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= "monitor", .session= AFB_SESSION_NONE, .callback= audioLogicMonitor, .info= "Subscribe Volume Events" },
+ { .name= "ping" , .session= AFB_SESSION_NONE, .callback= localping, .info= "Ping Binding" },
+ { .name= "setvolume", .session= AFB_SESSION_CHECK, .callback= audioLogicSetVol, .info= "Set Volume" },
+ { .name= "getvolume", .session= AFB_SESSION_CHECK, .callback= audioLogicGetVol, .info= "Get Volume" },
+ { .name= "subscribe", .session= AFB_SESSION_CHECK, .callback= audioLogicSubscribe, .info= "Subscribe AudioBinding Events" },
+ { .name= "monitor", .session= AFB_SESSION_CHECK, .callback= audioLogicMonitor, .info= "Activate AlsaCtl Monitoring" },
+ { .name= "open", .session= AFB_SESSION_CREATE,.callback= audioLogicOpen, .info= "Open a Dedicated SoundCard" },
+ { .name= "close", .session= AFB_SESSION_CLOSE, .callback= audioLogicClose, .info= "Close previously open SoundCard" },
{ .name= NULL } /* marker for end of the array */
};
diff --git a/AudioLogic/AudioLogicLib.c b/AudioLogic/AudioLogicLib.c
index ebe241c..857cc9f 100644
--- a/AudioLogic/AudioLogicLib.c
+++ b/AudioLogic/AudioLogicLib.c
@@ -29,12 +29,34 @@
#include "AudioLogicLib.h"
static struct afb_service srvitf;
-#define _GNU_SOURCE // needed for vasprintf
-// this function is call after all binder are loaded and initialised
-PUBLIC int audioLogicInit (struct afb_service service) {
- srvitf = service;
- return 0;
+PUBLIC void audioLogicSetVol(struct afb_req request) {
+
+ const char *vol = afb_req_value(request, "vol");
+ if (vol == NULL) {
+ afb_req_fail_f (request, "argument-missing", "vol=+-%[0,100] missing");
+ goto ExitOnError;
+ }
+
+ switch (vol[0]) {
+ case '+':
+ break;
+ case '-':
+ break;
+ case '%':
+ break;
+
+ default:
+ afb_req_fail_f (request, "value-invalid", "volume should be (+-%[0-100]xxx) vol=%s", vol);
+ goto ExitOnError;
+ }
+
+ // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card
+ afb_req_success (request, NULL, NULL);
+ return;
+
+ ExitOnError:
+ return;
}
// This callback is fired when afb_service_call for api/alsacore/subctl returns
@@ -46,44 +68,139 @@ STATIC void alsaSubcribeCB (void *handle, int iserror, struct json_object *resul
if (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;
- }
+ info = json_object_get_string(x);
+ if (!json_object_object_get_ex(result, "response", &resp)) resp = NULL;
+ }
// push message respond
if (iserror) afb_req_fail_f(request, "Fail", info);
else afb_req_success(request, resp, info);
- // free calling request
- afb_req_unref(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
+ // keep request for callback to respond
struct afb_req *handle = afb_req_store(request);
-
+
+ // get client context
+ AudioLogicCtxT *ctx = afb_req_context_get(request);
+
// push request to low level binding
- 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);
+ NOTICE (afbIface, "audioLogicMonitor ctx->devid=%s [ctx->queryurl=%s]", ctx->devid, json_object_to_json_string(ctx->queryurl));
+
+ if (ctx->queryurl) {
+ json_object_get (ctx->queryurl); // Make sure usage count does not fall to zero
+ afb_service_call(srvitf, "alsacore", "subscribe", ctx->queryurl, alsaSubcribeCB, handle);
+ }
+
+ else afb_req_fail_f(request, "context-invalid", "No valid queryurl in client context");
// success/failure messages return from callback
}
+// Subscribe to AudioBinding events
+PUBLIC void audioLogicSubscribe (struct afb_req request) {
+
+ return;
+}
+
+
// Call when all bindings are loaded and ready to accept request
PUBLIC void audioLogicGetVol(struct afb_req request) {
+ // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card
afb_req_success (request, NULL, NULL);
return;
}
-PUBLIC void audioLogicSetVol(struct afb_req request) {
-
+// This callback is fired when afb_service_call for api/alsacore/subctl returns
+STATIC void audioLogicOpenCB (void *handle, int iserror, struct json_object *result) {
+ struct afb_req request = afb_req_unstore(handle);
+ struct json_object *response;
+ //INFO (afbIface, "result=[%s]\n", json_object_to_json_string (result));
- afb_req_success (request, NULL, NULL);
- return;
+
+ if (iserror) { // on error proxy information we got from lower layer
+ if (result) {
+ struct json_object *status, *info;
+
+ if (json_object_object_get_ex(result, "request", &response)) {
+ json_object_object_get_ex(response, "info" , &info);
+ json_object_object_get_ex(response, "status", &status);
+ afb_req_fail(request, json_object_get_string(status), json_object_get_string(info));
+ goto OnExit;
+ }
+ } else {
+ afb_req_fail(request, "Fail", "Unknown Error" );
+ }
+ goto OnExit;
+ }
+
+ // Get response from object
+ json_object_object_get_ex(result, "response", &response);
+ if (response) {
+ struct json_object *subobj;
+
+ // attach client context to session
+ AudioLogicCtxT *ctx = malloc (sizeof(AudioLogicCtxT));
+
+ // extract information from Json Alsa Object
+ json_object_object_get_ex(response, "cardid", &subobj);
+ if (subobj) ctx->cardid= json_object_get_int(subobj);
+
+ // store devid as an object for further alsa request
+ json_object_object_get_ex(response, "devid", &subobj);
+ if (subobj) ctx->devid= strdup(json_object_get_string(subobj));
+
+ json_object_object_get_ex(response, "shortname", &subobj);
+ if (subobj)ctx->shortname=strdup(json_object_get_string(subobj));
+
+ json_object_object_get_ex(response, "longname", &subobj);
+ if (subobj)ctx->longname=strdup(json_object_get_string(subobj));
+ // add AudioLogicCtxT to Client Session
+ NOTICE (afbIface, "audioLogicOpen ctx->devid=[%s]", ctx->devid);
+
+ // save queryurl with devid only for further ALSA request
+ ctx->queryurl=json_object_new_object();
+ json_object_object_add(ctx->queryurl, "devid",json_object_new_string(ctx->devid));
+
+ afb_req_context_set(request, ctx, free);
+ }
+
+ // release original calling request
+ afb_req_success(request, response, NULL);
+
+
+ OnExit:
+ afb_req_unref(request);
+ return;
}
+// Delegate to lowerlevel the mapping of soundcard name with soundcard ID
+PUBLIC void audioLogicOpen(struct afb_req request) {
+
+ // Delegate query to lower level
+ struct afb_req *handle = afb_req_store(request);
+ if (!handle) afb_req_fail(request, "error", "out of memory");
+ else afb_service_call(srvitf, "alsacore", "getCardId", json_object_get(afb_req_json(request)), audioLogicOpenCB, handle);
+}
+
+// Free client context create from audioLogicOpenCB
+PUBLIC void audioLogicClose (struct afb_req request) {
+
+ // retrieve current client context to print debug info
+ AudioLogicCtxT *ctx = (AudioLogicCtxT*) afb_req_context_get(request);
+ DEBUG (afbIface, "audioLogicClose cardid=%d devid=%s shortname=%s longname=%s", ctx->cardid, ctx->devid, ctx->shortname, ctx->longname);
+}
+
+
+// this function is call after all binder are loaded and initialised
+PUBLIC int audioLogicInit (struct afb_service service) {
+ srvitf = service;
+
+ return 0;
+}
diff --git a/AudioLogic/AudioLogicLib.h b/AudioLogic/AudioLogicLib.h
index 21513fd..8530360 100644
--- a/AudioLogic/AudioLogicLib.h
+++ b/AudioLogic/AudioLogicLib.h
@@ -40,10 +40,24 @@ typedef int BOOL;
// import from AlsaAfbBinding
extern const struct afb_binding_interface *afbIface;
+
+// This structure hold private data for a given client of binding
+typedef struct {
+
+ int cardid;
+ const char *devid;
+ const char *shortname;
+ const char *longname;
+ json_object *queryurl;
+} AudioLogicCtxT;
+
// import from AlsaAfbMapping
PUBLIC void audioLogicSetVol (struct afb_req request);
PUBLIC void audioLogicGetVol(struct afb_req request);
PUBLIC void audioLogicMonitor(struct afb_req request);
+PUBLIC void audioLogicOpen(struct afb_req request);
+PUBLIC void audioLogicClose(struct afb_req request);
+PUBLIC void audioLogicSubscribe(struct afb_req request);
PUBLIC int audioLogicInit (struct afb_service service);
#endif /* AUDIOLIBMAPPING_H */
diff --git a/AudioLogic/README.md b/AudioLogic/README.md
index 399f905..fa50173 100644
--- a/AudioLogic/README.md
+++ b/AudioLogic/README.md
@@ -3,16 +3,33 @@
------------------------------------------------------------------------
Testing: (from project directory bindings)
- * start binder: ~/opt/bin/afb-daemon --ldpaths=./build --roothttp=htdocs
- * connect browser on http://localhost:1234
+ * start binder: ~/opt/bin/afb-daemon --ldpaths=./build --token=mysecret --roothttp=htdocs
+ * connect browser on http://localhost:1234?devid=hw:0
+
+ # Open Sound Card from its name
+ http://localhost:1234/api/audio/open?token=mysecret&sndname=H650e
# Subscribe event for a given board
- http://localhost:1234/api/audio/subscribe?devid=hw:0
+ http://localhost:1234/api/audio/subscribe?token=mysecret&devid=hw:0
# Increase Volume
- http://localhost:1234/api/audio/setvol?devid=hw:0&pcm=master&vol=50%
+ http://localhost:1234/api/audio/setvol?token=mysecret&devid=hw:0&pcm=master&vol=50%
# Get Volume
- http://localhost:1234/api/audio/getvol?devid=hw:0&pcm=master
+ http://localhost:1234/api/audio/getvol?token=mysecret&devid=hw:0&pcm=master
+
+ # Close Session
+ http://localhost:1234/api/audio/close?token=mysecret
+
+
+Testing with afb-client-demo
- \ No newline at end of file
+```
+~/opt/bin/afb-client-demo localhost:1234/api?token=mysecret
+alsacore subctl {"devid":"hw:0"}
+```
+
+Start AlsaMixer and change volume
+```
+alsamixer -D hw:0
+``` \ No newline at end of file