Initial Audio plugin
authorManuel Bachmann <manuel.bachmann@iot.bzh>
Wed, 16 Dec 2015 19:38:03 +0000 (20:38 +0100)
committerManuel Bachmann <manuel.bachmann@iot.bzh>
Wed, 16 Dec 2015 19:38:49 +0000 (20:38 +0100)
Signed-off-by: Manuel Bachmann <manuel.bachmann@iot.bzh>
CMakeLists.txt
README.md
include/proto-def.h
plugins/CMakeLists.txt
plugins/audio/audio-alsa.c [new file with mode: 0644]
plugins/audio/audio-alsa.h [new file with mode: 0644]
plugins/audio/audio-api.c
plugins/audio/audio-api.h [new file with mode: 0644]
src/CMakeLists.txt
src/rest-api.c

index af98b38..a3ab4c3 100644 (file)
@@ -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)
index cb23e45..5846f00 100644 (file)
--- 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:
index fc3a9cf..4241b4b 100644 (file)
@@ -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);
index 0ddaf45..7696938 100644 (file)
@@ -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 (file)
index 0000000..8c08c8d
--- /dev/null
@@ -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 (&params);
+    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 (file)
index 0000000..a85f419
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef AUDIO_ALSA_H
+#define AUDIO_ALSA_H
+
+#include <alsa/asoundlib.h>
+
+#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
index 9d4f3cb..547f97e 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#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 (file)
index 0000000..0928f0f
--- /dev/null
@@ -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
index 50e3ef3..ebf023a 100644 (file)
@@ -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)
index 06b6ea8..c7f4b03 100644 (file)
@@ -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