diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2017-03-09 15:58:04 +0100 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2017-03-09 15:58:04 +0100 |
commit | 5cb52e556fed8eb0cf74d1052fe413fbb7406b0e (patch) | |
tree | 80965e8ad49b5191b200b6bbb1241c4718a0c000 | |
parent | a237499e8c2e2a045ae3eea0b9a4aaac12032e81 (diff) |
Syncup Status with Microchip
20 files changed, 728 insertions, 371 deletions
diff --git a/AlsaSound/CMakeLists.txt b/AlsaSound/CMakeLists.txt index 7b1d5e9..7356ca4 100644 --- a/AlsaSound/CMakeLists.txt +++ b/AlsaSound/CMakeLists.txt @@ -28,5 +28,5 @@ SET(link_libraries ) ADD_SUBDIRECTORY(CoreBinding) -ADD_SUBDIRECTORY(HardAbsLayer) +ADD_SUBDIRECTORY(HALayer) diff --git a/AlsaSound/CoreBinding/AlsaAfbBinding.c b/AlsaSound/CoreBinding/AlsaAfbBinding.c index 2c5c789..4ae7ccc 100644 --- a/AlsaSound/CoreBinding/AlsaAfbBinding.c +++ b/AlsaSound/CoreBinding/AlsaAfbBinding.c @@ -40,11 +40,12 @@ static void localping(struct afb_req request) { */ 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= "getinfo", .session= AFB_SESSION_NONE, .callback= alsaGetInfo, .info= "List All/One Sound Cards Info" }, - { .name= "getctl", .session= AFB_SESSION_NONE, .callback= alsaGetCtl, .info= "List All/One Controls from selected sndcard" }, - { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= alsaSubcribe, .info= "Subscribe to events from selected sndcard" }, - { .name= "getcardid", .session= AFB_SESSION_NONE, .callback= alsaGetCardId,.info= "Get CardId from its short/long name" }, + { .name= "ping" , .session= AFB_SESSION_NONE, .callback= localping, .info= "Ping Binding" }, + { .name= "getinfo", .session= AFB_SESSION_NONE, .callback= alsaGetInfo, .info= "List All/One Sound Cards Info" }, + { .name= "getctl", .session= AFB_SESSION_NONE, .callback= alsaGetCtl, .info= "List All/One Controls from selected sndcard" }, + { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= alsaSubcribe, .info= "Subscribe to events from selected sndcard" }, + { .name= "getcardid", .session= AFB_SESSION_NONE, .callback= alsaGetCardId, .info= "Get CardId from its short/long name" }, + { .name= "registerHal",.session= AFB_SESSION_NONE,.callback= alsaRegisterHal,.info= "Register Hal CardName/ApiPrefix" }, { .name= NULL } /* marker for end of the array */ }; diff --git a/AlsaSound/CoreBinding/AlsaLibMapping.c b/AlsaSound/CoreBinding/AlsaLibMapping.c index 8dc1772..900aa3d 100644 --- a/AlsaSound/CoreBinding/AlsaLibMapping.c +++ b/AlsaSound/CoreBinding/AlsaLibMapping.c @@ -52,6 +52,14 @@ typedef struct { evtHandleT *evtHandle; } sndHandleT; +typedef struct { + char *apiprefix; + char *shortname; +}cardRegistryT; + +cardRegistryT *cardRegistry[MAX_SND_CARD+1]; + + STATIC json_object *DB2StringJsonOject (long dB) { char label [20]; if (dB < 0) { @@ -511,7 +519,7 @@ PUBLIC void alsaGetCtl(struct afb_req request) { json_object *query = afb_req_json(request); afb_req_fail_f (request, "Query=%s NumID not integer &numid=%s&", json_object_to_json_string(query), rqtNumid); - goto ExitOnError; + goto OnErrorExit; }; const char *rqtQuiet = afb_req_value(request, "quiet"); @@ -520,18 +528,18 @@ PUBLIC void alsaGetCtl(struct afb_req request) { json_object *query = afb_req_json(request); afb_req_fail_f (request, "Query=%s NumID not integer &numid=%s&", json_object_to_json_string(query), rqtQuiet); - goto ExitOnError; + goto OnErrorExit; }; // Open sound we use Alsa high level API like amixer.c if (!queryValues.devid || (err = snd_hctl_open(&handle, queryValues.devid, 0)) < 0) { afb_req_fail_f (request, "alsaGetControl devid=[%s] open fail error=%s\n", queryValues.devid, snd_strerror(err)); - goto ExitOnError; + goto OnErrorExit; } if ((err = snd_hctl_load(handle)) < 0) { afb_req_fail_f (request, "alsaGetControl devid=[%s] load fail error=%s\n", queryValues.devid, snd_strerror(err)); - goto ExitOnError; + goto OnErrorExit; } // allocate ram for ALSA elements @@ -546,7 +554,7 @@ PUBLIC void alsaGetCtl(struct afb_req request) { json_object_put(sndctrls); // we abandon request let's free response afb_req_fail_f (request, "alsaGetControl devid=[%s/%s] snd_hctl_elem_info error: %s\n" , queryValues.devid, snd_hctl_name(handle), snd_strerror(err)); - goto ExitOnError; + goto OnErrorExit; } // each control is added into a JSON array @@ -559,7 +567,7 @@ PUBLIC void alsaGetCtl(struct afb_req request) { return; // nothing special only for debugger breakpoint - ExitOnError: + OnErrorExit: return; } @@ -587,7 +595,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* snd_ctl_event_alloca(&ctlEvent); // initialise event structure on stack err = snd_ctl_read(evtHandle->ctl, ctlEvent); - if (err < 0) goto ExitOnError; + if (err < 0) goto OnErrorExit; // we only process sndctrl element if (snd_ctl_event_get_type(ctlEvent) != SND_CTL_EVENT_ELEM) goto ExitOnSucess; @@ -619,7 +627,7 @@ STATIC int sndCtlEventCB (sd_event_source* src, int fd, uint32_t revents, void* ExitOnSucess: return 0; - ExitOnError: + OnErrorExit: WARNING (afbIface, "sndCtlEventCB: ignored unsupported event type"); return (0); } @@ -636,14 +644,14 @@ PUBLIC void alsaSubcribe (struct afb_req request) { const char *devid = afb_req_value(request, "devid"); if (devid == NULL) { afb_req_fail_f (request, "devid-missing", "devid=hw:xxx missing"); - goto ExitOnError; + goto OnErrorExit; } // open control interface for devid err = snd_ctl_open(&ctlHandle, devid, SND_CTL_READONLY); if (err < 0) { afb_req_fail_f (request, "devid-unknown", "SndCard devid=%s Not Found err=%d", devid, err); - goto ExitOnError; + goto OnErrorExit; } // get sound card index use to search existing subscription @@ -666,7 +674,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { if (idxFree == -1) { afb_req_fail_f (request, "register-toomany", "Cannot register new event Maxcard==%devent name=%s", idx); snd_ctl_close(ctlHandle); - goto ExitOnError; + goto OnErrorExit; } evtHandle = malloc (sizeof(evtHandleT)); @@ -680,7 +688,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { if (err < 0) { afb_req_fail_f (request, "subscribe-fail", "Cannot subscribe events from devid=%s err=%d", devid, err); snd_ctl_close(ctlHandle); - goto ExitOnError; + goto OnErrorExit; } // get pollfd attach to this sound board @@ -691,7 +699,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { 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); - goto ExitOnError; + goto OnErrorExit; } // create binder event attached to devid name @@ -699,7 +707,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { 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; + goto OnErrorExit; } // everything looks OK let's move forward @@ -710,7 +718,7 @@ PUBLIC void alsaSubcribe (struct afb_req request) { err = afb_req_subscribe(request, evtHandle->afbevt); if (err != 0) { afb_req_fail_f (request, "register-eventname", "Cannot subscribe binder event name=%s [invalid channel]", devid, err); - goto ExitOnError; + goto OnErrorExit; } // increase usage count and return success @@ -718,14 +726,15 @@ PUBLIC void alsaSubcribe (struct afb_req request) { afb_req_success(request, NULL, NULL); return; - ExitOnError: + OnErrorExit: return; } // Subscribe to every Alsa CtlEvent send by a given board PUBLIC void alsaGetCardId (struct afb_req request) { char devid [10]; - int card, err, index; + const char *devname, *shortname, *longname; + int card, err, index, idx; json_object *respJson; snd_ctl_t *ctlHandle; snd_ctl_card_info_t *cardinfo; @@ -733,7 +742,7 @@ PUBLIC void alsaGetCardId (struct afb_req request) { const char *sndname = afb_req_value(request, "sndname"); if (sndname == NULL) { afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); - goto ExitOnError; + goto OnErrorExit; } // loop on potential card number @@ -747,31 +756,77 @@ PUBLIC void alsaGetCardId (struct afb_req request) { err = snd_ctl_open(&ctlHandle, devid, SND_CTL_READONLY); if (err < 0) continue; + // extract sound card information snd_ctl_card_info(ctlHandle, cardinfo); index = snd_ctl_card_info_get_card(cardinfo); - + devname = snd_ctl_card_info_get_id(cardinfo); + shortname= snd_ctl_card_info_get_name(cardinfo); + longname = snd_ctl_card_info_get_longname(cardinfo); + // check if short|long name match - if (!strcmp (sndname, snd_ctl_card_info_get_id(cardinfo))) break; - if (!strcmp (sndname, snd_ctl_card_info_get_name(cardinfo))) break; - if (!strcmp (sndname, snd_ctl_card_info_get_longname(cardinfo))) break; + if (!strcmp (sndname, devname)) break; + if (!strcmp (sndname, shortname)) break; + if (!strcmp (sndname, longname)) break; } if (card == MAX_SND_CARD) { afb_req_fail_f (request, "sndcard-notfound", "Fail to find card with name=%s", sndname); - goto ExitOnError; + goto OnErrorExit; } // proxy ctlevent as a binder event respJson = json_object_new_object(); json_object_object_add(respJson, "index" ,json_object_new_int (index)); json_object_object_add(respJson, "devid" ,json_object_new_string (devid)); - json_object_object_add(respJson, "shortname" ,json_object_new_string (snd_ctl_card_info_get_name(cardinfo))); - json_object_object_add(respJson, "longname" ,json_object_new_string (snd_ctl_card_info_get_longname(cardinfo))); + json_object_object_add(respJson, "shortname" ,json_object_new_string (shortname)); + json_object_object_add(respJson, "longname" ,json_object_new_string (longname)); + // search for a HAL binder card mapping name to api prefix + for (idx=0; idx < MAX_SND_CARD; idx++) { + if (!strcmp (cardRegistry[idx]->shortname, shortname)) break; + } + // if a match if found, then we have an HAL for this board let's return its value + if (idx < MAX_SND_CARD) json_object_object_add(respJson, "halapi",json_object_new_string (cardRegistry[idx]->apiprefix)); + afb_req_success(request, respJson, NULL); return; - ExitOnError: + OnErrorExit: + return; +} + +// Register loaded HAL with board Name and API prefix +PUBLIC void alsaRegisterHal (struct afb_req request) { + static int index=0; + const char *shortname, *apiPrefix; + + apiPrefix = afb_req_value(request, "prefix"); + if (apiPrefix == NULL) { + afb_req_fail_f (request, "argument-missing", "prefix=BindingApiPrefix missing"); + goto OnErrorExit; + } + + shortname = afb_req_value(request, "name"); + if (shortname == NULL) { + afb_req_fail_f (request, "argument-missing", "sndname=SndCardName missing"); + goto OnErrorExit; + } + + if (index == MAX_SND_CARD) { + afb_req_fail_f (request, "alsahal-toomany", "Fail to register sndname=[%s]", shortname); + goto OnErrorExit; + } + + cardRegistry[index]= malloc (sizeof(cardRegistry)); + cardRegistry[index]->apiprefix=strdup(apiPrefix); + cardRegistry[index]->shortname=strdup(shortname); + index++;cardRegistry[index]=NULL; + + // when OK nothing to return + afb_req_success(request, NULL, NULL); + return; + + OnErrorExit: return; } diff --git a/AlsaSound/CoreBinding/AlsaLibMapping.h b/AlsaSound/CoreBinding/AlsaLibMapping.h index cd6b409..e9e3a42 100644 --- a/AlsaSound/CoreBinding/AlsaLibMapping.h +++ b/AlsaSound/CoreBinding/AlsaLibMapping.h @@ -36,6 +36,8 @@ typedef int BOOL; #include <afb/afb-binding.h> #include <afb/afb-service-itf.h> +#include "MiscHelpers.h" + // import from AlsaAfbBinding extern const struct afb_binding_interface *afbIface; @@ -45,6 +47,7 @@ PUBLIC void alsaGetInfo (struct afb_req request); PUBLIC void alsaGetCtl(struct afb_req request); PUBLIC void alsaSubcribe (struct afb_req request); PUBLIC void alsaGetCardId (struct afb_req request); +PUBLIC void alsaRegisterHal (struct afb_req request); #endif /* ALSALIBMAPPING_H */ diff --git a/AlsaSound/CoreBinding/README.md b/AlsaSound/CoreBinding/README.md index 5b6f026..a4b0395 100644 --- a/AlsaSound/CoreBinding/README.md +++ b/AlsaSound/CoreBinding/README.md @@ -12,6 +12,9 @@ Testing: (from project directory bindings) # Get Info on a given Sound Card http://localhost:1234/api/alsacore/getinfo?devid=hw:0 + # Get shortname/longname for a given card + http://localhost:1234/api/alsacore/getcardid?devid=hw:0 + # Get all controls from a given sound card http://localhost:1234/api/alsacore/getctl?devid=hw:0 diff --git a/AlsaSound/HardAbsLayer/CMakeLists.txt b/AlsaSound/HALayer/CMakeLists.txt index e24a9d9..0b12f62 100644 --- a/AlsaSound/HardAbsLayer/CMakeLists.txt +++ b/AlsaSound/HALayer/CMakeLists.txt @@ -18,6 +18,9 @@ PROJECT(hadware-abstraction-layer C) +# Fulup NOTE: this might have to be change for a formal static/dynamic lib +set(halsharedlib ${CMAKE_CURRENT_SOURCE_DIR}/Shared/SharedHalLib.c) ADD_SUBDIRECTORY(IntelHda) +ADD_SUBDIRECTORY(Shared) diff --git a/AlsaSound/HardAbsLayer/IntelHda/CMakeLists.txt b/AlsaSound/HALayer/IntelHda/CMakeLists.txt index 0d3f344..77218e2 100644 --- a/AlsaSound/HardAbsLayer/IntelHda/CMakeLists.txt +++ b/AlsaSound/HALayer/IntelHda/CMakeLists.txt @@ -22,7 +22,7 @@ INCLUDE_DIRECTORIES(${include_dirs}) ################################################## # Inte-HDA sound card Hardware Abstraction Layer ################################################## -ADD_LIBRARY(intel-hda-hal MODULE IntelHdaBinding.c IntelHdaLib.c) +ADD_LIBRARY(intel-hda-hal MODULE IntelHdaHAL.c ${halsharedlib}) SET_TARGET_PROPERTIES(intel-hda-hal PROPERTIES PREFIX "" diff --git a/AlsaSound/HALayer/IntelHda/IntelHdaHAL.c b/AlsaSound/HALayer/IntelHda/IntelHdaHAL.c new file mode 100644 index 0000000..b04b545 --- /dev/null +++ b/AlsaSound/HALayer/IntelHda/IntelHdaHAL.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 "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 +#include "AlsaHalIface.h" // Include Share Interface to Alsa Sound Card HAL + +/***************************************************************************** + * alsaCtlsMap link hight level sound control with low level Alsa numid ctls. + * + * To find out which control your sound card uses + * aplay -l + * amixer -D hw:xx controls + * amixer -D hw:xx contents + * amixer -D "hw:3" cget numid=xx + *****************************************************************************/ +STATIC alsaHalCtlMapT alsaHalCtlsMap[]= { + { .control=Master_Playback_Volume, .numid=16, .group=OUTVOL, .values=1, .minval=0, .maxval= 87 , .step=0, .acl=RW, .info= "Master Playback Volume" }, + { .control=PCM_Playback_Volume , .numid=27, .group=PCMVOL, .values=2, .minval=0, .maxval= 255, .step=0, .acl=RW, .info= "PCM Playback Volume" }, + { .control=PCM_Playback_Switch , .numid=17, .group=SWITCH, .values=1, .minval=0, .maxval= 1 , .step=0, .acl=RW, .info= "Master Playback Switch" }, + { .control=Capture_Volume , .numid=12, .group=INVOL , .values=2, .minval=0, .maxval= 31 , .step=0, .acl=RW, .info= "Capture Volume" }, + { .numid=0 } /* marker for end of the array */ +} ; + +/*********************************************************************************** + * AlsaHalSndT provides + * - cardname used to map a given card to its HAL + * - ctls previously defined AlsaHalMapT control maps + * - info free text + * + * WARNING: name should fit with 'aplay -l' as it used to map from devid to HAL + * you may also retreive shortname when AudioBinder is running from a browser + * http://localhost:1234/api/alsacore/getcardid?devid=hw:xxx + * + ***********************************************************************************/ +PUBLIC alsaHalSndCardT alsaHalSndCard = { + .name = "HDA Intel PCH", + .info = "Hardware Abstraction Layer for IntelHDA sound card", + .ctls = alsaHalCtlsMap, +}; + +/*********************************************************************************** + * AlsaHalSndT provides + * - cardname used to map a given card to its HAL + * - ctls previously defined AlsaHalMapT control maps + * - info free text + * + * WARNING: name should fit with 'aplay -l' as it used to map from devid to HAL + * you may also retreive shortname when AudioBinder is running from a browser + * http://localhost:1234/api/alsacore/getcardid?devid=hw:xxx + * + ***********************************************************************************/ +PUBLIC struct afb_binding alsaHalBinding = { + /* description conforms to VERSION 1 */ + .type= AFB_BINDING_VERSION_1, + .v1= { + .prefix= "intel-hda", + .info = "Hardware Abstraction Layer for IntelHDA sound card", + } +}; + + diff --git a/AlsaSound/HALayer/Shared/CMakeLists.txt b/AlsaSound/HALayer/Shared/CMakeLists.txt new file mode 100644 index 0000000..27d93e0 --- /dev/null +++ b/AlsaSound/HALayer/Shared/CMakeLists.txt @@ -0,0 +1,30 @@ +########################################################################### +# 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. +########################################################################### + + +INCLUDE_DIRECTORIES(${include_dirs}) + +################################################## +# Shared HAL(Hardware Abstraction Layer) +################################################## +ADD_LIBRARY(shared-hal MODULE SharedHalLib.c) + +TARGET_LINK_LIBRARIES(shared-hal ${link_libraries}) +INSTALL(TARGETS shared-hal LIBRARY DESTINATION ${binding_install_dir}) + + diff --git a/AlsaSound/HALayer/Shared/SharedHalLib.c b/AlsaSound/HALayer/Shared/SharedHalLib.c new file mode 100644 index 0000000..ffa25e0 --- /dev/null +++ b/AlsaSound/HALayer/Shared/SharedHalLib.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2016 "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. + * + * reference: + * amixer contents; amixer controls; + * http://www.tldp.org/HOWTO/Alsa-sound-6.html + */ +#define _GNU_SOURCE // needed for vasprintf +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> +#include <fcntl.h> +#include <math.h> +#include <sys/time.h> +#include <sys/types.h> + +#include <json-c/json.h> +#include <afb/afb-binding.h> +#include <afb/afb-service-itf.h> + +#include "MiscHelpers.h" +#include "AlsaHalIface.h" + +typdef struct { + int numid; +} shareHallMap_T; + +static struct afb_service srvitf; +static const struct afb_binding_interface *afbIface; +static shareHallMap_T *shareHallMap; + + +STATIC void localping(struct afb_req request) { + json_object *query = afb_req_json(request); + afb_req_success(request, query, NULL); +} + +// This callback when api/alsacore/subscribe 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) { + 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; + } + + // 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 +STATIC void halMonitor(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); + + // 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); + + // success/failure messages return from callback +} + +// Subscribe to AudioBinding events +STATIC void halSubscribe (struct afb_req request) { + const char *devid = afb_req_value(request, "devid"); + if (devid == NULL) { + afb_req_fail_f (request, "devid-missing", "devid=hw:xxx missing"); + } +} + +// Call when all bindings are loaded and ready to accept request +STATIC void halGetVol(struct afb_req request) { + + // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card + afb_req_success (request, NULL, NULL); + return; + +} + +STATIC void halSetVol(struct afb_req request) { + const char *arg; + const char *pcm; + + arg = afb_req_value(request, "vol"); + if (arg == NULL) { + afb_req_fail_f (request, "argument-missing", "vol=[0,100] missing"); + goto OnErrorExit; + } + + pcm = afb_req_value(request, "pcm"); + if (pcm == NULL) pcm="Master"; + + // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card + afb_req_success (request, NULL, NULL); + return; + + OnErrorExit: + return; + +} + +// this is call when after all bindings are loaded +STATIC int halGetControl(struct afb_service service) { + srvitf = service; + struct json_object *queryin, *queryout, *ctls, *devid; + + // get query from request + queryin = afb_req_json(request); + + // check devid was given + devid= json_object_object_get(queryin,"devid"); + if (!ctls) { + afb_req_fail_f(request, "devid-notfound", "No DevID given query=[%s]", json_object_get_string(queryin)); + goto OnErrorExit; + } + + // loop on requested controls + ctls= json_object_object_get(queryin,"ctls"); + if (!ctls || json_object_array_length(ctls) <= 0) { + afb_req_fail_f(request, "ctls-notfound", "No Controls given query=[%s]", json_object_get_string(queryin)); + goto OnErrorExit; + } + + for (int idx=0; idx< json_object_array_length(ctls), idx++) { + struct json_object *ctl; + halControlEnumT control; + int value; + + // each controls should be halControlEnumT+value + ctl = json_object_array_get_idx(ctls, idx); + if (json_object_array_length(ctl != 2)) { + afb_req_fail_f(request, "ctl-invalid", "Invalid Control devid=%s ctl=[%s]"json_object_get_string(devid), json_object_get_string(cls)); + goto OnErrorExit; + } + + // As HAL and Business logic use the same AlsaMixerHal.h direct conversion is not an issue + control = (halControlEnumT)json_object_get_int(json_object_array_get_idx(ctl,0)); + value = json_object_get_int(json_object_array_get_idx(ctl,0)); + + if (control >= EndHalCrlTag || control <= StartHalCrlTag) { + afb_req_fail_f(request, "ctl-invalid", "Invalid Control devid=%s ctl=[%s] should be [%d=%d]" + , json_object_get_string(devid), json_object_get_string(cls)), StartHalCrlTag, EndHalCrlTag; + goto OnErrorExit; + } + + + default: + NOTICE (afbIface, "audioLogicOpenCB2 unknown HAL control=[%s]", json_object_get_string(ctl)): + } + } + + + // register HAL with Alsa Low Level Binder devid=hw:0&numid=1&quiet=0 + queryurl=json_object_new_object(); + json_object_object_add(queryurl, "prefix",json_object_new_string(alsaHalBinding.v1.prefix)); + json_object_object_add(queryurl, "name" ,json_object_new_string(alsaHalSndCard.name)); + afb_service_call(srvitf, "alsacore", "registerHal", queryurl, halGetControlCB, queryurl); + + + afb_req_success (request, sndctrls, NULL); + return; + +OnErrorExit: + +}; + +STATIC void halInitCB (void *handle, int iserror, struct json_object *result) { + struct json_object *queryurl = (json_object*)handle; + + if (iserror) NOTICE (afbIface, "halInitCB: registration alsaHAL query=[%s] Fail", json_object_to_json_string(queryurl)); + else DEBUG(afbIface, "halInitCB: registration alsaHAL card=[%s] Success", json_object_to_json_string(queryurl)); +} + +// 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) { + srvitf = service; + struct json_object *queryurl; + + // API prefix is used as sndcard halname + alsaHalBinding.v1.prefix= prefix; + + // register HAL with Alsa Low Level Binder + queryurl=json_object_new_object(); + json_object_object_add(ctx->queryurl, "prefix",json_object_new_string(alsaHalBinding.v1.prefix)); + json_object_object_add(ctx->queryurl, "name" ,json_object_new_string(alsaHalSndCard.name)); + afb_service_call(srvitf, "alsacore", "registerHal", queryurl, halInitCB, NULL); + + return 0; +}; + + +// Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT +STATIC const struct afb_verb_desc_v1 halSharedApi[] = { + /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ + { .name= "ping" , .session= AFB_SESSION_NONE, .callback= localping, .info= "Ping Binding" }, + { .name= "getcontrol", .session= AFB_SESSION_NONE, .callback= halGetControl,.info= "Get Control" }, + { .name= "setvolume", .session= AFB_SESSION_NONE, .callback= halSetVol, .info= "Set Volume" }, + { .name= "getvolume", .session= AFB_SESSION_NONE, .callback= halGetVol, .info= "Get Volume" }, + { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= halSubscribe, .info= "Subscribe AudioBinding Events" }, + { .name= NULL } /* marker for end of the array */ +}; + +// Process HAL mapping from alsaHalSndCardT before registering HAL binder +PUBLIC const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) { + int count; + afbIface= itf; // need to keep a static trace of binder interface for avances functions + alsaHalBinding.verbs=halSharedApi; // complete sndcard specific alsaHalBinding with standard HAL APIs + alsaHalCtlMapT *alsaHalCtls = MapalsaHalSndCard.alsaHalCtlsMap; // Get sndcard specific HAL control mapping + + if (alsaHalCtls == NULL) { + ERROR (afbIface, "afbBindingV1Register Fail alsaHalCtlsMap==NULL"); + return NULL; + } + + // Create a zone to store HAL high/low level mapping + shareHallMap = calloc (EndHalCrlTag * sizeof(shareHallMap_T)); + for (int idx= 0; alsaHalCtlsMap[idx].numid != 0; idx++) { + shareHallMap[alsaHalCtlsMap[idx].]->numid = alsaHalCtlsMap[idx].numid; + } + + return alsaHalBinding; /* returns the description of the binding */ +} diff --git a/AlsaSound/include/AlsaMixerHal.h b/AlsaSound/HALayer/include/AlsaHalCtls.h index 399f8ab..a17315a 100644 --- a/AlsaSound/include/AlsaMixerHal.h +++ b/AlsaSound/HALayer/include/AlsaHalCtls.h @@ -20,6 +20,7 @@ */ + #ifndef ALSAMIXERMAP_H #define ALSAMIXERMAP_H @@ -31,41 +32,26 @@ typedef enum { SWITCH, ROUTE, CARD, -} groupEnum; +} halGroupEnumT; typedef enum { READ, WRITE, RW, -} aclEnum; +} halAclEnumT; typedef enum { + StartHalCrlTag=0, + + // HighLevel Audio Control List Master_Playback_Volume, PCM_Playback_Volume, PCM_Playback_Switch, Capture_Volume, -} actionEnum; -typedef const struct { - actionEnum action; - int numid; - groupEnum group; - int values; - int minval; - int maxval; - int step; - char* info; - aclEnum acl; - -} AlsaHalMapT; + EndHalCrlTag // used to compute number of ctls +} halControlEnumT; -typedef struct { - const char *halname; - const char *longname; - const char *info; - AlsaHalMapT *ctls; - -} AlsaHalSndT; #endif /* ALSAMIXERMAP_H */ diff --git a/AlsaSound/HALayer/include/AlsaHalIface.h b/AlsaSound/HALayer/include/AlsaHalIface.h new file mode 100644 index 0000000..83ab57c --- /dev/null +++ b/AlsaSound/HALayer/include/AlsaHalIface.h @@ -0,0 +1,52 @@ +/* + * AlsaLibMapping -- provide low level interface with AUDIO lib (extracted from alsa-json-gateway code) + * Copyright (C) 2015,2016,2017, 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. + */ + +#ifndef SHAREDHALLIB_H +#define SHAREDHALLIB_H + +#include <stdio.h> +#include <afb/afb-binding.h> + +#include "MiscHelpers.h" +#include "AlsaHalCtls.h" + +typedef const struct { + halControlEnumT control; + int numid; + halGroupEnumT group; + int values; + int minval; + int maxval; + int step; + char* info; + halAclEnumT acl; + +} alsaHalCtlMapT; + +typedef struct { + const char *prefix; + const char *name; + const char *info; + alsaHalCtlMapT *ctls; + +} alsaHalSndCardT; + +PUBLIC alsaHalSndCardT alsaHalSndCard; +PUBLIC struct afb_binding alsaHalBinding; + +#endif /* SHAREDHALLIB_H */ + diff --git a/AlsaSound/HardAbsLayer/IntelHda/IntelHdaLib.h b/AlsaSound/HALayer/include/MiscHelpers.h index edf9474..0181847 100644 --- a/AlsaSound/HardAbsLayer/IntelHda/IntelHdaLib.h +++ b/AlsaSound/HALayer/include/MiscHelpers.h @@ -15,9 +15,9 @@ * limitations under the License. */ +#ifndef MISCHELPER_H +#define MISCHELPER_H -// few coding convention -typedef int BOOL; #ifndef PUBLIC #define PUBLIC #endif @@ -27,23 +27,7 @@ typedef int BOOL; #ifndef TRUE #define TRUE 1 #endif -#define STATIC static - -#ifndef AUDIOLIBMAPPING_H -#define AUDIOLIBMAPPING_H +#define STATIC static -#include <json-c/json.h> -#include <afb/afb-binding.h> -#include <afb/afb-service-itf.h> - -// import from AlsaAfbBinding -extern const struct afb_binding_interface *afbIface; - -// import from AlsaAfbMapping -PUBLIC void intelHdaSetVol (struct afb_req request); -PUBLIC void intelHdaGetVol(struct afb_req request); -PUBLIC void intelHdaSubscribe(struct afb_req request); -PUBLIC int intelHdaInit (struct afb_service service, const char *cardname); - -#endif /* AUDIOLIBMAPPING_H */ +#endif /* MISCHELPER_H */ diff --git a/AlsaSound/HardAbsLayer/IntelHda/IntelHdaBinding.c b/AlsaSound/HardAbsLayer/IntelHda/IntelHdaBinding.c deleted file mode 100644 index 0452314..0000000 --- a/AlsaSound/HardAbsLayer/IntelHda/IntelHdaBinding.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2016 "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 -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <netdb.h> -#include <fcntl.h> -#include <math.h> -#include <sys/time.h> -#include <sys/types.h> - -#include "IntelHdaLib.h" - -PUBLIC const struct afb_binding_interface *afbIface; - -STATIC void localping(struct afb_req request) { - json_object *query = afb_req_json(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= intelHdaSetVol, .info= "Set Volume" }, - { .name= "getvolume", .session= AFB_SESSION_NONE, .callback= intelHdaGetVol, .info= "Get Volume" }, - { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= intelHdaSubscribe, .info= "Subscribe AudioBinding Events" }, - { .name= NULL } /* marker for end of the array */ -}; - -/* - * description of the binding for afb-daemon - */ -STATIC const struct afb_binding binding_description = { - /* description conforms to VERSION 1 */ - .type= AFB_BINDING_VERSION_1, - .v1= { - .prefix= "intel-hda", - .info= "Hardware Abstraction Layer for IntelHDA sound card", - .verbs = binding_verbs - } -}; - -// 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 (intelHdaInit(service, binding_description.v1.prefix)); -}; - -/* - * activation function for registering the binding called by afb-daemon - */ -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/AlsaSound/HardAbsLayer/IntelHda/IntelHdaLib.c b/AlsaSound/HardAbsLayer/IntelHda/IntelHdaLib.c deleted file mode 100644 index ad4fcf4..0000000 --- a/AlsaSound/HardAbsLayer/IntelHda/IntelHdaLib.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2016 "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. - * - * reference: - * amixer contents; amixer controls; - * http://www.tldp.org/HOWTO/Alsa-sound-6.html - */ -#define _GNU_SOURCE // needed for vasprintf -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <netdb.h> -#include <fcntl.h> -#include <math.h> -#include <sys/time.h> -#include <sys/types.h> - -#include "IntelHdaLib.h" -#include "AlsaMixerHal.h" - -static struct afb_service srvitf; - -// Normalise Intel-HDA numid -static AlsaHalMapT alsaCtlsMap[]= { // check with amixer -D hw:xx controls; amixer -D "hw:3" cget numid=xx - /* ACTION(enum) NUMID(int) IFACE(enum) VALUES(int) MinVal(int) MaxVal(int) Step(int) ACL=READ|WRITE|RW INFO=comment */ - { .action=Master_Playback_Volume, .numid=16, .group=OUTVOL, .values=1, .minval=0, .maxval= 87 , .step=0, .acl=RW, .info= "Master Playback Volume" }, - { .action=PCM_Playback_Volume , .numid=27, .group=PCMVOL, .values=2, .minval=0, .maxval= 255, .step=0, .acl=RW, .info= "PCM Playback Volume" }, - { .action=PCM_Playback_Switch , .numid=17, .group=SWITCH, .values=1, .minval=0, .maxval= 1 , .step=0, .acl=RW, .info= "Master Playback Switch" }, - { .action=Capture_Volume , .numid=12, .group=INVOL , .values=2, .minval=0, .maxval= 31 , .step=0, .acl=RW, .info= "Capture Volume" }, - { .numid=0 } /* marker for end of the array */ -} ; - -// Warning: Longname is used to locate board on the system -static AlsaHalSndT alsaSndCard = { - .longname= "HDA Intel PCH", - .info = "Hardware Abstraction Layer for IntelHDA sound card", - .ctls = alsaCtlsMap, -}; - - -// 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) { - 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; - } - - // 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 intelHdaMonitor(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); - - // 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); - - // success/failure messages return from callback -} - -// Subscribe to AudioBinding events -PUBLIC void intelHdaSubscribe (struct afb_req request) { - const char *devid = afb_req_value(request, "devid"); - if (devid == NULL) { - afb_req_fail_f (request, "devid-missing", "devid=hw:xxx missing"); - } - -} - - -// Call when all bindings are loaded and ready to accept request -PUBLIC void intelHdaGetVol(struct afb_req request) { - - // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card - afb_req_success (request, NULL, NULL); - return; - -} - -PUBLIC void intelHdaSetVol(struct afb_req request) { - const char *arg; - char *pcm; - - arg = afb_req_value(request, "vol"); - if (arg == NULL) { - afb_req_fail_f (request, "argument-missing", "vol=[0,100] missing"); - goto ExitOnError; - } - - arg = afb_req_value(request, "pcm"); - if (arg == NULL) pcm="Master"; - - // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card - afb_req_success (request, NULL, NULL); - return; - - ExitOnError: - return; - -} - - -// this function is call after all binder are loaded and initialised -PUBLIC int intelHdaInit (struct afb_service service, const char *cardname) { - srvitf = service; - - // API prefix is used as sndcard halname - alsaSndCard.halname= cardname; - return 0; -}
\ No newline at end of file diff --git a/AudioLogic/AudioLogicBinding.c b/AudioLogic/AudioLogicBinding.c index 1220f29..0c63d00 100644 --- a/AudioLogic/AudioLogicBinding.c +++ b/AudioLogic/AudioLogicBinding.c @@ -26,7 +26,6 @@ #include <sys/time.h> #include <sys/types.h> -#include "AlsaMixerHal.h" #include "AudioLogicLib.h" PUBLIC const struct afb_binding_interface *afbIface; diff --git a/AudioLogic/AudioLogicLib.c b/AudioLogic/AudioLogicLib.c index 857cc9f..b45707a 100644 --- a/AudioLogic/AudioLogicLib.c +++ b/AudioLogic/AudioLogicLib.c @@ -27,15 +27,46 @@ #include <sys/types.h> #include "AudioLogicLib.h" + static struct afb_service srvitf; +STATIC int cbCheckResponse (struct afb_req request, int iserror, struct json_object *result) { + struct json_object *response, *status, *info; + + if (iserror) { // on error proxy information we got from lower layer + if (result) { + 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, "cbCheckFail", "No Result inside API response" ); + } + goto OnErrorExit; + } + + return (0); + + OnErrorExit: + return (1); +} + PUBLIC void audioLogicSetVol(struct afb_req request) { - + struct json_object *queryurl; + + // keep request for callback to respond + struct afb_req *handle = afb_req_store(request); + + // get client context + AudioLogicCtxT *ctx = afb_req_context_get(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; + goto OnExit; } switch (vol[0]) { @@ -48,34 +79,36 @@ PUBLIC void audioLogicSetVol(struct afb_req request) { default: afb_req_fail_f (request, "value-invalid", "volume should be (+-%[0-100]xxx) vol=%s", vol); - goto ExitOnError; + goto OnExit; + } + + if (!ctx->halapi) { + afb_req_fail_f(request, "context-invalid", "No valid halapi in client context"); + goto OnExit; } - // Should call here Hardware Alsa Abstraction Layer for corresponding Sound Card - afb_req_success (request, NULL, NULL); - return; + // ********** Caluler le volume en % de manière intelligente + + queryurl=json_object_new_object(); + json_object_object_add(ctx->queryurl, "pcm",json_object_new_int(Master_Playback_Volume)); + json_object_object_add(ctx->queryurl, "value",json_object_new_int(volume)); - ExitOnError: + // subcontract HAL API to process volume + afb_service_call(srvitf, ctx->halapi, "volume", queryurl, audioLogicSetVolCB, handle); + + // final success/failure messages handle from callback + OnExit: return; } // 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) { - 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; - } - - // push message respond - if (iserror) afb_req_fail_f(request, "Fail", info); - else afb_req_success(request, resp, info); + struct afb_req request = afb_req_unstore(handle); + + if (!cbCheckResponse (request, iserror, result)) goto OnExit + OnExit: + return; } // Create and subscribe to alsacore ctl events @@ -117,65 +150,150 @@ PUBLIC void audioLogicGetVol(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); +STATIC void audioLogicOpenCB2 (void *handle, int iserror, struct json_object *result) { struct json_object *response; - //INFO (afbIface, "result=[%s]\n", json_object_to_json_string (result)); - - - 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; - } + + // Make sure we got a response from API + struct afb_req request = afb_req_unstore(handle); + if (!cbCheckResponse (request, iserror, result)) 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); + if (!response) { + afb_req_fail_f(request, "response-notfound", "No Controls return from HAL/getcontrol devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; + } + + // get client context + AudioLogicCtxT *ctx = afb_req_context_get(request); + if (!ctx) { + afb_req_fail_f(request, "ctx-notfound", "No Client Context HAL/getcontrol devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; + } + + // extract sounds controls information from received Object + struct json_object *ctls; + json_object_object_get_ex(response, "ctls", &ctls); + if (!ctls) { + afb_req_fail_f(request, "ctls-notfound", "No Controls return from HAL/getcontrol devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; + } + + // make sure return controls have a valid type + if (json_object_get_type (ctls) != json_type_array ) { + afb_req_fail_f(request, "ctls-notarray", "Invalid Controls return from HAL/getcontrol devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; + } + + // loop on array and store values into client context + for (int idx=0; idx < json_object_array_length (ctls), idx++) { + struct json_object *ctl; + halControlEnumT control; + int value; - // 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)); + ctl = json_object_array_get_idx(ctls, idx); + if (json_object_array_length(ctl != 2)) { + afb_req_fail_f(request, "ctl-invalid", "Invalid Control return from HAL/getcontrol devid=[%] name=[%s] ctl=%s" + , ctx->devid, ctx->shortname, json_object_get_string(ctl)); + goto OnExit; + } - json_object_object_get_ex(response, "shortname", &subobj); - if (subobj)ctx->shortname=strdup(json_object_get_string(subobj)); + // As HAL and Business logic use the same AlsaMixerHal.h direct conversion is not an issue + control = (halControlEnumT)json_object_get_int(json_object_array_get_idx(ctl,0)); + value = json_object_get_int(json_object_array_get_idx(ctl,0)); - 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); + switch(control) { + case Master_Playback_Volume: + ctx->volumes.masterPlaybackVolume = value; + break; + + case PCM_Playback_Volume: + ctx->volumes.pcmPlaybackVolume = value; + break; + + case PCM_Playback_Switch: + ctx->volumes.pcmPlaybackSwitch = value; + break; - // 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)); + case Capture_Volume: + ctx->volumes.captureVolume = value; + break; + + default: + NOTICE (afbIface, "audioLogicOpenCB2 unknown HAL control=[%s]", json_object_get_string(ctl)): + } + } + + OnExit: + afb_req_context_set(request, ctx, free); + return; +} - afb_req_context_set(request, ctx, free); +// This callback is fired when afb_service_call for api/alsacore/subctl returns +STATIC void audioLogicOpenCB1 (void *handle, int iserror, struct json_object *result) { + struct json_object *response, *subobj; + + // Make sure we got a valid API response + struct afb_req request = afb_req_unstore(handle); + if (!cbCheckResponse (request, iserror, result)) goto OnExit + + // Get response from object + json_object_object_get_ex(result, "response", &response); + if (!response) { + afb_req_fail_f(request, "response-notfound", "No Controls return from HAL/getcontrol devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; } - // release original calling request - afb_req_success(request, response, NULL); + // 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, "halapi", &subobj); + if (subobj) ctx->halapi= 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)); + + // 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); + + // sound card was find let's store keycontrols into client session + if (!ctx->halapi) { + afb_req_fail_f(request, "hal-notfound", "No HAL found devid=[%] name=[%s]", ctx->devid, ctx->shortname); + goto OnExit; + } + struct json_object *queryurl =json_object_new_object(); + struct json_object *ctls =json_object_new_object(); + + // add sound controls we want to keep track of into client session context + json_object_object_add(ctls, json_object_new_int((int)Master_Playback_Volume)); + json_object_object_add(ctls, json_object_new_int((int)PCM_Playback_Volume)); + json_object_object_add(ctls, json_object_new_int((int)PCM_Playback_Switch)); + json_object_object_add(ctls, json_object_new_int((int)Capture_Volume)); + + // send request to soundcard HAL binding + json_object_array_add(queryurl, ctx->queryurl); + json_object_object_add(queryurl, "ctls",ctls); + afb_service_call(srvitf, ctx->halapi, "getControl", queryurl, audioLogicOpenCB2, handle); + + afb_req_success(request, response, NULL); + OnExit: + // release original calling request afb_req_unref(request); return; } @@ -186,7 +304,7 @@ 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); + else afb_service_call(srvitf, "alsacore", "getCardId", json_object_get(afb_req_json(request)), audioLogicOpenCB1, handle); } // Free client context create from audioLogicOpenCB @@ -200,7 +318,6 @@ PUBLIC void audioLogicClose (struct afb_req request) { // this function is call after all binder are loaded and initialised PUBLIC int audioLogicInit (struct afb_service service) { - srvitf = service; - + srvitf = service; return 0; } diff --git a/AudioLogic/AudioLogicLib.h b/AudioLogic/AudioLogicLib.h index 8530360..10e431d 100644 --- a/AudioLogic/AudioLogicLib.h +++ b/AudioLogic/AudioLogicLib.h @@ -36,6 +36,8 @@ typedef int BOOL; #include <afb/afb-binding.h> #include <afb/afb-service-itf.h> +#include "AlsaHalCtls.h" // Alsa Hardware Abstraction Layer Controls + // import from AlsaAfbBinding extern const struct afb_binding_interface *afbIface; @@ -48,6 +50,13 @@ typedef struct { const char *devid; const char *shortname; const char *longname; + const char *halapi; + struct { // volume in % [0-100] + int masterPlaybackVolume; + int pcmPlaybackVolume; + int pcmPlaybackSwitch; + int captureVolume; + } volumes; json_object *queryurl; } AudioLogicCtxT; diff --git a/CMakeLists.txt b/CMakeLists.txt index 56b5f09..006ff74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ ENDIF(CMAKE_BUILD_TYPE MATCHES Debug) SET(include_dirs ${INCLUDE_DIRS} - ${CMAKE_SOURCE_DIR}/AlsaSound/include + ${CMAKE_SOURCE_DIR}/AlsaSound/HALayer/include ${json-c_INCLUDE_DIRS} ${afb-daemon_INCLUDE_DIRS} ) diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 2da26c2..ee7b001 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -2,10 +2,11 @@ <configurationDescriptor version="100"> <logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT"> <df root="." name="0"> - <df name="Alsa"> - <df name="HardAbsLayer"> - <df name="Includes"> - <in>AlsaMixerHal.h</in> + <df name="AlsaSound"> + <df name="HALayer"> + <df name="include"> + <in>AlsaHalIface.h</in> + <in>MiscHelpers.h</in> </df> </df> </df> @@ -64,7 +65,15 @@ <preBuildFirst>true</preBuildFirst> </preBuild> </makefileType> - <item path="Alsa/Includes/AlsaMixerHal.h" ex="false" tool="3" flavor2="0"> + <item path="AlsaSound/HALayer/include/AlsaHalIface.h" + ex="false" + tool="3" + flavor2="0"> + </item> + <item path="AlsaSound/HALayer/include/MiscHelpers.h" + ex="false" + tool="3" + flavor2="0"> </item> <item path="MostVolume/DeviceContainer.cpp" ex="false" tool="1" flavor2="0"> </item> |