From 241a06586b3602962874e6d2ac09e258ad6173d2 Mon Sep 17 00:00:00 2001 From: Manuel Bachmann Date: Wed, 16 Dec 2015 20:38:03 +0100 Subject: [PATCH] Initial Audio plugin Signed-off-by: Manuel Bachmann --- CMakeLists.txt | 8 +++-- README.md | 1 + include/proto-def.h | 5 ++- plugins/CMakeLists.txt | 8 +++-- plugins/audio/audio-alsa.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ plugins/audio/audio-alsa.h | 18 ++++++++++ plugins/audio/audio-api.c | 68 ++++++++++++++++++++++++++++---------- plugins/audio/audio-api.h | 26 +++++++++++++++ src/CMakeLists.txt | 3 ++ src/rest-api.c | 4 ++- 10 files changed, 196 insertions(+), 27 deletions(-) create mode 100644 plugins/audio/audio-alsa.c create mode 100644 plugins/audio/audio-alsa.h create mode 100644 plugins/audio/audio-api.h diff --git a/CMakeLists.txt b/CMakeLists.txt index af98b389..a3ab4c37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,8 +37,12 @@ PKG_CHECK_MODULES(json-c REQUIRED json-c) PKG_CHECK_MODULES(libmicrohttpd REQUIRED libmicrohttpd) PKG_CHECK_MODULES(uuid REQUIRED uuid) # Optional plugin dependencies +PKG_CHECK_MODULES(alsa alsa) PKG_CHECK_MODULES(librtlsdr librtlsdr>=0.5.0) +IF(alsa_FOUND) + MESSAGE(STATUS "ALSA found ; will compile Audio plugin... (PLUGIN)") +ENDIF(alsa_FOUND) IF(librtlsdr_FOUND) MESSAGE(STATUS "librtlsdr found ; will compile Radio plugin... (PLUGIN)") ENDIF(librtlsdr_FOUND) @@ -46,8 +50,8 @@ ENDIF(librtlsdr_FOUND) INCLUDE(FindThreads) FIND_PACKAGE(Threads) -SET(include_dirs ${INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/include ${json-c_INCLUDE_DIRS} ${libmicrohttpd_INCLUDE_DIRS} ${librtlsdr_INCLUDE_DIRS}) -SET(link_libraries ${json-c_LIBRARIES} ${libmicrohttpd_LIBRARIES} ${uuid_LIBRARIES} ${librtlsdr_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${libefence_LIBRARIES} -lmagic -lm) +SET(include_dirs ${INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/include ${json-c_INCLUDE_DIRS} ${libmicrohttpd_INCLUDE_DIRS} ${uuid_INCLUDE_DIRS} ${alsa_INCLUDE_DIRS} ${librtlsdr_INCLUDE_DIRS}) +SET(link_libraries ${json-c_LIBRARIES} ${libmicrohttpd_LIBRARIES} ${uuid_LIBRARIES} ${alsa_LIBRARIES} ${librtlsdr_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${libefence_LIBRARIES} -lmagic -lm) ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(plugins) diff --git a/README.md b/README.md index cb23e45c..5846f001 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ industry requirementsas the primary target for this code is AGL. optionally, for plugins : + * alsa ("libasound2-dev/alsa-devel"); * rtl-sdr >= 0.5.0 (fetch and build from "git://git.osmocom.org/rtl-sdr"); and the following tools: diff --git a/include/proto-def.h b/include/proto-def.h index fc3a9cfa..4241b4b9 100644 --- a/include/proto-def.h +++ b/include/proto-def.h @@ -34,10 +34,9 @@ void initPlugins (AFB_session *session); typedef AFB_plugin* (*AFB_pluginCB)(); PUBLIC AFB_plugin* tokenRegister (); -PUBLIC AFB_plugin* dbusRegister (); -PUBLIC AFB_plugin* alsaRegister (); -PUBLIC AFB_plugin* radioRegister (); +PUBLIC AFB_plugin* audioRegister (); PUBLIC AFB_plugin* helloWorldRegister (); +PUBLIC AFB_plugin* radioRegister (); // Session handling PUBLIC AFB_error sessionCheckdir (AFB_session *session); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 0ddaf453..76969380 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,11 +1,13 @@ -SET(AUDIO_PLUGIN audio/audio-api.c) SET(SESSION_PLUGIN session/token-api.c) SET(SAMPLE_PLUGINS samples/HelloWorld.c) +IF(alsa_FOUND) + SET(AUDIO_PLUGIN audio/audio-api.c audio/audio-alsa.c) +ENDIF(alsa_FOUND) IF(librtlsdr_FOUND) - SET(RADIO_PLUGIN radio/radio-rtlsdr.c radio/radio-api.c) + SET(RADIO_PLUGIN radio/radio-api.c radio/radio-rtlsdr.c) ENDIF(librtlsdr_FOUND) -SET(PLUGINS_SOURCES ${AUDIO_PLUGIN} ${SESSION_PLUGIN} ${RADIO_PLUGIN} ${SAMPLE_PLUGINS}) +SET(PLUGINS_SOURCES ${SESSION_PLUGIN} ${SAMPLE_PLUGINS} ${AUDIO_PLUGIN} ${RADIO_PLUGIN}) ADD_LIBRARY(plugins OBJECT ${PLUGINS_SOURCES}) INCLUDE_DIRECTORIES(${include_dirs}) diff --git a/plugins/audio/audio-alsa.c b/plugins/audio/audio-alsa.c new file mode 100644 index 00000000..8c08c8db --- /dev/null +++ b/plugins/audio/audio-alsa.c @@ -0,0 +1,82 @@ +#include "audio-api.h" +#include "audio-alsa.h" + +PUBLIC unsigned char _alsa_init (const char *name, audioCtxHandleT *ctx) { + + snd_pcm_t *dev; + snd_pcm_hw_params_t *params; + int num; + + if (snd_pcm_open (&dev, name, SND_PCM_STREAM_PLAYBACK, 0) < 0) + return 0; + + snd_pcm_hw_params_malloc (¶ms); + snd_pcm_hw_params_any (dev, params); + snd_pcm_hw_params_set_access (dev, params, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format (dev, params, SND_PCM_FORMAT_S16_LE); + snd_pcm_hw_params_set_rate_near (dev, params, &ctx->rate, 0); + snd_pcm_hw_params_set_channels (dev, params, ctx->channels); + if (snd_pcm_hw_params (dev, params) < 0) { + snd_pcm_hw_params_free (params); + return 0; + } + snd_pcm_prepare (dev); + + /* allocate the global array if it hasn't been done */ + if (!dev_ctx) { + dev_ctx = (dev_ctx_T**) malloc (sizeof(dev_ctx_T)); + dev_ctx[0] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T)); + dev_ctx[0]->name = NULL; + dev_ctx[0]->dev = NULL; + } + + /* is a card with similar name already opened ? */ + for (num = 0; num < (sizeof(dev_ctx)/sizeof(dev_ctx_T)); num++) { + if (dev_ctx[num]->name && + !strcmp (dev_ctx[num]->name, name)) + return 0; + } + num++; + + /* it's not... let us add it to the global array */ + dev_ctx[num] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T)); + dev_ctx[num]->name = strdup (name); + dev_ctx[num]->dev = dev; + dev_ctx[num]->params = params; + + return 1; +} + +PUBLIC void _alsa_free (const char *name) { + + int num; + + for (num = 0; num < (sizeof(dev_ctx)/sizeof(dev_ctx_T)); num++) { + if (dev_ctx[num]->name && + !strcmp (dev_ctx[num]->name, name)) { + snd_pcm_close (dev_ctx[num]->dev); + snd_pcm_hw_params_free (dev_ctx[num]->params); + free (dev_ctx[num]->name); + dev_ctx[num]->name = NULL; + dev_ctx[num]->dev = NULL; + free(dev_ctx[num]); + return; + } + } +} + +PUBLIC void _alsa_play (unsigned int num, void *buf, int len) { + + if (!dev_ctx || !dev_ctx[num]) + return; + + int16_t *cbuf = (int16_t *)buf; + int frames = len / 2; + int res; + + if ((res = snd_pcm_writei (dev_ctx[num]->dev, cbuf, frames)) != frames) { + snd_pcm_recover (dev_ctx[num]->dev, res, 0); + snd_pcm_prepare (dev_ctx[num]->dev); + } + /* snd_pcm_drain (dev_ctx[num]->dev); */ +} \ No newline at end of file diff --git a/plugins/audio/audio-alsa.h b/plugins/audio/audio-alsa.h new file mode 100644 index 00000000..a85f419d --- /dev/null +++ b/plugins/audio/audio-alsa.h @@ -0,0 +1,18 @@ +#ifndef AUDIO_ALSA_H +#define AUDIO_ALSA_H + +#include + +#include "local-def.h" + +typedef struct dev_ctx dev_ctx_T; + +struct dev_ctx { + char *name; + snd_pcm_t *dev; + snd_pcm_hw_params_t *params; +}; + +static struct dev_ctx **dev_ctx = NULL; + +#endif /* AUDIO_ALSA_H */ \ No newline at end of file diff --git a/plugins/audio/audio-api.c b/plugins/audio/audio-api.c index 9d4f3cb6..547f97ed 100644 --- a/plugins/audio/audio-api.c +++ b/plugins/audio/audio-api.c @@ -16,36 +16,68 @@ * along with this program. If not, see . */ +#include "audio-api.h" +#include "audio-alsa.h" -#include "local-def.h" -STATIC json_object* wrongApi (AFB_request *request, void* handle) { - int zero=0; - int bug=1234; - int impossible; +/* ------ LOCAL HELPER FUNCTIONS --------- */ + +/* private client context creation ; default values */ +STATIC audioCtxHandleT* initAudioCtx () { + + audioCtxHandleT *ctx; + + ctx = malloc (sizeof(audioCtxHandleT)); + ctx->volume = 25; + ctx->rate = 22050; + ctx->channels = 2; + + return ctx; +} + +/* called when client session dies [e.g. client quits for more than 15mns] */ +STATIC json_object* freeAudio (AFB_clientCtx *client) { + + //releaseAudio (client->plugin->handle, client->ctx); + free (client->ctx); - impossible=bug/zero; + return jsonNewMessage (AFB_SUCCESS, "Released radio and client context"); } +/* ------ PUBLIC PLUGIN FUNCTIONS --------- */ -STATIC struct { - void * somedata; -} handle; +STATIC json_object* init (AFB_request *request) { /* AFB_SESSION_CREATE */ + audioCtxHandleT *ctx; + json_object *jresp; + + /* create a private client context */ + ctx = initAudioCtx(); + request->client->ctx = (audioCtxHandleT*)ctx; + + _alsa_init("default", ctx); + + jresp = json_object_new_object(); + json_object_object_add (jresp, "token", json_object_new_string (request->client->token)); +} -STATIC AFB_restapi pluginApis[]= { - {"ping" , AFB_SESSION_NONE, (AFB_apiCB)apiPingTest,"Ping Application Framework"}, - {"error" , AFB_SESSION_NONE, (AFB_apiCB)wrongApi , "Ping Application Framework"}, + +STATIC AFB_restapi pluginApis[]= { + {"init" , AFB_SESSION_CREATE, (AFB_apiCB)init , "Audio API - init"}, +// {"error" , AFB_SESSION_CHECK, (AFB_apiCB)wrongApi , "Ping Application Framework"}, {NULL} }; -PUBLIC AFB_plugin *alsaRegister () { - AFB_plugin *plugin = malloc (sizeof (AFB_plugin)); - plugin->type = AFB_PLUGIN_JSON; - plugin->info = "Application Framework Binder Service"; - plugin->prefix= "alsa"; - plugin->apis = pluginApis; +PUBLIC AFB_plugin *audioRegister () { + AFB_plugin *plugin = malloc (sizeof(AFB_plugin)); + plugin->type = AFB_PLUGIN_JSON; + plugin->info = "Application Framework Binder - Audio plugin"; + plugin->prefix = "audio"; + plugin->apis = pluginApis; + + plugin->freeCtxCB = freeAudio; + return (plugin); }; \ No newline at end of file diff --git a/plugins/audio/audio-api.h b/plugins/audio/audio-api.h new file mode 100644 index 00000000..0928f0fa --- /dev/null +++ b/plugins/audio/audio-api.h @@ -0,0 +1,26 @@ +#ifndef AUDIO_API_H +#define AUDIO_API_H + +#include "audio-alsa.h" + +/* global plugin handle, should store everything we may need */ +typedef struct { + int devCount; +} pluginHandleT; + +/* structure holding one audio card with current usage status */ +typedef struct { + char *name; + void *handle; /* handle to implementation (ALSA, PulseAudio...) */ + } audioDevT; + +/* private client context [will be destroyed when client leaves] */ +typedef struct { + audioDevT *radio; /* pointer to client audio card */ + unsigned int volume; /* audio volume : 0-100 */ + unsigned int rate; /* audio rate (Hz) */ + unsigned int channels; /* audio channels : 1(mono)/2(stereo)... */ +} audioCtxHandleT; + + +#endif /* AUDIO_API_H */ \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50e3ef37..ebf023af 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,6 @@ +IF(alsa_FOUND) + ADD_DEFINITIONS(-DHAVE_AUDIO_PLUGIN=1) +ENDIF(alsa_FOUND) IF(librtlsdr_FOUND) ADD_DEFINITIONS(-DHAVE_RADIO_PLUGIN=1) ENDIF(librtlsdr_FOUND) diff --git a/src/rest-api.c b/src/rest-api.c index 06b6ea87..c7f4b03e 100644 --- a/src/rest-api.c +++ b/src/rest-api.c @@ -615,8 +615,10 @@ void initPlugins(AFB_session *session) { int i = 0; plugins[i++] = tokenRegister(session), - plugins[i++] = alsaRegister(session), plugins[i++] = helloWorldRegister(session), +#ifdef HAVE_AUDIO_PLUGIN + plugins[i++] = audioRegister(session), +#endif #ifdef HAVE_RADIO_PLUGIN plugins[i++] = radioRegister(session), #endif -- 2.16.6