From a237499e8c2e2a045ae3eea0b9a4aaac12032e81 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 8 Mar 2017 23:56:40 +0100 Subject: Late Evening Commit --- AudioLogic/AudioLogicBinding.c | 14 ++-- AudioLogic/AudioLogicLib.c | 153 ++++++++++++++++++++++++++++++++++++----- AudioLogic/AudioLogicLib.h | 14 ++++ AudioLogic/README.md | 29 ++++++-- 4 files changed, 181 insertions(+), 29 deletions(-) (limited to 'AudioLogic') 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 #include -#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 -- cgit 1.2.3-korg