From 7dda5549b51ce1bbf674c620a5715986d7da4ffd Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Fri, 25 Aug 2017 01:10:00 +0200 Subject: Fix Initial Volume for Jabra --- Alsa-afb/Alsa-AddCtl.c | 8 +- Alsa-afb/Alsa-ApiHat.c | 8 +- Audio-Common/audio-common.c | 6 + Audio-Common/audio-common.h | 6 + HAL-afb/HAL-interface/hal-interface.c | 6 +- HAL-afb/HAL_MOST_UNICENS/hal_most_unicens.c | 2 +- HAL-afb/Jabra-Solemate/JabraUsbHAL.c | 20 +- conf.d/app-templates | 2 +- conf.d/cmake/config.cmake | 1 + conf.d/project/alsa.d/README.md | 175 ++ conf.d/project/alsa.d/asoundrc.sample | 8 +- conf.d/project/json.d/CMakeLists.txt | 32 + conf.d/project/json.d/README.md | 22 + conf.d/project/json.d/onload-aaaa-sample.json | 103 + conf.d/project/lua.d/CMakeLists.txt | 34 + conf.d/project/lua.d/onload-aaaa-00-utils.lua | 86 + conf.d/project/lua.d/onload-aaaa-01-init.lua | 48 + conf.d/project/lua.d/onload-aaaa-03-controls.lua | 118 ++ conf.d/project/lua.d/onload-aaaa-10-event.lua | 74 + htdocs/alsa-core.html | 20 +- htdocs/alsa-hal.html | 2 +- htdocs/audio-control.html | 25 +- nbproject/configurations.xml | 2182 +++++----------------- nbproject/project.xml | 20 +- 24 files changed, 1233 insertions(+), 1775 deletions(-) create mode 100644 conf.d/project/alsa.d/README.md create mode 100644 conf.d/project/json.d/CMakeLists.txt create mode 100644 conf.d/project/json.d/README.md create mode 100644 conf.d/project/json.d/onload-aaaa-sample.json create mode 100644 conf.d/project/lua.d/CMakeLists.txt create mode 100644 conf.d/project/lua.d/onload-aaaa-00-utils.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-01-init.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-03-controls.lua create mode 100644 conf.d/project/lua.d/onload-aaaa-10-event.lua diff --git a/Alsa-afb/Alsa-AddCtl.c b/Alsa-afb/Alsa-AddCtl.c index b9045f5..aaa9347 100644 --- a/Alsa-afb/Alsa-AddCtl.c +++ b/Alsa-afb/Alsa-AddCtl.c @@ -114,7 +114,7 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_objec if (done) ctlType = json_object_get_int(tmpJ); else ctlType = SND_CTL_ELEM_TYPE_INTEGER; - json_object_object_get_ex(ctlJ, "value", &tmpJ); + json_object_object_get_ex(ctlJ, "val", &tmpJ); ctlValue = json_object_get_int(tmpJ); // default for json_object_get_int is zero @@ -162,7 +162,11 @@ STATIC json_object * addOneSndCtl(afb_req request, snd_ctl_t *ctlDev, json_objec snd_ctl_elem_info_get_id(elemInfo, elemId); // If this is a hardware ctl only update value - if (ctlNumid != CTL_AUTO) goto UpdateDefaultVal; + if (ctlNumid != CTL_AUTO) { + json_object_object_get_ex(ctlJ, "val", &tmpJ); + ctlValue = json_object_get_int(tmpJ); + goto UpdateDefaultVal; + } count = snd_ctl_elem_info_get_count(elemInfo); min = (int) snd_ctl_elem_info_get_min(elemInfo); diff --git a/Alsa-afb/Alsa-ApiHat.c b/Alsa-afb/Alsa-ApiHat.c index bbb3959..e5172de 100644 --- a/Alsa-afb/Alsa-ApiHat.c +++ b/Alsa-afb/Alsa-ApiHat.c @@ -43,11 +43,11 @@ STATIC int AlsaInit(void) { static const struct afb_verb_v2 api_verbs[] = { /* VERB'S NAME FUNCTION TO CALL */ { .verb = "ping", .callback = pingtest, .info="Ping Presence Check on API"}, - { .verb = "getinfo", .callback = alsaGetInfo, .info="Return sound cards list"}, - { .verb = "getctl", .callback = alsaGetCtls, .info="Get one or many control values"}, - { .verb = "setctl", .callback = alsaSetCtls, .info="Set one control or more"}, + { .verb = "infoget", .callback = alsaGetInfo, .info="Return sound cards list"}, + { .verb = "ctlget", .callback = alsaGetCtls, .info="Get one or many control values"}, + { .verb = "ctlset", .callback = alsaSetCtls, .info="Set one control or more"}, { .verb = "subscribe", .callback = alsaEvtSubcribe, .info="subscribe to alsa events"}, - { .verb = "getcardid", .callback = alsaGetCardId, .info="get sound card id"}, + { .verb = "cardidget", .callback = alsaGetCardId, .info="get sound card id"}, { .verb = "halregister", .callback = alsaRegisterHal, .info="register a new HAL in alsacore"}, { .verb = "hallist", .callback = alsaActiveHal, .info="Get list of currently active HAL"}, { .verb = "ucmquery", .callback = alsaUseCaseQuery,.info="Use Case Manager Query"}, diff --git a/Audio-Common/audio-common.c b/Audio-Common/audio-common.c index b75cd9b..25629b5 100644 --- a/Audio-Common/audio-common.c +++ b/Audio-Common/audio-common.c @@ -37,6 +37,12 @@ PUBLIC const char *halCtlsLabels[] = { [Multimedia_Playback_Volume] = "Multimedia_Playback_Volume", [Navigation_Playback_Volume] = "Navigation_Playback_Volume", [Emergency_Playback_Volume] = "Emergency_Playback_Volume", + [Telephony_Playback_Volume] = "Telephony_Playback_Volume", + + [Multimedia_Playback_Switch] = "Multimedia_Playback_Switch", + [Navigation_Playback_Switch] = "Navigation_Playback_Switch", + [Emergency_Playback_Switch] = "Emergency_Playback_Switch", + [Telephony_Playback_Switch] = "Telephony_Playback_Switch", // Do not remove EndHalCrlTag [EndHalCrlTag] = NULL diff --git a/Audio-Common/audio-common.h b/Audio-Common/audio-common.h index 82ada36..7077eab 100644 --- a/Audio-Common/audio-common.h +++ b/Audio-Common/audio-common.h @@ -81,6 +81,12 @@ typedef enum { PCM_Playback_Switch, Capture_Volume, Master_OnOff_Switch, + Telephony_Playback_Volume, + Multimedia_Playback_Switch, + Navigation_Playback_Switch, + Emergency_Playback_Switch, + Telephony_Playback_Switch, + // Application Virtual Channels Multimedia_Playback_Volume, diff --git a/HAL-afb/HAL-interface/hal-interface.c b/HAL-afb/HAL-interface/hal-interface.c index ad5eabb..4a32d72 100644 --- a/HAL-afb/HAL-interface/hal-interface.c +++ b/HAL-afb/HAL-interface/hal-interface.c @@ -138,7 +138,7 @@ STATIC int halCallAlsaSetCtls(json_object *ctlsOutJ) { json_object_object_add(queryJ, "devid", json_object_new_string(halSndCard->devid)); json_object_object_add(queryJ, "ctl", ctlsOutJ); - err = afb_service_call_sync("alsacore", "setctl", queryJ, &responseJ); + err = afb_service_call_sync("alsacore", "ctlset", queryJ, &responseJ); json_object_put(responseJ); // let's ignore response return err; @@ -312,7 +312,7 @@ STATIC json_object *halCallAlsaGetCtls(json_object *ctlsOutJ) { json_object_object_add(queryJ, "devid", json_object_new_string(halSndCard->devid)); json_object_object_add(queryJ, "ctl", ctlsOutJ); - err = afb_service_call_sync("alsacore", "getctl", queryJ, &responseJ); + err = afb_service_call_sync("alsacore", "ctlget", queryJ, &responseJ); if (err) goto OnErrorExit; // Let ignore info data if any and keep on response @@ -518,7 +518,7 @@ PUBLIC int halServiceInit(const char *apiPrefix, alsaHalSndCardT *alsaHalSndCard if (halCtls[idx].ctl.step) json_object_object_add(ctlJ, "step", json_object_new_int(halCtls[idx].ctl.step)); if (halCtls[idx].ctl.type) json_object_object_add(ctlJ, "type", json_object_new_int(halCtls[idx].ctl.type)); if (halCtls[idx].ctl.count) json_object_object_add(ctlJ, "count", json_object_new_int(halCtls[idx].ctl.count)); - if (halCtls[idx].ctl.value) json_object_object_add(ctlJ, "value", json_object_new_int(halCtls[idx].ctl.value)); + if (halCtls[idx].ctl.value) json_object_object_add(ctlJ, "val", json_object_new_int(halCtls[idx].ctl.value)); if (halCtls[idx].ctl.dbscale) { json_object *dbscaleJ = json_object_new_object(); diff --git a/HAL-afb/HAL_MOST_UNICENS/hal_most_unicens.c b/HAL-afb/HAL_MOST_UNICENS/hal_most_unicens.c index 06fc0c1..5e29b59 100644 --- a/HAL-afb/HAL_MOST_UNICENS/hal_most_unicens.c +++ b/HAL-afb/HAL_MOST_UNICENS/hal_most_unicens.c @@ -87,7 +87,7 @@ __attribute__ ((unused)) static void unicens_request_card_values(const char* dev goto OnErrorExit; } - afb_service_call("alsacore", "getctl", j_query, + afb_service_call("alsacore", "ctlget", j_query, &unicens_request_card_values_cb, NULL); diff --git a/HAL-afb/Jabra-Solemate/JabraUsbHAL.c b/HAL-afb/Jabra-Solemate/JabraUsbHAL.c index 03d53d8..d3ddcfc 100644 --- a/HAL-afb/Jabra-Solemate/JabraUsbHAL.c +++ b/HAL-afb/Jabra-Solemate/JabraUsbHAL.c @@ -17,9 +17,9 @@ * * To find out which control your sound card uses * aplay -l # Check sndcard name name in between [] - * amixer -D hw:USB controls # get supported controls - * amixer -Dhw:USB cget name=Power-Switch - * amixer -Dhw:USB cset name=Power-Switch true + * amixer -D hw:v1340 controls # get supported controls + * amixer -Dhw:v1340 cget name=Power-Switch + * amixer -Dhw:v1340 cset name=Power-Switch true * */ #define _GNU_SOURCE @@ -63,8 +63,8 @@ STATIC halVolRampT volRampEmergency= { // Map HAL hight sndctl with Alsa numid and optionally with a custom callback for non Alsa supported functionalities. STATIC alsaHalMapT alsaHalMap[]= { - { .tag=Master_Playback_Volume, . ctl={.name="PCM Playback Volume" } }, - { .tag=PCM_Playback_Volume , .ctl={.name="PCM Playback Volume" } }, + { .tag=Master_Playback_Volume, . ctl={.name="PCM Playback Volume", .value=12 } }, + { .tag=PCM_Playback_Volume , .ctl={.name="PCM Playback Volume", .value=12 } }, { .tag=PCM_Playback_Switch , .ctl={.name="PCM Playback Switch" } }, { .tag=Capture_Volume , .ctl={.name="Mic Capture Volume" } }, @@ -74,17 +74,17 @@ STATIC alsaHalMapT alsaHalMap[]= { }, // Implement Rampup Volume for Virtual Channels - { .tag=Multimedia_Playback_Volume, .cb={.callback=volumeRamp, .handle=&volRampMultimedia}, .info="Rampup Multimedia Volume", - .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER, .name="Playback Multimedia Ramp"} - }, { .tag=Navigation_Playback_Volume, .cb={.callback=volumeRamp, .handle=&volRampNavigation}, .info="RampUp Navigation Volume", - .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER,.name="Playback Navigation Ramp"} + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER,.name="Playback Navigation Ramp", .value=80 } }, { .tag=Emergency_Playback_Volume, .cb={.callback=volumeRamp, .handle=&volRampEmergency}, .info="Rampup Emergency Volume", - .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER,.name="Playback Emergency Ramp"} + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER,.name="Playback Emergency Ramp", .value=80 } }, // Sound Card does not support hardware channel volume mixer (note softvol default range 0-256) + { .tag=Multimedia_Playback_Volume, .cb={.callback=volumeRamp, .handle=&volRampMultimedia}, .info="Ramp-up Multimedia Volume", + .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER, .name="Playback Multimedia Ramp", .value=80 } + }, { .tag=PCM_Volume_Multimedia, .info="Playback Multimedia Softvol", .ctl={.numid=CTL_AUTO, .type=SND_CTL_ELEM_TYPE_INTEGER, .count=2, .maxval=255, .value=200, .name="Playback Multimedia"} }, diff --git a/conf.d/app-templates b/conf.d/app-templates index 2e8abc4..cf98a0c 160000 --- a/conf.d/app-templates +++ b/conf.d/app-templates @@ -1 +1 @@ -Subproject commit 2e8abc421151b81272f7ab988e494fd29eb431ff +Subproject commit cf98a0c4992fe307b5fff068b8fa50dbb64561cd diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index e4b095b..82124dc 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -159,4 +159,5 @@ set(WIDGET_TYPE application/vnd.agl.service) # This include is mandatory and MUST happens at the end # of this file, else you expose you to unexpected behavior # ----------------------------------------------------------- + include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake) diff --git a/conf.d/project/alsa.d/README.md b/conf.d/project/alsa.d/README.md new file mode 100644 index 0000000..aa2a54e --- /dev/null +++ b/conf.d/project/alsa.d/README.md @@ -0,0 +1,175 @@ + +Alsa Configuration is not complex, but it's heavy and every except intuitive. + +In order to set your configuration move step by step. And verify at each new step that you did not introduce a regression. + +### Make sure your board is not taken by PulseAudio + +* Pavucontrol is your friend. Go in device configuration and switch to off the device you want to make available to ALSA. +* Check for your device list with 'play -l'. Note that just after card number your get an alias for your sound card. + it is simpler to use this alias, card number will change depending on plug/unplug of device when this alias name + is more stable (except for few stupid driver who use 'USB' as sound card name. +* When your know your sound alias (eg:v1340 in mu case) you can test it with 'speaker-test -D v1340 -c2 -twav'. You may also + use sound card number with 'speaker-test -D hw:0 -c2 -twav'. Nevertheless as said previously this number is not stable. +* you are now ready to write your $HOME/.asoundrc config + +Note that $HOME/.asoundrc is loaded within libasound client and not by Alsa kernel, this is the reason why you do not need +to activate any control or restart a daemon for modifications to be taken in account. + +To use ALSA with AAAA and the controller you need to write 1 section in your ALSA config + +* Sound Card Mixer: Allows multiple audio stream to be played on the same sound card. If hardware support mixer, Alsa will use it. If + not it will provide mixing by software. +* Audio Role Volume: They provide independent volume for each audio role. For reference, we use Alsa softvolume, depending on + your hardware you may have this directly avaliable from your sound card. +* Authorised Audio PCM: those channel are designed for applications we do not trust and then enforce AAAA control check + before granting the access to a given channel. + +### Sound Card Mixer + +``` +pcm.SoundCardMixer { + type dmix + ipc_key 1024 + ipc_key_add_uid false + ipc_perm 0666 # mixing for all users + + # Define target effective sound card (cannot be a plugin) + slave { pcm "hw:v1340" } #Jabra Solmate + + # DMIX can only map two channels + bindings { + 0 0 + 1 1 + } +} +``` + +Warning: if you have more than one Mixer each of them should have a unique ipc_key. You sound card alias move in the slave section. +When this is done you may try your mixer with: + +``` + speaker-test -D MyMixerPCM -c2 -twav +``` + + +### Audio Role + +``` +pcm.NavigationRole { + type softvol + + # Point Slave on HOOK for policies control + slave.pcm "SoundCardMixer" + + # name should match with HAL but do not set card=xx + control.name "Playback Navigation" + +} + +``` + +The slave you point to your SoundCardMixer, and the control.name should be EXACTLY the same as the one defined in your HAL. + + +WARNING: The control here "Playback Navigation" is a user defined kernel control. It means that this kernel is created in +kernel space, but that its action happen in user space. When create those control remains visible until you reset your +sound card (eg: unplug USB), but they are save each time you reboot. It is recommended to start AAAA binder before testing +your softvol audio role channel. If you do the opposite the control will be create by Alsa Plugin and this will not inherit +of the default value you have in your HAL. + +When in place you should test it with: +``` + speaker-test -D NavigationRole -c2 -twav +``` + +IMPORTANT: control volume are attache to your physical hardware and not to intermediary level (Softvol or Mixer). To see the +newly created channel you should use +``` + amixer -Dhw:v1340 controls | grep -i playback +``` + +## Authorised Audio PCM + +This PCM is supervised with the AAAA audio hook plugin. The pluging and will any application request on this PCM and will +1st request an autorisation from AAAA controller to grant access for the client application. To do so, two things: +* the plugin should be declared (only once) +* you should declare as many authorized PCM as you need. + +### Plugin declaration + +``` +pcm_hook_type.MyHookPlugin { + install "AlsaInstallHook" + lib "/home/fulup/Workspace/AGL-AppFW/audio-bindings-dev/build/Alsa-Plugin/Alsa-Policy-Hook/policy_hook_cb.so" +} + +``` + +Lib is the path where to find AAAA Alsa hook plugin, install is the name of the init function it should not be changed. + + +When your plugin is defined you may declare your authorised PCM. Those PCM like softvol will take a slave, typically a lower +level of the audio role, or directly a mixer if your goal is to protect directly the Mixer. The AAAA Plugin hook take as + +``` +pcm.AuthorisedToNavigationOnly { + type hooks + slave.pcm "NavigationRole" + # Defined used hook sharelib and provide arguments/config to install func + hooks.0 { + type "MyHookPlugin" + hook_args { + verbose true # print few log messages (default false); + + # Every Call should return OK in order PCM to open (default timeout 100ms) + uri "ws://localhost:1234/api?token=audio-agent-token&uuid=audio-agent-session" + request { + # Request autorisation to write on navigation + RequestNavigation { + api "control" + verb "dispatch" + query "{'target':'navigation', 'args':{'device':'Jabra SOLEMATE v1.34.0'}}" + } + } + # map event reception to self generated signal + event { + pause 30 + resume 31 + stop 3 + } + } + } +} + +``` + + * The slave is the PCM that application will be transfer to if access to control is granted. + * Request is a suite à control action that respond to AGL standard application framework API + * Event is the mapping of signal an appplication will receive in case AAAA controller push event to the audio application. + +When using AAAA controller, most action should be transfert to the controller that will take action to authorise/deny the access. +Nevertheless it is also possible to directly access a lower level (e.g. call alsa Use Case Manager). People may also have their +own audio policy engine and request it directly from here. + +To test this last part your need to have a controller ready to respond to your request. Otherwise control will systematically +be denied. When your AAAA controller is ready to serve your request you may check this with +``` + amixer -Dhw:AuthorisedToMusicOnly controls | grep -i playback + amixer -Dhw:AuthorisedToNavigationOnly controls | grep -i playback +``` + +IMPORTANT: you need at least to audio role to really test this part. While you may assert with one channel that your flow +to accept/deny application works. You need two simultaneous audio stream to really play with the control. Typically when playing +music if you send a navigation message then the audio will be lower during the rendering of the navigation message. + +The action on how you lower an audio role when an other one with a higger level of priority come in place not defined at the +plugin level, but in the AAAA controller, where the API control/dispatch?target=xxxxx will execute a set of actions corresponding +the set/unset accept/deny of requested control. + +Remark: to understand what is happening it is a good idea to have an alxamixer option on the your soundcard +``` + amixer -Dhw:v1340 +``` + +(!) Do not forget to replace 'hw:v1340' by what ever is the alias of your sound card. \ No newline at end of file diff --git a/conf.d/project/alsa.d/asoundrc.sample b/conf.d/project/alsa.d/asoundrc.sample index 8976077..0716b11 100644 --- a/conf.d/project/alsa.d/asoundrc.sample +++ b/conf.d/project/alsa.d/asoundrc.sample @@ -27,13 +27,7 @@ pcm.MyMixerPCM { ipc_perm 0666 # mixing for all users # Define target effective sound card (cannot be a plugin) - slave { - pcm "hw:v1340" #Jabra Solmate - period_time 0 - period_size 1024 - buffer_size 8192 - rate 44100 - } + slave { pcm "hw:v1340" } #Jabra Solmate # DMIX can only map two channels bindings { diff --git a/conf.d/project/json.d/CMakeLists.txt b/conf.d/project/json.d/CMakeLists.txt new file mode 100644 index 0000000..8070997 --- /dev/null +++ b/conf.d/project/json.d/CMakeLists.txt @@ -0,0 +1,32 @@ +########################################################################### +# Copyright 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# 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. +########################################################################### + + +################################################## +# Control Policy Config file +################################################## +PROJECT_TARGET_ADD(ctl-config.d) + + file(GLOB XML_FILES "*.json") + + add_input_files("${XML_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} + ) diff --git a/conf.d/project/json.d/README.md b/conf.d/project/json.d/README.md new file mode 100644 index 0000000..0f4967d --- /dev/null +++ b/conf.d/project/json.d/README.md @@ -0,0 +1,22 @@ +By default controller searches for a config filename with the same 'middlename' as daemon process. As an example if your process name is afb-daemon then middle name is 'daemon'. + +``` + onload-middlename-xxxxx.json + + # Middlename is taken from process middlename. +``` + +You may overload config search path with environement variables + * AFB_BINDER_NAME: change patern config search path. 'export AFB_BINDER_NAME=sample' will make controller to search for a configfile name 'onload-sample-xxx.json'. + * CONTROL_CONFIG_PATH: change default reserch path for configuration. You may provide multiple directories separated by ':'. + * CONTROL_LUA_PATH: same as CONTROL_CONFIG_PATH but for Lua script files. + +Example to load a config name 'onload-myconfig-test.json' do +``` + AFB_BINDER_NAME='myconfig' afb-daemon --verbose ...' +``` + +Note: you may change search pattern for Lua script by adding 'ctlname=afb-middlename-xxx' in the metadata section of your config 'onload-*.json' + +WARNING: Audio Control are the one from the HAL and not from Alsa LowLevel + diff --git a/conf.d/project/json.d/onload-aaaa-sample.json b/conf.d/project/json.d/onload-aaaa-sample.json new file mode 100644 index 0000000..c95a62f --- /dev/null +++ b/conf.d/project/json.d/onload-aaaa-sample.json @@ -0,0 +1,103 @@ +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-aaaa-control", + "info": "Sample of Video AAAA controls", + "name": "afb-sample-controller", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "require": ["alsacore","jabra-usb","intel-hda","hal-most-unicens"], + "actions": + { + "label": "control-init", + "lua": "_Audio_Controller_Init", + "args": { + "evtname": "agl-audio" + } + } + }], + "controls": + [ + { + "label": "Multimedia", + "permissions": "urn:AGL:permission:audio:public:multimedia", + "actions": { + "label": "authorize-multimedia", + "lua": "_Temporarily_Control" + } + }, { + "label": "Navigation", + "permissions": "urn:AGL:permission:audio:public:navigation", + "actions": { + "label": "authorize-navigation", + "lua": "_Temporarily_Control", + "args": { + "ctl" : "Multimedia_Playback_Volume", + "val": 40 + } + } + }, { + "label": "Telephony", + "permissions": "urn:AGL:permission:audio:public:telephony", + "actions": { + "label": "authorize-multimedia", + "lua": "_Temporarily_Control", + "args": { + "ctl" : "Multimedia_Playback_Volume", + "val": 20 + } + } + }, { + "label": "Emergency", + "permissions": "urn:AGL:permission:audio:public:emergency", + "actions": { + "label": "authorize-multimedia", + "lua": "_Temporarily_Control", + "args": { + "ctl" : "Multimedia_Playback_Switch", + "val": 0 + }, + "label": "authorize-multimedia", + "lua": "_Temporarily_Control", + "args": { + "ctl" : "Navigation_Playback_Switch", + "val": 0 + } + } + } + ], + "events": + [ + { + "label": "ReverseEngage", + "actions": [{ + "label": "adjust_volume-reverse", + "lua": "_Temporarily_Control", + "args": { + "ctl": "Multimedia_Playback_Volume", + "val": 20 + } + }, + { + "label": "prevent-telephony", + "lua": "_Temporarily_Control", + "args": { + "ctl": "Telephony_Playback_Switch", + "val": 0 + } + } + ] + }, + { + "label": "SpeedChanged", + "actions": { + "label": "adjust_volume", + "lua": "_Adjust_Volume" + } + } + ] +} + diff --git a/conf.d/project/lua.d/CMakeLists.txt b/conf.d/project/lua.d/CMakeLists.txt new file mode 100644 index 0000000..71b3371 --- /dev/null +++ b/conf.d/project/lua.d/CMakeLists.txt @@ -0,0 +1,34 @@ +########################################################################### +# Copyright 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# 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. +########################################################################### + + +################################################## +# Control Policy Config file +################################################## +PROJECT_TARGET_ADD(ctl-lua.d) + file(GLOB LUA_FILES "*.lua") + + # Romain work around to activate lua compilation + set(LUA_LIST "${LUA_FILES}" CACHE STRING "") + + add_input_files("${LUA_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} + ) \ No newline at end of file diff --git a/conf.d/project/lua.d/onload-aaaa-00-utils.lua b/conf.d/project/lua.d/onload-aaaa-00-utils.lua new file mode 100644 index 0000000..29d2c70 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-00-utils.lua @@ -0,0 +1,86 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + 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. + + Note: this file should be called before any other to assert declare function + is loaded before anything else. + + References: + http://lua-users.org/wiki/DetectingUndefinedVariables + +--]] + + +--=================================================== +--= Niklas Frykholm +-- basically if user tries to create global variable +-- the system will not let them!! +-- call GLOBAL_lock(_G) +-- +--=================================================== +function GLOBAL_lock(t) + local mt = getmetatable(t) or {} + mt.__newindex = lock_new_index + setmetatable(t, mt) +end + +--=================================================== +-- call GLOBAL_unlock(_G) +-- to change things back to normal. +--=================================================== +function GLOBAL_unlock(t) + local mt = getmetatable(t) or {} + mt.__newindex = unlock_new_index + setmetatable(t, mt) +end + +function lock_new_index(t, k, v) + if (string.sub(k,1,1) ~= "_") then + GLOBAL_unlock(_G) + error("GLOBALS are locked -- " .. k .. + " must be declared local or prefix with '_' for globals.", 2) + else + rawset(t, k, v) + end +end + +function unlock_new_index(t, k, v) + rawset(t, k, v) +end + +-- return serialised version of printable table +function Dump_Table(o) + if type(o) == 'table' then + local s = '{ ' + for k,v in pairs(o) do + if type(k) ~= 'number' then k = '"'..k..'"' end + s = s .. '['..k..'] = ' .. Dump_Table(v) .. ',' + end + return s .. '} ' + else + return tostring(o) + end +end + + +-- simulate C prinf function +printf = function(s,...) + io.write(s:format(...)) + io.write("\n") + return +end + +-- lock global variable +GLOBAL_lock(_G) diff --git a/conf.d/project/lua.d/onload-aaaa-01-init.lua b/conf.d/project/lua.d/onload-aaaa-01-init.lua new file mode 100644 index 0000000..8de0c24 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-01-init.lua @@ -0,0 +1,48 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + 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. +--]] + +-- Global variable SHOULD start with _ +_Global_Context={} + +--[[ + This function is call during controller init phase as describe in onload-daemon-sample.json + It receives two argument 1st one is the source (here on load) second one is the arguments + as expose in config file. + + In this sample we create an event that take the name of args["zzzz"], the resulting handle + is save into _Global_Context for further use. + + Note: init functions are not call from a client and thus do not receive query + +--]] +function _Audio_Controller_Init(source, control) + + printf ("[--> Audio_Controller_Init -->] source=%d control=%s", source, Dump_Table(control)) + + -- create an event from configuration name + _Global_Context["event"]=AFB:evtmake(control["evtname"]) + + -- query HAL to retrieve sound card. + local err,result= AFB:servsync ("alsacore", "hallist", {}) + + if (err) then + AFB_ERROR("Fail to retrieve Audio HAL") + else + _Global_Context["registry"]=result["response"] + printf("[<-- Audio_Controller_Init <--] Active HAL=%s", Dump_Table(result["response"])) + end +end diff --git a/conf.d/project/lua.d/onload-aaaa-03-controls.lua b/conf.d/project/lua.d/onload-aaaa-03-controls.lua new file mode 100644 index 0000000..6c7c8a5 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-03-controls.lua @@ -0,0 +1,118 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + 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. + + Following function are called when a control activate a label with + labeller api -> APi=label VERB=dispatch + arguments are + - source (0) when requesting the label (-1) when releasing + - label comme from config given with 'control' in onload-middlename-xxxxx.json + - control is the argument part of the query as providing by control requesting the label. + +--]] + +_CurrentHalVolume={} + + +local function Apply_Hal_Control(source, label, adjustment) + local HAL = _Global_Context["registry"] + + -- check we really got some data + if (adjustment == nil) then + AFB:error ("--* (Hoops) Control should provide volume adjustment") + return 1 + end + + -- loop on each HAL save current volume and push adjustment + for key,hal in pairs(_Global_Context["registry"]) do + printf ("--- HAL=%s", Dump_Table(hal)) + + -- action set loop on active HAL and get current volume + -- if label respond then do volume adjustment + if (source == 0) then + + -- get current volume for each HAL + local err,result= AFB:servsync(hal["api"],"ctlget", {["label"]=label}) + + -- if no error save current volume and set adjustment + if (err ~= nil) then + local response= result["response"] + printf ("--- Response %s=%s", hal["api"], Dump_Table(response)) + + if (response == nil) then + printf ("--- Fail to Activate '%s'='%s' result=%s", hal["api"], label, Dump_Table(result)) + return 1 -- unhappy + end + + -- save response in global space + _CurrentHalVolume [hal["api"]] = response + + -- finally set the new value + local query= { + ["tag"]= response["tag"], + ["val"]= adjustment + } + + -- best effort to set adjustment value + AFB:servsync(hal["api"],"ctlset",query) + end + + else -- when label is release reverse action at preempt time + + if (_CurrentHalVolume [hal["api"]] ~= nil) then + + printf("--- Restoring initial volume HAL=%s Control=%s", hal["api"], _CurrentHalVolume [hal["api"]]) + + AFB:servsync(hal["api"],"ctlset", _CurrentHalVolume [hal["api"]]) + end + end + + end + return 0 -- happy end +end + + +-- Simple Happy(granted) Control +function _Temporarily_Control(source, control, client) + + printf ("[--> _Temporarily_Control -->] source=%d control=%s client=%s", source, Dump_Table(control), Dump_Table(client)) + + -- Init should have been properly done + if (_Global_Context["registry"] == nil) then + AFB:error ("--* (Hoops) No Hal in _Global_Context=%s", Dump_Table(_Global_Context)) + return 1 + end + + -- make sure label as valid + if (control["ctl"] == nil or control["val"] == nil) then + AFB:error ("--* Action Ignore no/invalid control=%s", Dump_Table(control)) + return 1 -- unhappy + end + + if (source == 0) then + AFB:info("-- Adjust %s=%d", control["ctl"], control["val"]) + local error=Apply_Hal_Control(source, control["ctl"], control["val"]) + if (error == nil) then + return 1 -- unhappy + end + AFB:notice ("[<-- _Temporarily_Control Granted<--]") + else + Apply_Hal_Control(source, control["ctl"],0) + AFB:notice ("[<-- _Temporarily_Control Restore--]") + end + + return 0 -- happy return +end + diff --git a/conf.d/project/lua.d/onload-aaaa-10-event.lua b/conf.d/project/lua.d/onload-aaaa-10-event.lua new file mode 100644 index 0000000..474ebe0 --- /dev/null +++ b/conf.d/project/lua.d/onload-aaaa-10-event.lua @@ -0,0 +1,74 @@ +--[[ + Copyright (C) 2016 "IoT.bzh" + Author Fulup Ar Foll + + 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. + + + Provide Sample Timer Handing to push event from LUA +--]] + +-- Create event on Lua script load +_MyContext={} + +-- WARNING: call back are global and should start with '_' +function _Timer_Test_CB (timer, context) + + local evtinfo= AFB:timerget(timer) + printf ("[-- _Timer_Test_C --] evtInfo=%s", Dump_Table(evtinfo)) + + --send an event an event with count as value + AFB:evtpush (_MyContext["event"], {["label"]= evtinfo["label"], ["count"]=evtinfo["count"], ["info"]=context["info"]}) + + -- note when timerCB return!=0 timer is kill + return 0 + +end + +-- sendback event depending on count and delay +function _Simple_Timer_Test (request, client) + + local context = { + ["info"]="My 1st private Event", + } + + -- if event does not exit create it now. + if (_MyContext["event"] == nil) then + _MyContext["event"]= AFB:evtmake(client["label"]) + end + + -- if delay not defined default is 5s + if (client["delay"]==nil) then client["delay"]=5000 end + + -- if count is not defined default is 10 + if (client["count"]==nil) then client["count"]=10 end + + -- we could use directly client but it is a sample + local myTimer = { + ["label"]=client["label"], + ["delay"]=client["delay"], + ["count"]=client["count"], + } + AFB:notice ("Test_Timer myTimer=%s", myTimer) + + -- subscribe to event + AFB:subscribe (request, _MyContext["event"]) + + -- settimer take a table with delay+count as input (count==0 means infinite) + AFB:timerset (myTimer, "_Timer_Test_CB", context) + + -- nothing special to return send back + AFB:success (request, myTimer) + + return 0 +end diff --git a/htdocs/alsa-core.html b/htdocs/alsa-core.html index ff17fd1..261599a 100644 --- a/htdocs/alsa-core.html +++ b/htdocs/alsa-core.html @@ -10,14 +10,14 @@ - +

Selected SndCard Select NUMID - @@ -32,17 +32,17 @@
    -
  1. -
  2. -
  3. +
  4. +
  5. +

  6. -
  7. -
  8. -
  9. -
  10. -
  11. +
  12. +
  13. +
  14. +
  15. +

  16. diff --git a/htdocs/alsa-hal.html b/htdocs/alsa-hal.html index 5909c2b..f41d37c 100644 --- a/htdocs/alsa-hal.html +++ b/htdocs/alsa-hal.html @@ -11,7 +11,7 @@

    Simple AlsaHAL tests

    - +

    Selected HAL diff --git a/htdocs/audio-control.html b/htdocs/audio-control.html index 964dc62..8216601 100644 --- a/htdocs/audio-control.html +++ b/htdocs/audio-control.html @@ -10,32 +10,13 @@

    Simple Audio Control Test

    - - -

    - Selected HAL - - - API Verbosity - -
    -
    - +
      -
    1. -
    2. +
    3. +

    4. -
    5. -
    6. -
    7. -