diff options
author | Fulup Ar Foll <fulup@iot.bzh> | 2018-05-17 21:43:24 +0200 |
---|---|---|
committer | Fulup Ar Foll <fulup@iot.bzh> | 2018-05-17 21:43:24 +0200 |
commit | 253df14bd84f535a54f4d12c95399899e1343c20 (patch) | |
tree | 16093cc86d2874afb3311124613e69e23e74acbc | |
parent | 29f5fc4e093b8793eaeeef056d0b998182269718 (diff) |
Initial version with dynamic APIs
19 files changed, 543 insertions, 247 deletions
diff --git a/app-controller-submodule b/app-controller-submodule -Subproject e8b0b3c3cc9b0453b88d1315822fda5963754ae +Subproject 7af94b8a6f953ed247815bf15049fe951817a21 diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index afba6b7..5f5bc23 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -131,8 +131,8 @@ list(APPEND link_libraries afb-helpers) set(CONTROL_SUPPORT_LUA 1) add_definitions(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}/package/lib/plugins:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib/plugins") -add_definitions(-DCONTROL_CONFIG_PATH="${CMAKE_BINARY_DIR}/package/etc:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/etc") -add_definitions(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/data") +add_definitions(-DCONTROL_CONFIG_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/etc:${CMAKE_BINARY_DIR}/package/etc:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/etc") +add_definitions(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/var") add_definitions(-DCTL_PLUGIN_MAGIC=987456123) add_definitions(-DUSE_API_DYN=1 -DAFB_BINDING_VERSION=dyn) diff --git a/conf.d/project/etc/4a-softmixer-config.json b/conf.d/project/etc/4a-softmixer-config.json deleted file mode 100644 index e67709f..0000000 --- a/conf.d/project/etc/4a-softmixer-config.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json", - "metadata": { - "uid": "Soft Mixer", - "version": "1.0", - "api": "softmixer", - "info": "Soft Mixer emulating hardware mixer" - }, - "resources": [ - { - "uid": "alsa-softmixer", - "info": "Map alsa-loop subdevices to 4A HAL streams", - "spath":"./plugins/alsa:../conf.d/project/lua.d", - "libs": ["alsa-router.ctlso", "softmixer-simple.lua"], - "lua": {"prefix":"smix","functions": ["snd_cards", "snd_zones", "snd_loops", "snd_streams"]} - } - ], - - "onload": [ - { - "uid": "init-soft-mixer", - "info": "Initialise Audio Router", - "action": "lua://alsa-softmixer#_init_softmixer_" - } - ], - - "controls": [ - { - "uid": "mixer-config", - "action": "lua://alsa-softmixer#_mixer_config_" - }, - { - "uid": "snd-cards", - "action": "plugin://alsa-softmixer#snd_cards" - }, - { - "uid": "snd-zone", - "action": "plugin://alsa-softmixer#snd_zones" - } - ] - -} diff --git a/conf.d/project/etc/4a-softmixer-test.json b/conf.d/project/etc/4a-softmixer-test.json new file mode 100644 index 0000000..f363a55 --- /dev/null +++ b/conf.d/project/etc/4a-softmixer-test.json @@ -0,0 +1,75 @@ +{ + "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json", + "metadata": { + "uid": "Soft Mixer", + "version": "1.0", + "api": "softmixer", + "info": "Soft Mixer emulating hardware mixer" + }, + "resources": [ + { + "uid": "softmixer", + "info": "Map alsa-loop subdevices to 4A HAL streams", + "spath": "./plugins/alsa:../conf.d/project/lua.d", + "libs": ["alsa-softmixer.ctlso", "softmixer-simple-test.lua"], + "lua": { + "prefix": "smix", + "functions": ["_mixer_new_"] + } + } + ], + + "onload": [ + { + "uid": "init-soft-mixer", + "info": "Initialise Audio Router", + "action": "lua://softmixer#_mixer_simple_test_" + } + ], + "controls": [ + { + "uid": "new", + "action": "plugin://softmixer#_mixer_new_", + "args": { + "devices": { + "playback": 0, + "capture": 1 + }, + "subdevs": [ + { + "subdev": 0, + "numid": 51 + }, + { + "subdev": 1, + "numid": 57 + }, + { + "subdev": 2, + "numid": 63 + }, + { + "subdev": 3, + "numid": 69 + }, + { + "subdev": 4, + "numid": 75 + }, + { + "subdev": 5, + "numid": 81 + }, + { + "subdev": 6, + "numid": 87 + }, + { + "subdev": 7, + "numid": 93 + } + ] + } + } + ] +} diff --git a/conf.d/project/lua.d/softmixer-simple.lua b/conf.d/project/lua.d/softmixer-simple-test.lua index e78eacd..6d6dffc 100644 --- a/conf.d/project/lua.d/softmixer-simple.lua +++ b/conf.d/project/lua.d/softmixer-simple-test.lua @@ -30,24 +30,14 @@ end -- Display receive arguments and echo them to caller -function _mixer_config_ (source, args) +function _mixer_simple_test_ (source, args) do local error local response - -- ==================== Default rate =========================== - - local audio_defaults = { - ["rate"] = 48000, - } - - -- ======================= Loop PCM =========================== - - local snd_aloop = { - ["uid"] = "Alsa-Loop", - ["devpath"] = "/dev/snd/by-path/platform-snd_aloop.0", + -- ================== Default Alsa snd-aloop numid and subdev config + local aloop = { ["devices"] = {["playback"]=0,["capture"]=1}, - ["params"] = audio_defaults, ["subdevs"] = { {["subdev"]= 0, ["numid"]= 51}, {["subdev"]= 1, ["numid"]= 57}, @@ -60,17 +50,23 @@ function _mixer_config_ (source, args) } } - error,response= smix:snd_loops (source, snd_aloop) - if (error ~= 0) then - AFB:error (source, "--InLua-- smix:snd_loops fail to attach sndcards=%s", Dump_Table(aloop)) - goto OnErrorExit - else - AFB:notice (source, "--InLua-- smix:snd_loops done response=%s\n", Dump_Table(response)) - end - + -- ==================== Default rate =========================== + + local audio_defaults = { + ["rate"] = 48000, + } + + -- ======================= Loop PCM =========================== + local snd_aloop = { + ["uid"] = "Alsa-Loop", + ["devpath"] = "/dev/snd/by-path/platform-snd_aloop.0", + ["params"] = audio_defaults, + ["devices"] = aloop.devices, + ["subdevs"] = aloop.subdevs, + } - -- ============================= Sound Cards =================== + -- ============================= Sound Cards =================== local snd_yamaha = { ["uid"]= "YAMAHA-APU70", ["devpath"]= "/dev/snd/by-id/usb-YAMAHA_Corporation_YAMAHA_AP-U70_USB_Audio_00-00", @@ -91,21 +87,8 @@ function _mixer_config_ (source, args) } } - -- group sound card as one multi channels card - local sndcards= { - snd_yamaha, - } - - error,response= smix:snd_cards (source, sndcards) - if (error ~= 0) then - AFB:error (source, "--InLua-- smix:snd_cards fail to attach sndcards=%s", Dump_Table(sndcards)) - goto OnErrorExit - else - AFB:notice (source, "--InLua-- smix:snd_cards done response=%s\n", Dump_Table(response)) - end -- ============================= Zones =================== - local zone_front= { ["uid"] = "front-seats", ["type"] = "playback", @@ -115,20 +98,7 @@ function _mixer_config_ (source, args) } } - local multi_zones = { - zone_front, - } - - error,response= smix:snd_zones (source, multi_zones) - if (error ~= 0) then - AFB:error (source, "--InLua-- smix:snd_zones fail to attach sndcards=%s", Dump_Table(multi_zones)) - goto OnErrorExit - else - AFB:notice (source, "--InLua-- smix:snd_zones done response=%s\n", Dump_Table(response)) - end - -- =================== Audio Stream ============================ - local stream_music= { ["uid"] = "multimedia", ["zone"] = "front-seats", @@ -143,20 +113,24 @@ function _mixer_config_ (source, args) ["mute"] = false, } - local snd_streams = { - stream_music, - stream_navigation, + --- ================ Create Mixer ========================= + local MyMixer= { + ["uid"]="Simple_Mixer", + ["backend"] = {snd_yamaha}, + ["frontend"]= {snd_aloop}, + ["zones"] = {zone_front}, + ["streams"] = {stream_music,stream_navigation}, } - error,response= smix:snd_streams (source, snd_streams) + local error,response= smix:_mixer_new_ (source, MyMixer) if (error ~= 0) then - AFB:error (source, "--InLua-- smix:snd_streams fail to attach sndcards=%s", Dump_Table(aloop)) + AFB:error (source, "--InLua-- smix:_mixer_new_ fail config=%s", Dump_Table(aloop)) goto OnErrorExit else - AFB:notice (source, "--InLua-- smix:streams_loops done response=%s\n", Dump_Table(response)) + AFB:notice (source, "--InLua-- smix:_mixer_new_ done response=%s\n", Dump_Table(response)) end - + -- ================== Happy End ============================= AFB:notice (source, "--InLua-- _mixer_config_ done") return 0 end @@ -166,16 +140,3 @@ function _mixer_config_ (source, args) AFB:error (source, "--InLua-- snd_attach fail") return 1 -- unhappy end -- end - --- Display receive arguments and echo them to caller -function _init_softmixer_ (source, args) - - printf ("*********** in print ") - -- create event to push change audio roles to potential listeners - _EventHandle=AFB:evtmake(source, "control") - - _mixer_config_ (source, args) - -end - -printf ("*********** load done ") diff --git a/mixer-binding/mixer-binding.c b/mixer-binding/mixer-binding.c index 7f199bc..fe4b284 100644 --- a/mixer-binding/mixer-binding.c +++ b/mixer-binding/mixer-binding.c @@ -56,7 +56,7 @@ STATIC int CtrlLoadStaticVerbs (afb_dynapi *apiHandle, AFB_ApiVerbs *verbs) { int errcount=0; for (int idx=0; verbs[idx].verb; idx++) { - errcount+= afb_dynapi_add_verb(apiHandle, CtrlApiVerbs[idx].verb, NULL, CtrlApiVerbs[idx].callback, (void*)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); + errcount+= afb_dynapi_add_verb(apiHandle, CtrlApiVerbs[idx].verb, CtrlApiVerbs[idx].info, CtrlApiVerbs[idx].callback, (void*)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); } return errcount; @@ -100,7 +100,8 @@ STATIC int CtrlLoadOneApi (void *cbdata, AFB_ApiT apiHandle) { // init API function (does not receive user closure ??? afb_dynapi_on_init(apiHandle, CtrlInitOneApi); - afb_dynapi_seal(apiHandle); + // should not seal API as each mixer+stream create a new verb + // afb_dynapi_seal(apiHandle); return err; OnErrorExit: diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 96a283e..812b398 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -26,10 +26,10 @@ </df> <df name="plugins"> <df name="alsa"> - <in>alsa-api-sndcards.c</in> - <in>alsa-api-sndloops.c</in> - <in>alsa-api-sndstreams.c</in> - <in>alsa-api-sndzones.c</in> + <in>alsa-api-backend.c</in> + <in>alsa-api-frontend.c</in> + <in>alsa-api-streams.c</in> + <in>alsa-api-zones.c</in> <in>alsa-capture.c</in> <in>alsa-core-ctl.c</in> <in>alsa-core-pcm.c</in> @@ -367,28 +367,28 @@ <cTool flags="1"> </cTool> </item> - <item path="plugins/alsa/alsa-api-sndcards.c" ex="false" tool="0" flavor2="2"> + <item path="plugins/alsa/alsa-api-backend.c" ex="false" tool="0" flavor2="2"> <cTool flags="0"> <incDir> <pElem>/usr/include/lua5.3</pElem> </incDir> </cTool> </item> - <item path="plugins/alsa/alsa-api-sndloops.c" ex="false" tool="0" flavor2="2"> + <item path="plugins/alsa/alsa-api-frontend.c" ex="false" tool="0" flavor2="2"> <cTool flags="0"> <incDir> <pElem>/usr/include/lua5.3</pElem> </incDir> </cTool> </item> - <item path="plugins/alsa/alsa-api-sndstreams.c" ex="false" tool="0" flavor2="2"> + <item path="plugins/alsa/alsa-api-streams.c" ex="false" tool="0" flavor2="2"> <cTool flags="0"> <incDir> <pElem>/usr/include/lua5.3</pElem> </incDir> </cTool> </item> - <item path="plugins/alsa/alsa-api-sndzones.c" ex="false" tool="0" flavor2="2"> + <item path="plugins/alsa/alsa-api-zones.c" ex="false" tool="0" flavor2="2"> <cTool flags="0"> <incDir> <pElem>/usr/include/lua5.3</pElem> diff --git a/plugins/alsa/CMakeLists.txt b/plugins/alsa/CMakeLists.txt index 51f4639..687ccb2 100644 --- a/plugins/alsa/CMakeLists.txt +++ b/plugins/alsa/CMakeLists.txt @@ -17,7 +17,7 @@ ########################################################################### -PROJECT_TARGET_ADD(alsa-router) +PROJECT_TARGET_ADD(alsa-softmixer) file(GLOB SOURCE_FILES "alsa-*.c") diff --git a/plugins/alsa/alsa-api-sndcards.c b/plugins/alsa/alsa-api-backend.c index daa996a..948d30d 100644 --- a/plugins/alsa/alsa-api-sndcards.c +++ b/plugins/alsa/alsa-api-backend.c @@ -38,16 +38,16 @@ OnErrorExit: } PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params) { - const char *format=NULL, *access=NULL; + const char *format = NULL, *access = NULL; // some default values - params->rate= ALSA_DEFAULT_PCM_RATE; - params->channels= 2; - params->sampleSize=0; + params->rate = ALSA_DEFAULT_PCM_RATE; + params->channels = 2; + params->sampleSize = 0; - int error = wrap_json_unpack(paramsJ, "{s?i,s?i, s?s, s?s !}", "rate",¶ms->rate,"channels", ¶ms->channels, "format",&format, "access",&access); + int error = wrap_json_unpack(paramsJ, "{s?i,s?i, s?s, s?s !}", "rate", ¶ms->rate, "channels", ¶ms->channels, "format", &format, "access", &access); if (error) goto OnErrorExit; - + if (!format) params->format = SND_PCM_FORMAT_S16_LE; else if (!strcasecmp(format, "S16_LE")) params->format = SND_PCM_FORMAT_S16_LE; else if (!strcasecmp(format, "S16_BE")) params->format = SND_PCM_FORMAT_S16_BE; @@ -69,8 +69,8 @@ PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *pa AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported format 'S16_LE|S32_L|...' format=%s", uid, format); goto OnErrorExit; } - - if (!access) params->access = SND_PCM_ACCESS_RW_INTERLEAVED; + + if (!access) params->access = SND_PCM_ACCESS_RW_INTERLEAVED; else if (!strcasecmp(access, "MMAP_INTERLEAVED")) params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED; else if (!strcasecmp(access, "MMAP_NONINTERLEAVED")) params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; else if (!strcasecmp(access, "MMAP_COMPLEX")) params->access = SND_PCM_ACCESS_MMAP_COMPLEX; @@ -78,7 +78,7 @@ PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *pa else if (!strcasecmp(access, "RW_NONINTERLEAVED")) params->access = SND_PCM_ACCESS_RW_NONINTERLEAVED; else { - AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s",uid, access); + AFB_ApiNotice(source->api, "ProcessSndParams:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s", uid, access); goto OnErrorExit; } @@ -89,11 +89,19 @@ OnErrorExit: } STATIC int ProcessOneSndCard(CtlSourceT *source, json_object *sndcardJ, AlsaPcmInfoT *snd) { - json_object *sinkJ=NULL, *paramsJ = NULL; + json_object *sinkJ = NULL, *paramsJ = NULL; int error; - error = wrap_json_unpack(sndcardJ, "{ss,s?s,s?s,s?i,s?i,s?i,so,s?o !}", "uid", &snd->uid, "devpath", &snd->devpath, "cardid", &snd->cardid - , "cardidx", &snd->cardidx, "device", &snd->device, "subdev", &snd->subdev, "sink", &sinkJ, "params", ¶msJ); + error = wrap_json_unpack(sndcardJ, "{ss,s?s,s?s,s?i,s?i,s?i,so,s?o !}" + , "uid", &snd->uid + , "devpath", &snd->devpath + , "cardid", &snd->cardid + , "cardidx", &snd->cardidx + , "device", &snd->device + , "subdev", &snd->subdev + , "sink", &sinkJ + , "params", ¶msJ + ); if (error || !snd->uid || !sinkJ || (!snd->devpath && !snd->cardid && snd->cardidx)) { AFB_ApiNotice(source->api, "ProcessOneSndCard missing 'uid|path|cardid|cardidx|channels|device|subdev|numid|params' devin=%s", json_object_get_string(sndcardJ)); goto OnErrorExit; @@ -106,10 +114,10 @@ STATIC int ProcessOneSndCard(CtlSourceT *source, json_object *sndcardJ, AlsaPcmI goto OnErrorExit; } } else { - snd->params.rate= ALSA_DEFAULT_PCM_RATE; - snd->params.access= SND_PCM_ACCESS_RW_INTERLEAVED; - snd->params.format=SND_PCM_FORMAT_S16_LE; - snd->params.channels=2; + snd->params.rate = ALSA_DEFAULT_PCM_RATE; + snd->params.access = SND_PCM_ACCESS_RW_INTERLEAVED; + snd->params.format = SND_PCM_FORMAT_S16_LE; + snd->params.channels = 2; } // check snd card is accessible @@ -157,54 +165,54 @@ OnErrorExit: return -1; } -CTLP_LUA2C(snd_cards, source, argsJ, responseJ) { - AlsaPcmInfoT *sndcards; - +PUBLIC int SndBackend(CtlSourceT *source, json_object *argsJ) { + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; int error; size_t count; + assert(mixerHandle); + + if (mixerHandle->backend) { + AFB_ApiError(source->api, "SndBackend: mixer=%s backend already declared %s", mixerHandle->uid, json_object_get_string(argsJ)); + goto OnErrorExit; + } + switch (json_object_get_type(argsJ)) { case json_type_object: count = 1; - sndcards = calloc(count + 1, sizeof (AlsaPcmInfoT)); - error = ProcessOneSndCard(source, argsJ, &sndcards[0]); + mixerHandle->backend = calloc(count + 1, sizeof (AlsaPcmInfoT)); + error = ProcessOneSndCard(source, argsJ, &mixerHandle->backend[0]); if (error) goto OnErrorExit; break; case json_type_array: count = json_object_array_length(argsJ); - sndcards = calloc(count + 1, sizeof (AlsaPcmInfoT)); + mixerHandle->backend = calloc(count + 1, sizeof (AlsaPcmInfoT)); for (int idx = 0; idx < count; idx++) { json_object *sndcardJ = json_object_array_get_idx(argsJ, idx); - error = ProcessOneSndCard(source, sndcardJ, &sndcards[idx]); + error = ProcessOneSndCard(source, sndcardJ, &mixerHandle->backend[idx]); if (error) goto OnErrorExit; } break; default: - AFB_ApiError(source->api, "L2C:sndcards: invalid argsJ= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndBackend: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } - // register Sound card and multi when needed - Softmixer->sndcardCtl = sndcards; if (count == 1) { - // only one sound card we multi would be useless - Softmixer->multiPcm = &sndcards[0]; + mixerHandle->multiPcm = &mixerHandle->backend[0]; } else { - AlsaPcmInfoT *pcmMulti; - + // instantiate an alsa multi plugin - pcmMulti = AlsaCreateMulti(source, "PcmMulti", 0); - if (!pcmMulti) goto OnErrorExit; + mixerHandle->multiPcm = AlsaCreateMulti(source, "PcmMulti", 0); + if (!mixerHandle->multiPcm) goto OnErrorExit; - Softmixer->multiPcm = pcmMulti; } - return 0; OnErrorExit: - AFB_ApiNotice(source->api, "L2C:sndcards fail to process: %s", json_object_get_string(argsJ)); + AFB_ApiNotice(source->api, "SndBackend mixer=%s fail to process: %s", mixerHandle->uid, json_object_get_string(argsJ)); return -1; } diff --git a/plugins/alsa/alsa-api-sndloops.c b/plugins/alsa/alsa-api-frontend.c index cf7bf55..c01a88b 100644 --- a/plugins/alsa/alsa-api-sndloops.c +++ b/plugins/alsa/alsa-api-frontend.c @@ -126,7 +126,7 @@ STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT * } break; default: - AFB_ApiError(source->api, "L2C:ProcessOneLoop=%s invalid subdevs= %s", loop->uid, json_object_get_string(subdevsJ)); + AFB_ApiError(source->api, "ProcessOneLoop=%s invalid subdevs= %s", loop->uid, json_object_get_string(subdevsJ)); goto OnErrorExit; } @@ -136,25 +136,42 @@ OnErrorExit: return -1; } -CTLP_LUA2C(snd_loops, source, argsJ, responseJ) { +PUBLIC int SndFrontend (CtlSourceT *source, json_object *argsJ) { + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; int error; - AlsaSndLoopT *sndLoop = calloc(1, sizeof (AlsaSndLoopT)); - - if (json_object_get_type(argsJ) != json_type_object) { - AFB_ApiError(source->api, "L2C:sndloops: invalid object type= %s", json_object_get_string(argsJ)); + assert (mixerHandle); + + if (mixerHandle->loop) { + AFB_ApiError(source->api, "SndFrontend: mixer=%s SndFrontend already declared %s", mixerHandle->uid, json_object_get_string(argsJ)); + goto OnErrorExit; + } + + mixerHandle->loop= calloc(1, sizeof (AlsaSndLoopT)); + + // or syntax purpose array is accepted but frontend should have a single driver entry + json_type type= json_object_get_type(argsJ); + if (type == json_type_array) { + size_t count= json_object_array_length(argsJ); + if (count != 1) { + AFB_ApiError(source->api, "SndFrontend: mixer=%s frontend only support on input driver args=%s", mixerHandle->uid, json_object_get_string(argsJ)); + goto OnErrorExit; + } + argsJ= json_object_array_get_idx(argsJ,0); + } + + type= json_object_get_type(argsJ); + if (type != json_type_object) { + AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object type= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } - error = ProcessOneLoop(source, argsJ, sndLoop); + error = ProcessOneLoop(source, argsJ, mixerHandle->loop); if (error) { - AFB_ApiError(source->api, "L2C:sndloops: invalid object= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } - // register routed into global softmixer handle - Softmixer->loopCtl = sndLoop; - return 0; OnErrorExit: diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c new file mode 100644 index 0000000..f1619c2 --- /dev/null +++ b/plugins/alsa/alsa-api-mixer.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 "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 // needed for vasprintf + +#include "alsa-softmixer.h" +#include <string.h> + +// Fulup need to be cleanup with new controller version +extern Lua2cWrapperT Lua2cWrap; + +// API + +static void MixerApiVerbCB(AFB_ReqT request) { + json_object *responseJ, *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL; + // retrieve action handle from request and execute the request + json_object *argsJ = afb_request_json(request); + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) afb_request_get_vcbdata(request); + int error; + int close = 0; + + CtlSourceT *source = alloca(sizeof (CtlSourceT)); + source->uid = mixerHandle->uid; + source->api = request->dynapi; + source->request = request; + source->context = mixerHandle; + + error = wrap_json_unpack(argsJ, "{s?b s?o,s?o,s?o,s?o !}" + , "close", &close + , "backend", &backendJ + , "frontend", &frontendJ + , "zones", &zonesJ + , "streams", &streamsJ + ); + if (error) { + AFB_ReqFailF(request, "MixerApiVerbCB", "missing 'uid|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + // Free attached resources and free mixer + if (close) { + AFB_ReqFailF(request, "MixerApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + if (backendJ) { + error = SndBackend(source, backendJ); + if (error) goto OnErrorExit; + } + + if (frontendJ) { + error = SndFrontend(source, frontendJ); + if (error) goto OnErrorExit; + } + + if (zonesJ) { + error = SndZones(source, zonesJ); + if (error) goto OnErrorExit; + } + + if (streamsJ) { + error = SndStreams(source, streamsJ, &responseJ); + if (error) goto OnErrorExit; + } + + + AFB_ReqSucess(request, responseJ, mixerHandle->uid); + return; + +OnErrorExit: + return; +} + +CTLP_LUA2C(_mixer_new_, source, argsJ, responseJ) { + SoftMixerHandleT *mixerHandle = calloc(1, sizeof (SoftMixerHandleT)); + json_object *backendJ = NULL, *frontendJ = NULL, *zonesJ = NULL, *streamsJ = NULL; + int error; + assert(source->api); + + if (json_object_get_type(argsJ) != json_type_object) { + AFB_ApiError(source->api, "_mixer_new_: invalid object type= %s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + error = wrap_json_unpack(argsJ, "{ss,s?s,s?o,s?o,s?o,s?o !}" + , "uid", &mixerHandle->uid + , "info", &mixerHandle->info + , "backend", &backendJ + , "frontend", &frontendJ + , "zones", &zonesJ + , "streams", &streamsJ); + if (error) { + AFB_ApiNotice(source->api, "_mixer_new_ missing 'uid|backend|frontend|zones|streams' mixer=%s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + // make sure string do not get deleted + mixerHandle->uid = strdup(mixerHandle->uid); + if (mixerHandle->info)mixerHandle->info = strdup(mixerHandle->info); + + // create mixer verb within API. + error = afb_dynapi_add_verb(source->api, mixerHandle->uid, mixerHandle->info, MixerApiVerbCB, mixerHandle, NULL, 0); + if (error) { + AFB_ApiError(source->api, "_mixer_new_ mixer=%s fail to register API verb", mixerHandle->uid); + return -1; + } + + // make sure sub command get access to mixer handle + source->context = mixerHandle; + + if (backendJ) { + error = SndBackend(source, backendJ); + if (error) goto OnErrorExit; + } + + if (frontendJ) { + error = SndFrontend(source, frontendJ); + if (error) goto OnErrorExit; + } + + if (zonesJ) { + error = SndZones(source, zonesJ); + if (error) goto OnErrorExit; + } + + if (streamsJ) { + error = SndStreams(source, streamsJ, responseJ); + if (error) goto OnErrorExit; + } + + return 0; + +OnErrorExit: + return -1; +}
\ No newline at end of file diff --git a/plugins/alsa/alsa-api-sndstreams.c b/plugins/alsa/alsa-api-streams.c index e55aeff..42d8ade 100644 --- a/plugins/alsa/alsa-api-sndstreams.c +++ b/plugins/alsa/alsa-api-streams.c @@ -29,6 +29,82 @@ // Fulup need to be cleanup with new controller version extern Lua2cWrapperT Lua2cWrap; +typedef struct { + const char* verb; + AlsaSndStreamT *streams; + SoftMixerHandleT *mixer; +} apiHandleT; + +static void StreamApiVerbCB(AFB_ReqT request) { + int close=0, error=0, quiet=0; + long volume=-1, mute=-1; + json_object *responseJ, *argsJ= afb_request_json(request); + apiHandleT *handle = (apiHandleT*) afb_request_get_vcbdata(request); + + CtlSourceT *source = alloca(sizeof (CtlSourceT)); + source->uid = handle->verb; + source->api = request->dynapi; + source->request = NULL; + source->context = NULL; + + error = wrap_json_unpack(argsJ, "{s?b s?b,s?b, s?i !}" + , "quiet", &quiet + , "close", &close + , "mute", &mute + , "volume", &volume + ); + if (error) { + AFB_ReqFailF(request, "StreamApiVerbCB", "Missing 'close|mute|volume|quiet' args=%s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + snd_ctl_t *ctlDev= AlsaCtlOpenCtl (source, handle->mixer->loop->cardid); + if (!ctlDev) { + AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to open sndcard=%s", handle->mixer->loop->cardid); + goto OnErrorExit; + } + + if (close) { + AFB_ReqFailF(request, "StreamApiVerbCB", "(Fulup) Close action still to be done mixer=%s", json_object_get_string(argsJ)); + goto OnErrorExit; + } + + if (volume != -1) { + error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, volume); + if (error) { + AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%ld", handle->streams->volume, volume); + goto OnErrorExit; + } + } + + if (mute != -1) { + error= AlsaCtlNumidSetLong (source, ctlDev, handle->streams->volume, !mute); + if (error) { + AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to set stream volume numid=%d value=%d", handle->streams->volume, !mute); + goto OnErrorExit; + } + } + + // if not in quiet mode return effective selected control values + if (quiet) responseJ=NULL; + else { + error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->volume, &volume); + error+= AlsaCtlNumidGetLong (source, ctlDev, handle->streams->mute, &mute); + if (error) { + AFB_ReqFailF(request, "StreamApiVerbCB", "Fail to get stream numids volume=%ld mute=%ld",volume, mute); + goto OnErrorExit; + } + wrap_json_pack (&responseJ,"{volume:si, mute:sb}", volume, mute); + } + + AFB_ReqSucess(request, responseJ, handle->verb); + return; + +OnErrorExit: + return; + +} + STATIC int ProcessOneStream(CtlSourceT *source, json_object *streamJ, AlsaSndStreamT *stream) { int error; json_object *paramsJ = NULL; @@ -36,11 +112,17 @@ STATIC int ProcessOneStream(CtlSourceT *source, json_object *streamJ, AlsaSndStr // Make sure default runs stream->volume = ALSA_DEFAULT_PCM_VOLUME; stream->mute = 0; - - error = wrap_json_unpack(streamJ, "{ss,ss,s?i,s?b,s?o !}", "uid", &stream->uid, "zone", &stream->zone, "volume", &stream->volume - , "mute", stream->mute, "params", ¶msJ); + stream->info = NULL; + + error = wrap_json_unpack(streamJ, "{ss,s?s,ss,s?i,s?b,s?o !}" + , "uid", &stream->uid + , "info", &stream->info + , "zone", &stream->zone + , "volume", &stream->volume + , "mute", stream->mute + , "params", ¶msJ); if (error) { - AFB_ApiNotice(source->api, "ProcessOneStream missing 'uid|zone|volume|rate|mute|params' stream=%s", json_object_get_string(streamJ)); + AFB_ApiNotice(source->api, "ProcessOneStream missing 'uid|[info]|zone|[volume]|[mute]|[params]' stream=%s", json_object_get_string(streamJ)); goto OnErrorExit; } @@ -67,16 +149,19 @@ OnErrorExit: return -1; } -CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { +PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **responseJ) { + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; AlsaSndStreamT *sndStream; int error; long value; size_t count; + assert(mixerHandle); + // assert static/global softmixer handle get requited info - AlsaSndLoopT *ctlLoop = Softmixer->loopCtl; + AlsaSndLoopT *ctlLoop = mixerHandle->loop; if (!ctlLoop) { - AFB_ApiError(source->api, "L2C:sndstreams: No Loop found [should register snd_loop first]"); + AFB_ApiError(source->api, "SndStreams: mixer=%s No Loop found [should register snd_loop first]", mixerHandle->uid); goto OnErrorExit; } @@ -86,7 +171,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { sndStream = calloc(count + 1, sizeof (AlsaSndStreamT)); error = ProcessOneStream(source, argsJ, &sndStream[0]); if (error) { - AFB_ApiError(source->api, "L2C:sndstreams: invalid stream= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndStreams: mixer=%s invalid stream= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } break; @@ -98,13 +183,13 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { json_object *sndStreamJ = json_object_array_get_idx(argsJ, idx); error = ProcessOneStream(source, sndStreamJ, &sndStream[idx]); if (error) { - AFB_ApiError(source->api, "sndstreams: invalid stream= %s", json_object_get_string(sndStreamJ)); + AFB_ApiError(source->api, "sndstreams: mixer=%s invalid stream= %s", mixerHandle->uid, json_object_get_string(sndStreamJ)); goto OnErrorExit; } } break; default: - AFB_ApiError(source->api, "L2C:sndstreams: invalid argsJ= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndStreams: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } @@ -116,10 +201,10 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { json_object *streamJ, *paramsJ; // Search for a free loop capture device - AFB_ApiNotice(source->api, "L2C:sndstreams stream=%s Start", (char*) sndStream[idx].uid); + AFB_ApiNotice(source->api, "SndStreams: mixer=%s stream=%s Start", mixerHandle->uid, (char*) sndStream[idx].uid); ctlLoop->scount--; if (ctlLoop->scount < 0) { - AFB_ApiError(source->api, "L2C:sndstreams no more subdev avaliable in loopback=%s", ctlLoop->uid); + AFB_ApiError(source->api, "SndStreams: mixer=%s stream=%s no more subdev avaliable in loopback=%s", mixerHandle->uid, sndStream[idx].uid, ctlLoop->uid); goto OnErrorExit; } @@ -144,7 +229,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { // Try to create/setup volume control. snd_ctl_t* ctlDev = AlsaCrlFromPcm(source, captureDev->handle); if (!ctlDev) { - AFB_ApiError(source->api, "AlsaCtlRegister [pcm=%s] fail attache sndcard", captureDev->cardid); + AFB_ApiError(source->api, "SndStreams: mixer=%s [pcm=%s] fail attache sndcard", mixerHandle->uid, captureDev->cardid); goto OnErrorExit; } @@ -163,9 +248,9 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { // create stream and delay pcm openning until vol control is created char volName[ALSA_CARDID_MAX_LEN]; snprintf(volName, sizeof (volName), "vol-%s", sndStream[idx].uid); - AlsaPcmInfoT *streamPcm = AlsaCreateStream(source, &sndStream[idx], captureDev, volName, VOL_CONTROL_MAX, 0); + AlsaPcmInfoT *streamPcm = AlsaCreateSoftvol(source, &sndStream[idx], captureDev, volName, VOL_CONTROL_MAX, 0); if (!streamPcm) { - AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to create stream", sndStream[idx].uid); + AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to create stream", mixerHandle->uid, sndStream[idx].uid); goto OnErrorExit; } @@ -179,14 +264,14 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { // snprintf(rateName, sizeof (rateName), "rate-%s", sndStream[idx].uid); // AlsaPcmInfoT *ratePcm= AlsaCreateRate(source, rateName, streamPcm, 1); // if (!ratePcm) { - // AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to create rate converter", sndStream[idx].uid); + // AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to create rate converter", sndStream[idx].uid); // goto OnErrorExit; // } // everything is not ready to open capture pcm error = snd_pcm_open(&streamPcm->handle, sndStream[idx].uid, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (error) { - AFB_ApiError(source->api, "L2C:sndstreams:%s(pcm) fail to open capture", sndStream[idx].uid); + AFB_ApiError(source->api, "SndStreams: mixer=%s%s(pcm) fail to open capture", mixerHandle->uid, sndStream[idx].uid); goto OnErrorExit; } @@ -204,7 +289,7 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { // toggle pause/resume (should be done after pcm_start) if ((error = snd_pcm_pause(captureDev->handle, !value)) < 0) { - AFB_ApiError(source->api, "L2C:sndstreams [capture=%s] fail to pause error=%s", captureDev->cardid, snd_strerror(error)); + AFB_ApiError(source->api, "SndStreams: mixer=%s [capture=%s] fail to pause error=%s", mixerHandle->uid, captureDev->cardid, snd_strerror(error)); goto OnErrorExit; } @@ -216,16 +301,36 @@ CTLP_LUA2C(snd_streams, source, argsJ, responseJ) { error += wrap_json_pack(&streamJ, "{ss ss si si so}", "uid", streamPcm->uid, "alsa", playbackDev->cardid, "volid", volNumid, "runid", runNumid, "params", paramsJ); error += json_object_array_add(*responseJ, streamJ); if (error) { - AFB_ApiError(source->api, "L2C:sndstreams:%s(stream) fail to prepare response", captureDev->cardid); + AFB_ApiError(source->api, "SndStreams: mixer=%s stream=%s fail to prepare response", mixerHandle->uid, captureDev->cardid); goto OnErrorExit; } + // create a dedicated verb for this stream compose of mixeruid/streamuid + apiHandleT *apiHandle = calloc(1, sizeof (apiHandleT)); + char apiVerb[128]; + error = snprintf(apiVerb, sizeof (apiVerb), "%s/%s", mixerHandle->uid, sndStream[idx].uid); + if (error == sizeof (apiVerb)) { + AFB_ApiError(source->api, "SndStreams mixer=%s fail to register Stream API too long %s/%s", mixerHandle->uid, mixerHandle->uid, sndStream[idx].uid); + return -1; + } + + apiHandle->mixer = mixerHandle; + apiHandle->streams = &sndStream[idx]; + apiHandle->verb = strdup(apiVerb); + error = afb_dynapi_add_verb(source->api, apiHandle->verb, sndStream[idx].info, StreamApiVerbCB, mixerHandle, NULL, 0); + if (error) { + AFB_ApiError(source->api, "SndStreams mixer=%s fail to register API verb=%s", mixerHandle->uid, apiHandle->verb); + return -1; + } + + // free tempry resource snd_ctl_close(ctlDev); + // Debug Alsa Config //AlsaDumpElemConfig (source, "\n\nAlsa_Config\n------------\n", "pcm"); //AlsaDumpPcmInfo(source, "\n\nPcm_config\n-----------\n", streamPcm->handle); - AFB_ApiNotice(source->api, "L2C:sndstreams:%s(stream) OK reponse=%s\n", streamPcm->uid, json_object_get_string(streamJ)); + AFB_ApiNotice(source->api, "SndStreams: mixer=%s stream=%s OK reponse=%s\n", mixerHandle->uid, streamPcm->uid, json_object_get_string(streamJ)); } return 0; diff --git a/plugins/alsa/alsa-api-sndzones.c b/plugins/alsa/alsa-api-zones.c index 7ca61ad..de834df 100644 --- a/plugins/alsa/alsa-api-sndzones.c +++ b/plugins/alsa/alsa-api-zones.c @@ -26,11 +26,11 @@ extern Lua2cWrapperT Lua2cWrap; STATIC int ProcessOneChannel(CtlSourceT *source, const char* uid, json_object *channelJ, AlsaPcmChannels *channel) { const char*channelUid; - + int error = wrap_json_unpack(channelJ, "{ss,si,s?i !}", "target", &channelUid, "channel", &channel->port); if (error) goto OnErrorExit; - - channel->uid=strdup(channelUid); + + channel->uid = strdup(channelUid); return 0; OnErrorExit: @@ -44,9 +44,13 @@ STATIC int ProcessOneZone(CtlSourceT *source, json_object *zoneJ, AlsaSndZoneT * const char* streamType; int error; - error = wrap_json_unpack(zoneJ, "{ss,s?s,so !}", "uid", &zone->uid, "type", &streamType, "mapping", &mappingJ); + error = wrap_json_unpack(zoneJ, "{ss,s?s,so !}" + , "uid", &zone->uid + , "type", &streamType + , "mapping", &mappingJ + ); if (error) { - AFB_ApiNotice(source->api, "ProcessOneone missing 'uid|type|mapping' zone=%s", json_object_get_string(zoneJ)); + AFB_ApiNotice(source->api, "ProcessOneZone missing 'uid|type|mapping' zone=%s", json_object_get_string(zoneJ)); goto OnErrorExit; } @@ -59,9 +63,9 @@ STATIC int ProcessOneZone(CtlSourceT *source, json_object *zoneJ, AlsaSndZoneT * goto OnErrorExit; } } - + // make sure remain valid even when json object is removed - zone->uid= strdup(zone->uid); + zone->uid = strdup(zone->uid); switch (json_object_get_type(mappingJ)) { case json_type_object: @@ -90,55 +94,63 @@ OnErrorExit: return -1; } -CTLP_LUA2C(snd_zones, source, argsJ, responseJ) { - AlsaSndZoneT *sndZone; +PUBLIC int SndZones(CtlSourceT *source, json_object *argsJ) { + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; + AlsaSndZoneT *zones=NULL; int error; size_t count; + assert(mixerHandle); + + if (mixerHandle->routes) { + AFB_ApiError(source->api, "SndZones: mixer=%s Zones already registered %s", mixerHandle->uid, json_object_get_string(argsJ)); + goto OnErrorExit; + } + switch (json_object_get_type(argsJ)) { case json_type_object: count = 1; - sndZone = calloc(count + 1, sizeof (AlsaSndZoneT)); - error = ProcessOneZone(source, argsJ, &sndZone[0]); + zones = calloc(count + 1, sizeof (AlsaSndZoneT)); + error = ProcessOneZone(source, argsJ, &zones[0]); if (error) { - AFB_ApiError(source->api, "L2C:sndzones: invalid zone= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } break; case json_type_array: count = json_object_array_length(argsJ); - sndZone = calloc(count + 1, sizeof (AlsaSndZoneT)); + zones = calloc(count + 1, sizeof (AlsaSndZoneT)); for (int idx = 0; idx < count; idx++) { json_object *sndZoneJ = json_object_array_get_idx(argsJ, idx); - error = ProcessOneZone(source, sndZoneJ, &sndZone[idx]); + error = ProcessOneZone(source, sndZoneJ, &zones[idx]); if (error) { - AFB_ApiError(source->api, "L2C:sndzones: invalid zone= %s", json_object_get_string(sndZoneJ)); + AFB_ApiError(source->api, "SndZones: mixer=%s invalid zone= %s", mixerHandle->uid, json_object_get_string(sndZoneJ)); goto OnErrorExit; } } break; default: - AFB_ApiError(source->api, "L2C:sndzones: invalid argsJ= %s", json_object_get_string(argsJ)); + AFB_ApiError(source->api, "SndZones: mixer=%s invalid argsJ= %s", mixerHandle->uid, json_object_get_string(argsJ)); goto OnErrorExit; } // register routed into global softmixer handle - Softmixer->zonePcms = calloc(count+1, sizeof (AlsaPcmInfoT*)); + mixerHandle->routes= calloc(count + 1, sizeof (AlsaPcmInfoT*)); // instantiate one route PCM per zone with multi plugin as slave - for (int idx = 0; sndZone[idx].uid != NULL; idx++) { - Softmixer->zonePcms[idx] = AlsaCreateRoute(source, &sndZone[idx], 0); - if (!Softmixer->zonePcms[idx]) { - AFB_ApiNotice(source->api, "L2C:sndzones fail to create route zone=%s", sndZone[idx].uid); + for (int idx = 0; zones[idx].uid != NULL; idx++) { + mixerHandle->routes[idx] = AlsaCreateRoute(source, &zones[idx], 0); + if (!mixerHandle->routes[idx]) { + AFB_ApiNotice(source->api, "SndZones: mixer=%s fail to create route zone=%s", mixerHandle->uid, zones[idx].uid); goto OnErrorExit; } } - // do not need this handle anymore - free (sndZone); + free (zones); return 0; OnErrorExit: + if (zones) free(zones); return -1; }
\ No newline at end of file diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c index 9a0b844..f224f92 100644 --- a/plugins/alsa/alsa-core-ctl.c +++ b/plugins/alsa/alsa-core-ctl.c @@ -170,6 +170,7 @@ OnErrorExit: return NULL; } + STATIC int CtlElemIdGetNumid(AFB_ApiT api, snd_ctl_t *ctlDev, snd_ctl_elem_id_t *elemId, int *numid) { snd_ctl_elem_info_t *elemInfo; diff --git a/plugins/alsa/alsa-plug-multi.c b/plugins/alsa/alsa-plug-multi.c index 3e82e1e..0dd417d 100644 --- a/plugins/alsa/alsa-plug-multi.c +++ b/plugins/alsa/alsa-plug-multi.c @@ -23,15 +23,17 @@ ALSA_PLUG_PROTO(multi); PUBLIC AlsaPcmInfoT* AlsaCreateMulti(CtlSourceT *source, const char *pcmUid, int open) { - + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; snd_config_t *multiConfig, *elemConfig, *slavesConfig, *slaveConfig, *bindingsConfig, *bindingConfig, *pcmConfig; int error = 0, channelIdx=0; AlsaPcmInfoT *pcmPlug = calloc(1, sizeof (AlsaPcmInfoT)); pcmPlug->uid = pcmUid; pcmPlug->cardid = pcmUid; - AlsaPcmInfoT* pcmSlaves=Softmixer->sndcardCtl; - if (!Softmixer->sndcardCtl) { + assert(mixerHandle); + + AlsaPcmInfoT* pcmSlaves=mixerHandle->backend; + if (!pcmSlaves) { AFB_ApiError(source->api, "AlsaCreateMulti: No Sound Card find [should register snd_cards first]"); goto OnErrorExit; } diff --git a/plugins/alsa/alsa-plug-route.c b/plugins/alsa/alsa-plug-route.c index 8fa5de8..d2ca223 100644 --- a/plugins/alsa/alsa-plug-route.c +++ b/plugins/alsa/alsa-plug-route.c @@ -48,17 +48,20 @@ OnErrorExit: } PUBLIC AlsaPcmInfoT* AlsaCreateRoute(CtlSourceT *source, AlsaSndZoneT *zone, int open) { - + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; snd_config_t *routeConfig, *elemConfig, *slaveConfig, *tableConfig, *pcmConfig; int error = 0; AlsaPcmInfoT *pcmPlug = calloc(1, sizeof (AlsaPcmInfoT)); pcmPlug->uid = zone->uid; pcmPlug->cardid = zone->uid; + + assert(mixerHandle); - AlsaPcmInfoT *pcmBackend = Softmixer->sndcardCtl; - AlsaPcmInfoT* pcmSlave=Softmixer->multiPcm; + AlsaPcmInfoT *pcmBackend = mixerHandle->backend; + AlsaPcmInfoT* pcmSlave=mixerHandle->multiPcm; if (!pcmBackend || !pcmSlave) { - AFB_ApiError(source->api, "AlsaCreateRoute:zone(%s)(zone) No Sound Card Ctl find [should register snd_cards first]", zone->uid); + AFB_ApiError(source->api, "AlsaCreateRoute: mixer=%s zone(%s)(zone) No Sound Card Ctl find [should register snd_cards first]" + , mixerHandle->uid, zone->uid); goto OnErrorExit; } diff --git a/plugins/alsa/alsa-plug-vol.c b/plugins/alsa/alsa-plug-vol.c index dc600f9..09bc51a 100644 --- a/plugins/alsa/alsa-plug-vol.c +++ b/plugins/alsa/alsa-plug-vol.c @@ -36,30 +36,32 @@ STATIC AlsaPcmInfoT* SlaveZoneByUid(CtlSourceT *source, AlsaPcmInfoT **pcmZones return NULL; } -PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open) { - +PUBLIC AlsaPcmInfoT* AlsaCreateSoftvol(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open) { + SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context; snd_config_t *streamConfig, *elemConfig, *slaveConfig, *controlConfig,*pcmConfig; int error = 0; AlsaPcmInfoT *pcmPlug= calloc(1,sizeof(AlsaPcmInfoT)); + assert (mixerHandle); + // assert static/global softmixer handle get requited info - AlsaSndLoopT *ctlLoop = Softmixer->loopCtl; + AlsaSndLoopT *ctlLoop = mixerHandle->loop; if (!ctlLoop) { - AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) No Loop found [should register snd_loop first]",stream->uid); + AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) No Loop found [should register snd_loop first]",stream->uid); goto OnErrorExit; } // assert static/global softmixer handle get requited info - AlsaPcmInfoT **pcmZones = Softmixer->zonePcms; + AlsaPcmInfoT **pcmZones = mixerHandle->routes; if (!pcmZones) { - AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) No Zone found [should register snd_zones first]", stream->uid); + AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) No Zone found [should register snd_zones first]", stream->uid); goto OnErrorExit; } // search for target zone uid AlsaPcmInfoT *pcmSlave= SlaveZoneByUid (source, pcmZones, stream->zone); if (!pcmSlave || !pcmSlave->uid) { - AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to find Zone=%s", stream->uid, stream->zone); + AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to find Zone=%s", stream->uid, stream->zone); goto OnErrorExit; } @@ -102,24 +104,24 @@ PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream if (open) error = _snd_pcm_softvol_open(&pcmPlug->handle, stream->uid, snd_config, streamConfig, SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK); if (error) { - AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to create Plug=%s Slave=%s error=%s", stream->uid, pcmPlug->cardid, pcmSlave->cardid, snd_strerror(error)); + AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to create Plug=%s Slave=%s error=%s", stream->uid, pcmPlug->cardid, pcmSlave->cardid, snd_strerror(error)); goto OnErrorExit; } error += snd_config_search(snd_config, "pcm", &pcmConfig); error += snd_config_add(pcmConfig, streamConfig); if (error) { - AFB_ApiError(source->api, "AlsaCreateStream:%s(stream) fail to add config", stream->uid); + AFB_ApiError(source->api, "AlsaCreateSoftvol:%s(stream) fail to add config", stream->uid); goto OnErrorExit; } // Debug config & pcm //AlsaDumpCtlConfig (source, "plug-stream", streamConfig, 1); - AFB_ApiNotice(source->api, "AlsaCreateStream:%s(stream) done\n", stream->uid); + AFB_ApiNotice(source->api, "AlsaCreateSoftvol:%s(stream) done\n", stream->uid); return pcmPlug; OnErrorExit: AlsaDumpCtlConfig(source, "plug-stream", streamConfig, 1); - AFB_ApiNotice(source->api, "AlsaCreateStream:%s(stream) OnErrorExit\n", stream->uid); + AFB_ApiNotice(source->api, "AlsaCreateSoftvol:%s(stream) OnErrorExit\n", stream->uid); return NULL; }
\ No newline at end of file diff --git a/plugins/alsa/alsa-softmixer.c b/plugins/alsa/alsa-softmixer.c index 033e87b..4528087 100644 --- a/plugins/alsa/alsa-softmixer.c +++ b/plugins/alsa/alsa-softmixer.c @@ -24,12 +24,9 @@ CTLP_LUA_REGISTER("alsa-softmixer") -SoftMixerHandleT *Softmixer; - // Call at initialisation time CTLP_ONLOAD(plugin, callbacks) { - AFB_ApiDebug(plugin->api, "SoftMixer plugin: uid='%s' 'info='%s'", plugin->uid, plugin->info); - Softmixer = calloc(1, sizeof(SoftMixerHandleT)); + AFB_ApiDebug(plugin->api, "SoftMixer Plugin Registered: uid='%s' 'info='%s'", plugin->uid, plugin->info); return NULL; } diff --git a/plugins/alsa/alsa-softmixer.h b/plugins/alsa/alsa-softmixer.h index e2c9370..7146e78 100644 --- a/plugins/alsa/alsa-softmixer.h +++ b/plugins/alsa/alsa-softmixer.h @@ -24,13 +24,14 @@ #include <afb/afb-binding.h> #include <systemd/sd-event.h> #include <json-c/json_object.h> -#include <stdio.h> #include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <alsa/asoundlib.h> #include "ctl-plugin.h" #include "wrap-json.h" -#include <alsa/asoundlib.h> #ifndef PUBLIC #define PUBLIC @@ -104,10 +105,9 @@ typedef struct { AlsaPcmInfoT *subdevs; } AlsaSndLoopT; - - typedef struct { const char *uid; + const char *info; const char *zone; int volume; int mute; @@ -116,23 +116,20 @@ typedef struct { } AlsaSndStreamT; typedef struct { - AlsaSndLoopT *loopCtl; - AlsaPcmInfoT *sndcardCtl; + const char *uid; + const char *info; + AlsaSndLoopT *loop; + AlsaPcmInfoT *backend; AlsaPcmInfoT *multiPcm; - AlsaPcmInfoT **zonePcms; + AlsaPcmInfoT **routes; } SoftMixerHandleT; -extern SoftMixerHandleT *Softmixer; - // alsa-utils-bypath.c PUBLIC snd_ctl_card_info_t* AlsaByPathInfo(CtlSourceT *source, const char *control); PUBLIC AlsaPcmInfoT* AlsaByPathOpenPcm(CtlSourceT *source, AlsaPcmInfoT *dev, snd_pcm_stream_t direction); PUBLIC snd_ctl_t *AlsaByPathOpenCtl(CtlSourceT *source, AlsaPcmInfoT *dev); PUBLIC int AlsaByPathDevid(CtlSourceT *source, AlsaPcmInfoT *dev); -// alsa-api-*.c -PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params); - // alsa-utils-dump.c PUBLIC void AlsaDumpFormats(CtlSourceT *source, snd_pcm_t *pcmHandle); PUBLIC char *AlsaDumpPcmUid(snd_pcm_t *pcmHandle, char *buffer, size_t len); @@ -168,7 +165,14 @@ PUBLIC int AlsaPcmCopy(CtlSourceT *source, AlsaPcmInfoT *pcmIn, AlsaPcmInfoT *pc PUBLIC AlsaPcmInfoT* AlsaCreateDmix(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave, int open); PUBLIC AlsaPcmInfoT* AlsaCreateMulti(CtlSourceT *source, const char *pcmName, int open); PUBLIC AlsaPcmInfoT* AlsaCreateRoute(CtlSourceT *source, AlsaSndZoneT *zone, int open); -PUBLIC AlsaPcmInfoT* AlsaCreateStream(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open); +PUBLIC AlsaPcmInfoT* AlsaCreateSoftvol(CtlSourceT *source, AlsaSndStreamT *stream, AlsaPcmInfoT *ctlControl, const char* ctlName, int max, int open); PUBLIC AlsaPcmInfoT* AlsaCreateRate(CtlSourceT *source, const char* pcmName, AlsaPcmInfoT *pcmSlave, int open); +// alsa-api-* +PUBLIC int ProcessSndParams(CtlSourceT *source, const char* uid, json_object *paramsJ, AlsaPcmHwInfoT *params); +PUBLIC int SndFrontend (CtlSourceT *source, json_object *argsJ); +PUBLIC int SndBackend (CtlSourceT *source, json_object *argsJ); +PUBLIC int SndZones (CtlSourceT *source, json_object *argsJ); +PUBLIC int SndStreams(CtlSourceT *source, json_object *argsJ, json_object **responseJ); + #endif
\ No newline at end of file |