From 2db7c92c0b4f5840884481fa4c95facbdea63bb6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Tue, 3 Jan 2017 11:13:47 +0100 Subject: [PATCH] Cleanup of the project MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The bindings "audio", "media" and "radio" were in the project since its beginning for historical reasons. But this bindings msut not be part of the current tree of sources. Change-Id: I9d903f094ddc4d2457e63987df0c221d2bd7b4d1 Signed-off-by: José Bollo --- bindings/CMakeLists.txt | 3 - bindings/audio/CMakeLists.txt | 27 -- bindings/audio/audio-alsa.c | 311 ------------------ bindings/audio/audio-alsa.h | 56 ---- bindings/audio/audio-api.c | 383 ---------------------- bindings/audio/audio-api.h | 38 --- bindings/audio/audio-pulse.c | 491 ---------------------------- bindings/audio/audio-pulse.h | 66 ---- bindings/audio/export.map | 1 - bindings/media/CMakeLists.txt | 18 -- bindings/media/export.map | 1 - bindings/media/media-api.c | 331 ------------------- bindings/media/media-api.h | 29 -- bindings/media/media-rygel.c | 721 ------------------------------------------ bindings/media/media-rygel.h | 68 ---- bindings/radio/CMakeLists.txt | 17 - bindings/radio/export.map | 1 - bindings/radio/radio-api.c | 376 ---------------------- bindings/radio/radio-api.h | 49 --- bindings/radio/radio-rtlsdr.c | 427 ------------------------- bindings/radio/radio-rtlsdr.h | 100 ------ 21 files changed, 3514 deletions(-) delete mode 100644 bindings/audio/CMakeLists.txt delete mode 100644 bindings/audio/audio-alsa.c delete mode 100644 bindings/audio/audio-alsa.h delete mode 100644 bindings/audio/audio-api.c delete mode 100644 bindings/audio/audio-api.h delete mode 100644 bindings/audio/audio-pulse.c delete mode 100644 bindings/audio/audio-pulse.h delete mode 100644 bindings/audio/export.map delete mode 100644 bindings/media/CMakeLists.txt delete mode 100644 bindings/media/export.map delete mode 100644 bindings/media/media-api.c delete mode 100644 bindings/media/media-api.h delete mode 100644 bindings/media/media-rygel.c delete mode 100644 bindings/media/media-rygel.h delete mode 100644 bindings/radio/CMakeLists.txt delete mode 100644 bindings/radio/export.map delete mode 100644 bindings/radio/radio-api.c delete mode 100644 bindings/radio/radio-api.h delete mode 100644 bindings/radio/radio-rtlsdr.c delete mode 100644 bindings/radio/radio-rtlsdr.h diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt index 2aacf1a1..8dbb9180 100644 --- a/bindings/CMakeLists.txt +++ b/bindings/CMakeLists.txt @@ -1,5 +1,2 @@ ADD_SUBDIRECTORY(samples) -ADD_SUBDIRECTORY(audio) -ADD_SUBDIRECTORY(radio) -ADD_SUBDIRECTORY(media) ADD_SUBDIRECTORY(intrinsics) diff --git a/bindings/audio/CMakeLists.txt b/bindings/audio/CMakeLists.txt deleted file mode 100644 index 11da28e1..00000000 --- a/bindings/audio/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(alsa alsa) -PKG_CHECK_MODULES(pulseaudio libpulse libpulse-simple) -INCLUDE(FindThreads) -FIND_PACKAGE(Threads) - -IF(alsa_FOUND) - - MESSAGE(STATUS "ALSA found ; will compile Audio binding... (BINDING)") - - IF(pulseaudio_FOUND) - MESSAGE(STATUS "PulseAudio found ; Audio binding will have PulseAudio support") - ADD_DEFINITIONS(-DHAVE_PULSE=1) - SET(pulse_sources audio-pulse.c) - ENDIF(pulseaudio_FOUND) - - INCLUDE_DIRECTORIES(${include_dirs} ${alsa_INCLUDE_DIRS} ${pulseaudio_INCLUDE_DIRS}) - ADD_LIBRARY(audio-api MODULE audio-api.c audio-alsa.c ${pulse_sources}) - SET_TARGET_PROPERTIES(audio-api PROPERTIES - PREFIX "" - LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" - ) - TARGET_LINK_LIBRARIES(audio-api ${link_libraries} ${alsa_LIBRARIES} ${pulseaudio_LIBRARIES}) - INSTALL(TARGETS audio-api - LIBRARY DESTINATION ${binding_install_dir}) - -ENDIF(alsa_FOUND) diff --git a/bindings/audio/audio-alsa.c b/bindings/audio/audio-alsa.c deleted file mode 100644 index cfb111bc..00000000 --- a/bindings/audio/audio-alsa.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "audio-api.h" -#include "audio-alsa.h" - -snd_mixer_selem_channel_id_t SCHANNELS[8] = { - SND_MIXER_SCHN_FRONT_LEFT, - SND_MIXER_SCHN_FRONT_RIGHT, - SND_MIXER_SCHN_FRONT_CENTER, - SND_MIXER_SCHN_REAR_LEFT, - SND_MIXER_SCHN_REAR_RIGHT, - SND_MIXER_SCHN_REAR_CENTER, - SND_MIXER_SCHN_SIDE_LEFT, - SND_MIXER_SCHN_SIDE_RIGHT -}; - -static struct dev_ctx_alsa **dev_ctx_a = NULL; - - -unsigned char _alsa_init (const char *name, audioCtxHandleT *ctx) { - - snd_pcm_t *dev; - snd_pcm_hw_params_t *params; - snd_mixer_t *mixer; - snd_mixer_selem_id_t *mixer_sid; - snd_mixer_elem_t *mixer_elm; - snd_mixer_elem_t *mixer_elm_m; - unsigned int rate = 22050; - long vol, vol_min, vol_max; - int num, i; - - if (snd_pcm_open (&dev, name, SND_PCM_STREAM_PLAYBACK, 0) < 0) { - fprintf (stderr, "ALSA backend could not open card '%s'\n", name); - 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, &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); - fprintf (stderr, "ALSA backend could set channels on card '%s'\n", name); - return 0; - } - snd_pcm_prepare (dev); - - snd_mixer_open (&mixer, 0); - if (snd_mixer_attach (mixer, name) < 0) { - snd_pcm_hw_params_free (params); - fprintf (stderr, "ALSA backend could not open mixer for card '%s'\n", name); - return 0; - } - snd_mixer_selem_register (mixer, NULL, NULL); - snd_mixer_load (mixer); - - snd_mixer_selem_id_alloca (&mixer_sid); - snd_mixer_selem_id_set_index (mixer_sid, 0); - snd_mixer_selem_id_set_name (mixer_sid, "Master"); - - mixer_elm = snd_mixer_find_selem (mixer, mixer_sid); - mixer_elm_m = NULL; - - if (!mixer_elm) { - /* no "Master" mixer ; we are probably on a board... search ! */ - for (mixer_elm = snd_mixer_first_elem (mixer); mixer_elm != NULL; - mixer_elm = snd_mixer_elem_next (mixer_elm)) { - if (snd_mixer_elem_info (mixer_elm) < 0) - continue; - snd_mixer_selem_get_id (mixer_elm, mixer_sid); - if (strstr (snd_mixer_selem_id_get_name (mixer_sid), "DVC Out")) { - - /* this is Porter... let us found the specific mute switch */ - snd_mixer_selem_id_set_index (mixer_sid, 0); - snd_mixer_selem_id_set_name (mixer_sid, "DVC Out Mute"); - mixer_elm_m = snd_mixer_find_selem (mixer, mixer_sid); - - break; - } - } - } - - if (mixer_elm) { - snd_mixer_selem_get_playback_volume_range (mixer_elm, &vol_min, &vol_max); - snd_mixer_selem_get_playback_volume (mixer_elm, SND_MIXER_SCHN_FRONT_LEFT, &vol); - } - - /* allocate the global array if it hasn't been done */ - if (!dev_ctx_a) { - dev_ctx_a = (dev_ctx_alsa_T**) malloc (sizeof(dev_ctx_alsa_T*)); - dev_ctx_a[0] = (dev_ctx_alsa_T*) malloc (sizeof(dev_ctx_alsa_T)); - dev_ctx_a[0]->name = NULL; - dev_ctx_a[0]->dev = NULL; - } - - /* is a card with similar name already opened ? */ - for (num = 0; num < (sizeof(dev_ctx_a)/sizeof(dev_ctx_alsa_T*)); num++) { - if (dev_ctx_a[num]->name && - !strcmp (dev_ctx_a[num]->name, name)) { - fprintf (stderr, "Card '%s' already locked by other ALSA backend session\n", name); - return 0; - } - } - num--; - - /* it's not... let us add it to the global array */ - dev_ctx_a = (dev_ctx_alsa_T**) realloc (dev_ctx_a, (num+1)*sizeof(dev_ctx_alsa_T*)); - if (!dev_ctx_a[num]) - dev_ctx_a[num] = (dev_ctx_alsa_T*) malloc (sizeof(dev_ctx_alsa_T)); - dev_ctx_a[num]->name = strdup (name); - dev_ctx_a[num]->dev = dev; - dev_ctx_a[num]->params = params; - dev_ctx_a[num]->mixer_elm = mixer_elm; - dev_ctx_a[num]->mixer_elm_m = mixer_elm_m; - dev_ctx_a[num]->vol_max = vol_max; - dev_ctx_a[num]->vol = vol; - dev_ctx_a[num]->thr_should_run = 0; - dev_ctx_a[num]->thr_finished = 0; - - /* make the client context aware of current card state */ - for (i = 0; i < 8; i++) - ctx->volume[i] = _alsa_get_volume (num, i); - ctx->mute = _alsa_get_mute (num); - ctx->idx = num; - ctx->name = strdup (name); - - fprintf (stderr, "Successfully initialized ALSA backend.\n"); - - return 1; -} - -void _alsa_free (const char *name) { - - int num; - - for (num = 0; num < (sizeof(dev_ctx_a)/sizeof(dev_ctx_alsa_T*)); num++) { - if (dev_ctx_a[num]->name && - !strcmp (dev_ctx_a[num]->name, name)) { - snd_pcm_close (dev_ctx_a[num]->dev); - snd_pcm_hw_params_free (dev_ctx_a[num]->params); - free (dev_ctx_a[num]->name); - dev_ctx_a[num]->dev = NULL; - dev_ctx_a[num]->name = NULL; - free (dev_ctx_a[num]); - return; - } - } -} - -void _alsa_play (int num) { - - if (!dev_ctx_a || !dev_ctx_a[num] || dev_ctx_a[num]->thr_should_run || - access (AUDIO_BUFFER, F_OK) == -1) - return; - - dev_ctx_a[num]->thr_should_run = 1; - dev_ctx_a[num]->thr_finished = 0; - pthread_create (&dev_ctx_a[num]->thr, NULL, _alsa_play_thread_fn, (void*)dev_ctx_a[num]); -} - -void _alsa_stop (int num) { - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->thr_should_run) - return; - - /* stop the "while" loop in thread */ - dev_ctx_a[num]->thr_should_run = 0; - - while (!dev_ctx_a[num]->thr_finished) - usleep(100000); - - pthread_join (dev_ctx_a[num]->thr, NULL); -} - -unsigned int _alsa_get_volume (int num, unsigned int channel) { - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->mixer_elm) - return 0; - - snd_mixer_selem_get_playback_volume (dev_ctx_a[num]->mixer_elm, SCHANNELS[channel], &dev_ctx_a[num]->vol); - - return (unsigned int)(dev_ctx_a[num]->vol*100)/dev_ctx_a[num]->vol_max; -} - -void _alsa_set_volume (int num, unsigned int channel, unsigned int vol) { - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->mixer_elm || - vol > 100) - return; - - snd_mixer_selem_set_playback_volume (dev_ctx_a[num]->mixer_elm, SCHANNELS[channel], (vol*dev_ctx_a[num]->vol_max)/100); -} - -void _alsa_set_volume_all (int num, unsigned int vol) { - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->mixer_elm || - vol > 100) - - fflush (stdout); /* seems to force this logic to apply quickly */ - snd_mixer_selem_set_playback_volume_all (dev_ctx_a[num]->mixer_elm, (vol*dev_ctx_a[num]->vol_max)/100); -} - -unsigned char _alsa_get_mute (int num) { - - int mute = 0; - snd_mixer_elem_t *elm_m; - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->mixer_elm) - return 0; - - dev_ctx_a[num]->mixer_elm_m ? (elm_m = dev_ctx_a[num]->mixer_elm_m) : - (elm_m = dev_ctx_a[num]->mixer_elm); - - if (snd_mixer_selem_has_playback_switch (elm_m)) { - snd_mixer_selem_get_playback_switch (elm_m, SND_MIXER_SCHN_FRONT_LEFT, &mute); - snd_mixer_selem_get_playback_switch (elm_m, SND_MIXER_SCHN_FRONT_RIGHT, &mute); - } - - if (dev_ctx_a[num]->mixer_elm_m) - return (unsigned char)mute; - else - return (unsigned char)!mute; -} - -void _alsa_set_mute (int num, unsigned char tomute) { - - snd_mixer_elem_t *elm_m; - int mute; - - if (!dev_ctx_a || !dev_ctx_a[num] || !dev_ctx_a[num]->mixer_elm || 1 < tomute) - return; - - if (dev_ctx_a[num]->mixer_elm_m) { - elm_m = dev_ctx_a[num]->mixer_elm_m; - mute = (int)!tomute; - } else { - elm_m = dev_ctx_a[num]->mixer_elm; - mute = (int)tomute; - } - - if (snd_mixer_selem_has_playback_switch (elm_m)) - snd_mixer_selem_set_playback_switch_all (elm_m, !mute); -} - -void _alsa_set_rate (int num, unsigned int rate) { - - if (!dev_ctx_a || !dev_ctx_a[num]) - return; - - snd_pcm_hw_params_set_rate_near (dev_ctx_a[num]->dev, dev_ctx_a[num]->params, &rate, 0); -} - -void _alsa_set_channels (int num, unsigned int channels) { - - if (!dev_ctx_a || !dev_ctx_a[num]) - return; - - snd_pcm_hw_params_set_channels (dev_ctx_a[num]->dev, dev_ctx_a[num]->params, channels); -} - - /* ---- LOCAL THREADED FUNCTIONS ---- */ - -void* _alsa_play_thread_fn (void *ctx) { - - dev_ctx_alsa_T *dev_ctx_a = (dev_ctx_alsa_T *)ctx; - FILE *file = NULL; - char *buf = NULL; - long size; - int frames, res; - - file = fopen (AUDIO_BUFFER, "rb"); - - while (dev_ctx_a->thr_should_run && file && (access (AUDIO_BUFFER, F_OK) != -1) ) { - fseek (file, 0, SEEK_END); - size = ftell (file); - buf = (char*) realloc (buf, size * sizeof(char)); - frames = (size * sizeof(char)) / 4; - - fseek (file, 0, SEEK_SET); - fread (buf, 1, size, file); - fflush (file); - - if ((res = snd_pcm_writei (dev_ctx_a->dev, buf, frames)) != frames) { - snd_pcm_recover (dev_ctx_a->dev, res, 0); - snd_pcm_prepare (dev_ctx_a->dev); - } - /* snd_pcm_drain (dev_ctx->dev); */ - } - if (buf) free(buf); - if (file) fclose(file); - - dev_ctx_a->thr_finished = 1; - return 0; -} diff --git a/bindings/audio/audio-alsa.h b/bindings/audio/audio-alsa.h deleted file mode 100644 index 651d57ce..00000000 --- a/bindings/audio/audio-alsa.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIO_ALSA_H -#define AUDIO_ALSA_H - -#include -#include - -#include "audio-api.h" - -#define AUDIO_BUFFER "/tmp/audio_buf" - -typedef struct dev_ctx_alsa dev_ctx_alsa_T; - -struct dev_ctx_alsa { - char *name; - snd_pcm_t *dev; - snd_pcm_hw_params_t *params; - snd_mixer_elem_t *mixer_elm; - snd_mixer_elem_t *mixer_elm_m; - long vol_max; - long vol; - pthread_t thr; - unsigned char thr_should_run; - unsigned char thr_finished; -}; - -unsigned char _alsa_init (const char *, audioCtxHandleT *); -void _alsa_free (const char *); -void _alsa_play (int); -void _alsa_stop (int); -unsigned int _alsa_get_volume (int, unsigned int); -void _alsa_set_volume (int, unsigned int, unsigned int); -void _alsa_set_volume_all (int, unsigned int); -unsigned char _alsa_get_mute (int); -void _alsa_set_mute (int, unsigned char); -void _alsa_set_channels (int, unsigned int); - -void* _alsa_play_thread_fn (void *); - -#endif /* AUDIO_ALSA_H */ diff --git a/bindings/audio/audio-api.c b/bindings/audio/audio-api.c deleted file mode 100644 index 7466173e..00000000 --- a/bindings/audio/audio-api.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include - -#include "audio-api.h" -#include "audio-alsa.h" -#ifdef HAVE_PULSE -#include "audio-pulse.h" -#endif - -#include -#include - -/* ------ BACKEND FUNCTIONS ------- */ - -unsigned char _backend_init (const char *name, audioCtxHandleT *ctx) { - - char *backend_env = getenv ("AFB_AUDIO_OUTPUT"); - unsigned char res = 0; - -# ifdef HAVE_PULSE - if (!backend_env || (strcasecmp (backend_env, "Pulse") == 0)) - res = _pulse_init (name, ctx); - if (!res) -#endif - res = _alsa_init (name, ctx); - - if (!res) - fprintf (stderr, "Could not initialize Audio backend\n"); - - return res; -} - -void _backend_free (audioCtxHandleT *ctx) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_free (ctx); else -# endif - _alsa_free (ctx->name); -} - -void _backend_play (audioCtxHandleT *ctx) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_play (ctx); else -# endif - _alsa_play (ctx->idx); -} - -void _backend_stop (audioCtxHandleT *ctx) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_stop (ctx); else -# endif - _alsa_stop (ctx->idx); -} - -unsigned int _backend_get_volume (audioCtxHandleT *ctx, unsigned int channel) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) return _pulse_get_volume (ctx, channel); else -# endif - return _alsa_get_volume (ctx->idx, channel); -} - -void _backend_set_volume (audioCtxHandleT *ctx, unsigned int channel, unsigned int vol) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_set_volume (ctx, channel, vol); else -# endif - _alsa_set_volume (ctx->idx, channel, vol); -} - -void _backend_set_volume_all (audioCtxHandleT *ctx, unsigned int vol) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_set_volume_all (ctx, vol); else -# endif - _alsa_set_volume_all (ctx->idx, vol); -} - -unsigned char _backend_get_mute (audioCtxHandleT *ctx) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) return _pulse_get_mute (ctx); else -# endif - return _alsa_get_mute (ctx->idx); -} - -void _backend_set_mute (audioCtxHandleT *ctx, unsigned char mute) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) _pulse_set_mute (ctx, mute); else -# endif - _alsa_set_mute (ctx->idx, mute); -} - -void _backend_set_channels (audioCtxHandleT *ctx, unsigned int channels) { - -# ifdef HAVE_PULSE - if (ctx->audio_dev) return; else -# endif - _alsa_set_channels (ctx->idx, channels); -} - -/* ------ LOCAL HELPER FUNCTIONS --------- */ - -/* private client context constructor ; default values */ -static audioCtxHandleT* initAudioCtx () { - - audioCtxHandleT *ctx; - int i; - - ctx = malloc (sizeof(audioCtxHandleT)); - ctx->audio_dev = NULL; - ctx->name = NULL; - ctx->idx = -1; - for (i = 0; i < 8; i++) - ctx->volume[i] = 25; - ctx->channels = 2; - ctx->mute = 0; - ctx->is_playing = 0; - - return ctx; -} - -static void releaseAudioCtx (void *context) { - - audioCtxHandleT *ctx = (audioCtxHandleT*) context; - - /* power it off */ - _backend_free (ctx); - - /* clean client context */ - ctx->audio_dev = NULL; - if (ctx->name) - free (ctx->name); - ctx->idx = -1; - free (ctx); -} - - -/* ------ PUBLIC PLUGIN FUNCTIONS --------- */ - -static void init (struct afb_req request) { /* AFB_SESSION_CHECK */ - - audioCtxHandleT *ctx = afb_req_context_get (request); - json_object *jresp; - - /* create a private client context */ - if (!ctx) { - ctx = initAudioCtx(); - afb_req_context_set (request, ctx, releaseAudioCtx); - } - - if (!_backend_init ("default", ctx)) - afb_req_fail (request, "failed", "backend initialization failed"); - - jresp = json_object_new_object(); - json_object_object_add (jresp, "init", json_object_new_string ("success")); - afb_req_success (request, jresp, "Audio initialized"); -} - -static void volume (struct afb_req request) { /* AFB_SESSION_CHECK */ - - audioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - unsigned int volume[8], i; - char *volume_i; - char volume_str[256]; - size_t len_str = 0; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value) { - for (i = 0; i < 8; i++) { - ctx->volume[i] = _backend_get_volume (ctx, i); - snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]); - len_str = strlen (volume_str); - } - json_object_object_add (jresp, "volume", json_object_new_string(volume_str)); - afb_req_success (request, jresp, "Audio - Volume obtained"); - return; - } - - /* "?value=" parameter, set volume */ - else { - volume_i = strdup (value); - volume_i = strtok (volume_i, ","); - volume[0] = (unsigned int) atoi (volume_i); - - if (100 < volume[0]) { - free (volume_i); - afb_req_fail (request, "failed", "volume must be between 0 and 100"); - return; - } - ctx->volume[0] = volume[0]; - _backend_set_volume (ctx, 0, ctx->volume[0]); - snprintf (volume_str, sizeof(volume_str), "%d,", ctx->volume[0]); - - for (i = 1; i < 8; i++) { - volume_i = strtok (NULL, ","); - /* if there is only one value, set all channels to this one */ - if (!volume_i && i == 1) - _backend_set_volume_all (ctx, ctx->volume[0]); - if (!volume_i || 100 < atoi(volume_i) || atoi(volume_i) < 0) - ctx->volume[i] = _backend_get_volume (ctx, i); - else { - ctx->volume[i] = (unsigned int) atoi(volume_i); - _backend_set_volume (ctx, i, ctx->volume[i]); - } - len_str = strlen(volume_str); - snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]); - } - free (volume_i); - json_object_object_add (jresp, "volume", json_object_new_string(volume_str)); - } - - afb_req_success (request, jresp, "Audio - Volume changed"); -} - -static void channels (struct afb_req request) { /* AFB_SESSION_CHECK */ - - audioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - char channels_str[256]; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value) { - snprintf (channels_str, sizeof(channels_str), "%d", ctx->channels); - - json_object_object_add (jresp, "channels", json_object_new_string (channels_str)); - afb_req_success (request, jresp, "Audio - Channels obtained"); - return; - } - - /* "?value=" parameter, set channels */ - else { - ctx->channels = (unsigned int) atoi (value); - _backend_set_channels (ctx, ctx->channels); - snprintf (channels_str, sizeof(channels_str), "%d", ctx->channels); - - jresp = json_object_new_object(); - json_object_object_add (jresp, "channels", json_object_new_string (channels_str)); - } - - afb_req_success (request, jresp, "Audio - Channels set"); -} - -static void mute (struct afb_req request) { /* AFB_SESSION_CHECK */ - - audioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value) { - ctx->mute = _backend_get_mute (ctx); - ctx->mute ? - json_object_object_add (jresp, "mute", json_object_new_string ("on")) - : json_object_object_add (jresp, "mute", json_object_new_string ("off")); - afb_req_success (request, jresp, "Audio - Mute status obtained"); - return; - } - - /* "?value=" parameter is "1" or "true" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) { - ctx->mute = 1; - _backend_set_mute (ctx, ctx->mute); - json_object_object_add (jresp, "mute", json_object_new_string ("on")); - } - - /* "?value=" parameter is "0" or "false" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) { - ctx->mute = 0; - _backend_set_mute (ctx, ctx->mute); - json_object_object_add (jresp, "mute", json_object_new_string ("off")); - } - - afb_req_success (request, jresp, "Audio - Mute set"); -} - -static void play (struct afb_req request) { /* AFB_SESSION_CHECK */ - - audioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value) { - ctx->is_playing ? - json_object_object_add (jresp, "play", json_object_new_string ("on")) - : json_object_object_add (jresp, "play", json_object_new_string ("off")); - afb_req_success (request, jresp, "Audio - Playing status obtained"); - return; - } - - /* "?value=" parameter is "1" or "true" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) { - ctx->is_playing = 1; - _backend_play (ctx); - json_object_object_add (jresp, "play", json_object_new_string ("on")); - } - - /* "?value=" parameter is "0" or "false" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) { - ctx->is_playing = 0; - _backend_stop (ctx); - json_object_object_add (jresp, "play", json_object_new_string ("off")); - } - - afb_req_success (request, jresp, "Audio - Play"); -} - -static void ping (struct afb_req request) { /* AFB_SESSION_NONE */ - afb_req_success (request, NULL, "Audio - Ping success"); -} - -static const struct afb_verb_desc_v1 verbs[] = { - {"init" , AFB_SESSION_CHECK, init , "Audio API - init"}, - {"volume" , AFB_SESSION_CHECK, volume , "Audio API - volume"}, - {"channels", AFB_SESSION_CHECK, channels , "Audio API - channels"}, - {"mute" , AFB_SESSION_CHECK, mute , "Audio API - mute"}, - {"play" , AFB_SESSION_CHECK, play , "Audio API - play"}, - {"ping" , AFB_SESSION_NONE, ping , "Audio API - ping"}, - {NULL} -}; - -static const struct afb_binding pluginDesc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder - Audio plugin", - .prefix = "audio", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &pluginDesc; -} diff --git a/bindings/audio/audio-api.h b/bindings/audio/audio-api.h deleted file mode 100644 index 1b40136d..00000000 --- a/bindings/audio/audio-api.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIO_API_H -#define AUDIO_API_H - -/* global plugin handle, should store everything we may need */ -typedef struct { - int devCount; -} pluginHandleT; - -/* private client context [will be destroyed when client leaves] */ -typedef struct { - void *audio_dev; /* handle to implementation (ALSA, PulseAudio...) */ - char *name; /* name of the audio card */ - int idx; /* audio card index within global array */ - unsigned int volume[8]; /* audio volume (8 channels) : 0-100 */ - unsigned int channels; /* audio channels : 1(mono)/2(stereo)... */ - unsigned char mute; /* audio muted : 0(false)/1(true) */ - unsigned char is_playing; /* audio is playing: 0(false)/1(true) */ -} audioCtxHandleT; - - -#endif /* AUDIO_API_H */ diff --git a/bindings/audio/audio-pulse.c b/bindings/audio/audio-pulse.c deleted file mode 100644 index 16e7aa15..00000000 --- a/bindings/audio/audio-pulse.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include - -#include "audio-api.h" -#include "audio-pulse.h" - -static struct alsa_info **alsa_info = NULL; -static struct dev_ctx_pulse **dev_ctx_p = NULL; -static unsigned int client_count = 0; - - -unsigned char _pulse_init (const char *name, audioCtxHandleT *ctx) { - - pa_mainloop *pa_loop; - pa_mainloop_api *pa_api; - pa_context *pa_context; - pa_simple *pa; - pa_sample_spec *pa_spec; - struct timeval tv_start, tv_now; - int ret, error, i; - - pa_loop = pa_mainloop_new (); - pa_api = pa_mainloop_get_api (pa_loop); - pa_context = pa_context_new (pa_api, "afb-audio-plugin"); - - /* allocate the global array if it hasn't been done */ - if (!dev_ctx_p) - dev_ctx_p = (dev_ctx_pulse_T**) malloc (sizeof(dev_ctx_pulse_T*)); - - /* create a temporary device, to be held until sink gets discovered */ - dev_ctx_pulse_T *dev_ctx_p_t = (dev_ctx_pulse_T*) malloc (sizeof(dev_ctx_pulse_T)); - dev_ctx_p_t->sink_name = NULL; - dev_ctx_p_t->card_name = (char**) malloc (sizeof(char*)); - dev_ctx_p_t->card_name[0] = strdup (name); - dev_ctx_p_t->pa_loop = pa_loop; - dev_ctx_p_t->pa_context = pa_context; - - pa_context_set_state_callback (pa_context, _pulse_context_cb, (void*)dev_ctx_p_t); - pa_context_connect (pa_context, NULL, 0, NULL); - - /* 1 second should be sufficient to retrieve sink info */ - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 2) { - pa_mainloop_iterate (pa_loop, 0, &ret); - - if (ret == -1) { /* generic error */ - fprintf (stderr, "Stopping PulseAudio backend...\n"); - return 0; - } - - if ((ret > 0)&&(ret < 100)) { /* 0 and >100 are PulseAudio codes */ - /* found a matching sink from callback */ - fprintf (stderr, "Success : using sink n.%d\n", ret-1); - ctx->audio_dev = (void*)dev_ctx_p[ret-1]; - break; - } - gettimeofday (&tv_now, NULL); - } - /* fail if we found no matching sink */ - if (!ctx->audio_dev) - return 0; - - /* make the client context aware of current card state */ - ctx->mute = (unsigned char)dev_ctx_p[ret-1]->mute; - ctx->channels = (unsigned int)dev_ctx_p[ret-1]->volume.channels; - for (i = 0; i < ctx->channels; i++) - ctx->volume[i] = dev_ctx_p[ret-1]->volume.values[i]; - ctx->idx = ret-1; - - /* open matching sink for playback */ - pa_spec = (pa_sample_spec*) malloc (sizeof(pa_sample_spec)); - pa_spec->format = PA_SAMPLE_S16LE; - pa_spec->rate = 22050; - pa_spec->channels = (uint8_t)ctx->channels; - - if (!(pa = pa_simple_new (NULL, "afb-audio-plugin", PA_STREAM_PLAYBACK, dev_ctx_p[ret-1]->sink_name, - "afb-audio-output", pa_spec, NULL, NULL, &error))) { - fprintf (stderr, "Error opening PulseAudio sink %s : %s\n", - dev_ctx_p[ret-1]->sink_name, pa_strerror(error)); - return 0; - } - dev_ctx_p[ret-1]->pa = pa; - free (pa_spec); - - client_count++; - - fprintf (stderr, "Successfully initialized PulseAudio backend.\n"); - - return 1; -} - -void _pulse_free (audioCtxHandleT *ctx) { - - int num, i; - - client_count--; - if (client_count > 0) return; - - for (num = 0; num < (sizeof(dev_ctx_p)/sizeof(dev_ctx_pulse_T*)); num++) { - - for (i = 0; num < (sizeof(dev_ctx_p[num]->card_name)/sizeof(char*)); i++) { - free (dev_ctx_p[num]->card_name[i]); - dev_ctx_p[num]->card_name[i] = NULL; - } - pa_context_disconnect (dev_ctx_p[num]->pa_context); - pa_context_unref (dev_ctx_p[num]->pa_context); - pa_mainloop_free (dev_ctx_p[num]->pa_loop); - pa_simple_free (dev_ctx_p[num]->pa); - free (dev_ctx_p[num]->sink_name); - dev_ctx_p[num]->pa_context = NULL; - dev_ctx_p[num]->pa_loop = NULL; - dev_ctx_p[num]->pa = NULL; - dev_ctx_p[num]->sink_name = NULL; - free (dev_ctx_p[num]); - } -} - -void _pulse_play (audioCtxHandleT *ctx) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - - if (!dev_ctx_p_c || dev_ctx_p_c->thr_should_run || access (AUDIO_BUFFER, F_OK) == -1) - return; - - dev_ctx_p_c->thr_should_run = 1; - dev_ctx_p_c->thr_finished = 0; - pthread_create (&dev_ctx_p_c->thr, NULL, _pulse_play_thread_fn, (void*)dev_ctx_p_c); -} - -void _pulse_stop (audioCtxHandleT *ctx) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - - if (!dev_ctx_p_c || !dev_ctx_p_c->thr_should_run) - return; - - dev_ctx_p_c->thr_should_run = 0; - while (!dev_ctx_p_c->thr_finished) - usleep(100000); - pthread_join (dev_ctx_p_c->thr, NULL); -} - -unsigned int _pulse_get_volume (audioCtxHandleT *ctx, unsigned int channel) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - - if (!dev_ctx_p_c) - return 0; - - _pulse_refresh_sink (dev_ctx_p_c); - - return (dev_ctx_p_c->volume.values[channel]*100)/PA_VOLUME_NORM; -} - -void _pulse_set_volume (audioCtxHandleT *ctx, unsigned int channel, unsigned int vol) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - struct pa_cvolume volume; - - if (!dev_ctx_p_c) - return; - - volume = dev_ctx_p_c->volume; - volume.values[channel] = (vol*PA_VOLUME_NORM)/100; - - pa_context_set_sink_volume_by_name (dev_ctx_p_c->pa_context, dev_ctx_p_c->sink_name, - &volume, NULL, NULL); - _pulse_refresh_sink (dev_ctx_p_c); -} - -void _pulse_set_volume_all (audioCtxHandleT *ctx, unsigned int vol) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - struct pa_cvolume volume; - - if (!dev_ctx_p_c) - return; - - pa_cvolume_init (&volume); - pa_cvolume_set (&volume, dev_ctx_p_c->volume.channels, vol); - - pa_context_set_sink_volume_by_name (dev_ctx_p_c->pa_context, dev_ctx_p_c->sink_name, - &volume, NULL, NULL); - _pulse_refresh_sink (dev_ctx_p_c); -} - -unsigned char _pulse_get_mute (audioCtxHandleT *ctx) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - - if (!dev_ctx_p_c) - return 0; - - _pulse_refresh_sink (dev_ctx_p_c); - - return (unsigned char)dev_ctx_p_c->mute; -} - -void _pulse_set_mute (audioCtxHandleT *ctx, unsigned char mute) { - - dev_ctx_pulse_T* dev_ctx_p_c = (dev_ctx_pulse_T*)ctx->audio_dev; - - if (!dev_ctx_p_c) - return; - - pa_context_set_sink_mute_by_name (dev_ctx_p_c->pa_context, dev_ctx_p_c->sink_name, - (int)mute, NULL, NULL); - _pulse_refresh_sink (dev_ctx_p_c); -} - - /* ---- LOCAL HELPER FUNCTIONS ---- */ - -void _pulse_refresh_sink (dev_ctx_pulse_T* dev_ctx_p_c) { - - pa_mainloop_api *pa_api; - - dev_ctx_p_c->pa_loop = pa_mainloop_new (); - pa_api = pa_mainloop_get_api (dev_ctx_p_c->pa_loop); - dev_ctx_p_c->pa_context = pa_context_new (pa_api, "afb-audio-plugin"); - - dev_ctx_p_c->refresh = 1; - - switch (pa_context_get_state (dev_ctx_p_c->pa_context)) { - case PA_CONTEXT_READY: - pa_context_get_sink_info_by_name (dev_ctx_p_c->pa_context, - dev_ctx_p_c->sink_name, - _pulse_sink_info_cb, (void*)dev_ctx_p_c); - break; - default: - return; - } - - while (dev_ctx_p_c->refresh) - pa_mainloop_iterate (dev_ctx_p_c->pa_loop, 0, NULL); -} - -void _pulse_enumerate_cards () { - - void **cards, **card; - char *name, *found, *alsa_name, *card_name; - int new_info, i, num = 0; - - /* allocate the global alsa array */ - alsa_info = (alsa_info_T**) malloc (sizeof(alsa_info_T*)); - alsa_info[0] = (alsa_info_T*) malloc (sizeof(alsa_info_T)); - alsa_info[0]->device = NULL; - alsa_info[0]->synonyms = NULL; - - /* we use ALSA to enumerate cards */ - snd_device_name_hint (-1, "pcm", &cards); - card = cards; - - for (; *card != NULL; card++) { - name = snd_device_name_get_hint (*card, "NAME"); - new_info = 1; - - /* alsa name is before ':' (if ':' misses, then it has no card) */ - found = strstr (name, ":"); - if (!found) continue; - /* */ - alsa_name = (char*) malloc (found-name+1); - strncpy (alsa_name, name, found-name); - alsa_name[found-name] = '\0'; - - /* card name is the invariant between "CARD=" and ',' */ - found = strstr (name, "CARD="); - if (!found) continue; - /* */ - found += 5; - card_name = strdup (found); - found = strstr (card_name, ","); - if (found) card_name[found-card_name] = '\0'; - - /* was the card name already listed in the global alsa array ? */ - for (i = 0; i < (sizeof(alsa_info)/sizeof(alsa_info_T*)); i++) { - - if (alsa_info[i]->device && - !strcmp (alsa_info[i]->device, card_name)) { - /* it was ; add the alsa name as a new synonym */ - asprintf (&alsa_info[i]->synonyms, "%s:%s", alsa_info[i]->synonyms, alsa_name); - new_info = 0; - break; - } - } - /* it was not ; create it */ - if (new_info) { - alsa_info = (alsa_info_T**) realloc (alsa_info, (num+1)*sizeof(alsa_info_T*)); - alsa_info[num] = (alsa_info_T*) malloc (sizeof(alsa_info_T)); - alsa_info[num]->device = strdup (card_name); - asprintf (&alsa_info[num]->synonyms, ":%s", alsa_name); - num++; - } - free (alsa_name); - free (card_name); - } -} - -char** _pulse_find_cards (const char *name) { - - char **cards = NULL; - char *needle, *found, *next; - int num, i = 0; - - if (!alsa_info) - _pulse_enumerate_cards (); - - asprintf (&needle, ":%s", name); - - for (num = 0; num < (sizeof(alsa_info)/sizeof(alsa_info_T*)); num++) { - - found = strstr (alsa_info[num]->synonyms, needle); - while (found) { - /* if next character is not ':' or '\0', we are wrong */ - if ((found[strlen(name)+1] != ':') && (found[strlen(name)+1] != '\0')) { - found = strstr (found+1, needle); - continue; - } - /* found it ; now return all the "synonym" cards */ - found = strstr (alsa_info[num]->synonyms, ":"); - while (found) { - next = strstr (found+1, ":"); - if (!next) break; - cards = (char**) realloc (cards, (i+1)*sizeof(char*)); - cards[i] = (char*) malloc (next-found+1); - strncpy (cards[i], found+1, next-found); - cards[i][next-found-1] = '\0'; - found = next; i++; - } - } - } - free (needle); - - return cards; -} - - /* ---- LOCAL CALLBACK FUNCTIONS ---- */ - -void _pulse_context_cb (pa_context *context, void *data) { - - pa_context_state_t state = pa_context_get_state (context); - dev_ctx_pulse_T *dev_ctx_p_t = (dev_ctx_pulse_T *)data; - - if (state == PA_CONTEXT_FAILED) { - fprintf (stderr, "Could not connect to PulseAudio !\n"); - pa_mainloop_quit (dev_ctx_p_t->pa_loop, -1); - pa_context_disconnect (dev_ctx_p_t->pa_context); - pa_context_unref (dev_ctx_p_t->pa_context); - pa_mainloop_free (dev_ctx_p_t->pa_loop); - } - - if (state == PA_CONTEXT_READY) - pa_context_get_sink_info_list (context, _pulse_sink_list_cb, (void*)dev_ctx_p_t); -} - -void _pulse_sink_list_cb (pa_context *context, const pa_sink_info *info, - int eol, void *data) { - - dev_ctx_pulse_T *dev_ctx_p_t = (dev_ctx_pulse_T *)data; - const char *device_string; - char *device, *found; - char **cards; - int num, i; - - if (eol != 0) - return; - - device_string = pa_proplist_gets (info->proplist, "device.string"); - /* ignore sinks with no cards */ - if (!device_string) - return; - - /* was a sink with similar name already found ? */ - for (num = 0; num < (sizeof(dev_ctx_p)/sizeof(dev_ctx_pulse_T*)); num++) { - if (dev_ctx_p[num]->sink_name && - !strcmp (dev_ctx_p[num]->sink_name, info->name)) { - - /* yet it was, did it have the required card ? */ - cards = dev_ctx_p[num]->card_name; - for (i = 0; i < (sizeof(cards)/sizeof(char*)); i++) { - if (!strcmp (cards[i], dev_ctx_p_t->card_name[0])) { - /* it did : stop there and succeed */ - fprintf (stderr, "Found matching sink : %s\n", info->name); - /* we return num+1 because '0' is already used */ - pa_mainloop_quit (dev_ctx_p_t->pa_loop, num+1); - pa_context_disconnect (dev_ctx_p_t->pa_context); - pa_context_unref (dev_ctx_p_t->pa_context); - pa_mainloop_free (dev_ctx_p_t->pa_loop); - } - } - /* it did not, ignore and return */ - return; - } - } - num++; - - /* remove ending ":0",":1"... in device name */ - device = strdup (device_string); - found = strstr (device, ":"); - if (found) device[found-device] = '\0'; - - /* new sink, find all the cards it manages, fail if none */ - cards = _pulse_find_cards (device); - free (device); - if (!cards) - return; - - /* everything is well, register it in global array */ - dev_ctx_p_t->sink_name = strdup (info->name); - dev_ctx_p_t->card_name = cards; - dev_ctx_p_t->mute = info->mute; - dev_ctx_p_t->volume = info->volume; - dev_ctx_p_t->thr_should_run = 0; - dev_ctx_p_t->thr_finished = 0; - dev_ctx_p[num] = dev_ctx_p_t; - - /* does this new sink have the card we are looking for ? */ /* TODO : factorize this */ - for (i = 0; i < (sizeof(cards)/sizeof(char*)); i++) { - if (!strcmp (cards[i], dev_ctx_p_t->card_name[0])) { - /* it did : stop there and succeed */ - fprintf (stderr, "Found matching sink : %s\n", info->name); - /* we return num+1 because '0' is already used */ - pa_mainloop_quit (dev_ctx_p_t->pa_loop, num+1); - pa_context_disconnect (dev_ctx_p_t->pa_context); - pa_context_unref (dev_ctx_p_t->pa_context); - pa_mainloop_free (dev_ctx_p_t->pa_loop); - } - } -} - -void _pulse_sink_info_cb (pa_context *context, const pa_sink_info *info, - int eol, void *data) { - - dev_ctx_pulse_T *dev_ctx_p_c = (dev_ctx_pulse_T *)data; - - if (eol != 0) - return; - - dev_ctx_p_c->refresh = 0; - dev_ctx_p_c->mute = info->mute; - dev_ctx_p_c->volume = info->volume; -} - - /* ---- LOCAL THREADED FUNCTIONS ---- */ - -void* _pulse_play_thread_fn (void *ctx) { - - dev_ctx_pulse_T *dev_ctx_p_c = (dev_ctx_pulse_T *)ctx; - FILE *file = NULL; - char *buf = NULL; - long size; - int error; - - file = fopen (AUDIO_BUFFER, "rb"); - - while (dev_ctx_p_c->thr_should_run && file && (access (AUDIO_BUFFER, F_OK) != -1) ) { - fseek (file, 0, SEEK_END); - size = ftell (file); - buf = (char*) realloc (buf, size * sizeof(char)); - - fseek (file, 0, SEEK_SET); - fread (buf, 1, size, file); - fflush (file); - - if (pa_simple_write (dev_ctx_p_c->pa, buf, size*2, &error) < 0) - fprintf (stderr, "Error writing to PulseAudio : %s\n", pa_strerror (error)); - /* pa_simple_drain (dev_ctx_p_c->pa); */ - } - if (buf) free(buf); - if (file) fclose(file); - - dev_ctx_p_c->thr_finished = 1; - return 0; -} diff --git a/bindings/audio/audio-pulse.h b/bindings/audio/audio-pulse.h deleted file mode 100644 index 7ef5dd77..00000000 --- a/bindings/audio/audio-pulse.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIO_PULSE_H -#define AUDIO_PULSE_H - -#include -#include -#include -#include - -#include "audio-alsa.h" - -typedef struct dev_ctx_pulse dev_ctx_pulse_T; -typedef struct alsa_info alsa_info_T; - -struct dev_ctx_pulse { - char *sink_name; - char **card_name; - pa_mainloop *pa_loop; - pa_context *pa_context; - pa_simple *pa; - pa_cvolume volume; - int mute; - unsigned char refresh; - pthread_t thr; - unsigned char thr_should_run; - unsigned char thr_finished; -}; - -struct alsa_info { - char *device; - char *synonyms; -}; - -unsigned char _pulse_init (const char *, audioCtxHandleT *); -void _pulse_free (audioCtxHandleT *); -void _pulse_play (audioCtxHandleT *); -void _pulse_stop (audioCtxHandleT *); -unsigned int _pulse_get_volume (audioCtxHandleT *, unsigned int); -void _pulse_set_volume (audioCtxHandleT *, unsigned int, unsigned int); -void _pulse_set_volume_all (audioCtxHandleT *, unsigned int); -unsigned char _pulse_get_mute (audioCtxHandleT *); -void _pulse_set_mute (audioCtxHandleT *, unsigned char); - -void _pulse_context_cb (pa_context *, void *); -void _pulse_sink_list_cb (pa_context *, const pa_sink_info *, int, void *); -void _pulse_sink_info_cb (pa_context *, const pa_sink_info *, int, void *); -void* _pulse_play_thread_fn (void *); -void _pulse_refresh_sink (dev_ctx_pulse_T *); - -#endif /* AUDIO_PULSE_H */ diff --git a/bindings/audio/export.map b/bindings/audio/export.map deleted file mode 100644 index 0ef1ac79..00000000 --- a/bindings/audio/export.map +++ /dev/null @@ -1 +0,0 @@ -{ global: afbBindingV1Register; local: *; }; diff --git a/bindings/media/CMakeLists.txt b/bindings/media/CMakeLists.txt deleted file mode 100644 index 2866dfbc..00000000 --- a/bindings/media/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(gupnp gupnp-1.0 gupnp-av-1.0 gssdp-1.0 gobject-2.0 gio-2.0) - -IF(gupnp_FOUND) - - MESSAGE(STATUS "gupnp found ; will compile Media binding... (binding)") - - INCLUDE_DIRECTORIES( ${include_dirs} ${gupnp_INCLUDE_DIRS}) - ADD_LIBRARY(media-api MODULE media-api.c media-rygel.c) - SET_TARGET_PROPERTIES(media-api PROPERTIES - PREFIX "" - LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" - ) - TARGET_LINK_LIBRARIES(media-api ${link_libraries} ${gupnp_LIBRARIES}) - INSTALL(TARGETS media-api - LIBRARY DESTINATION ${binding_install_dir}) - -ENDIF(gupnp_FOUND) diff --git a/bindings/media/export.map b/bindings/media/export.map deleted file mode 100644 index 0ef1ac79..00000000 --- a/bindings/media/export.map +++ /dev/null @@ -1 +0,0 @@ -{ global: afbBindingV1Register; local: *; }; diff --git a/bindings/media/media-api.c b/bindings/media/media-api.c deleted file mode 100644 index 32a1d3d3..00000000 --- a/bindings/media/media-api.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include - -#include - -#include "media-api.h" -#include "media-rygel.h" - -#include -#include - -json_object* _rygel_list (mediaCtxHandleT *); - -/* ------ LOCAL HELPER FUNCTIONS --------- */ - -/* private client context creation ; default values */ -static mediaCtxHandleT* initMediaCtx () { - - mediaCtxHandleT *ctx; - - ctx = malloc (sizeof(mediaCtxHandleT)); - ctx->media_server = NULL; - ctx->index = 0; - - return ctx; -} - -/* ------ PUBLIC PLUGIN FUNCTIONS --------- */ - -static void init (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - json_object *jresp; - - /* create a private client context */ - if (!ctx) { - ctx = initMediaCtx(); - afb_req_context_set (request, ctx, free); - } - - /* initialize server connection */ - if (!ctx->media_server) - _rygel_init (ctx); - - jresp = json_object_new_object (); - json_object_object_add (jresp, "init", json_object_new_string ("success")); - afb_req_success (request, jresp, "Media - Initialized"); -} - -static void list (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - json_object *jresp; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - jresp = _rygel_list (ctx); - - if (!jresp) { - afb_req_fail (request, "failed", "no content found in media server"); - return; - } - - afb_req_success (request, jresp, "Media - Listed"); -} - -static void selecting (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - unsigned int index; - char index_str[5]; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - /* no "?value=" parameter : return current index */ - if (!value) { - snprintf (index_str, sizeof(index_str), "%d", ctx->index); - jresp = json_object_new_object(); - json_object_object_add (jresp, "index", json_object_new_string (index_str)); - } - - /* "?value=" parameter is negative */ - else if (atoi(value) < 0) { - afb_req_fail (request, "failed", "chosen index cannot be negative"); - return; - } - - /* "?value=" parameter is positive */ - else if (atoi(value) >= 0) { - index = (unsigned int) atoi(value); - - if (!_rygel_select (ctx, index)) { - afb_req_fail (request, "failed", "chosen index superior to current media count"); - return; - } - - ctx->index = index; - jresp = json_object_new_object(); - json_object_object_add (jresp, "index", json_object_new_string (value)); - } - else - jresp = NULL; - - afb_req_success (request, jresp, "Media - Listed"); -} - -static void play (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - json_object *jresp; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - if (!_rygel_do (ctx, PLAY, NULL)) { - afb_req_fail (request, "failed", "could not play chosen media"); - return; - } - - jresp = json_object_new_object (); - json_object_object_add (jresp, "play", json_object_new_string ("success")); - afb_req_success (request, jresp, "Media - Listed"); -} - -static void stop (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - json_object *jresp; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - if (!_rygel_do (ctx, STOP, NULL)) { - afb_req_fail (request, "failed", "could not stop chosen media"); - return; - } - - jresp = json_object_new_object (); - json_object_object_add (jresp, "stop", json_object_new_string ("success")); - afb_req_success (request, jresp, "Media - Stopped"); -} - -static void pausing (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - json_object *jresp; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - if (!_rygel_do (ctx, PAUSE, NULL)) { - afb_req_fail (request, "failed", "could not pause chosen media"); - return; - } - - jresp = json_object_new_object(); - json_object_object_add (jresp, "pause", json_object_new_string ("success")); - afb_req_success (request, jresp, "Media - Paused"); -} - -static void seek (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - /* no "?value=" parameter : return error */ - if (!value) { - afb_req_fail (request, "failed", "you must provide a time"); - return; - } - - if (!_rygel_do (ctx, SEEK, (char *)value)) { - afb_req_fail (request, "failed", "could not seek chosen media"); - return; - } - - jresp = json_object_new_object(); - json_object_object_add (jresp, "seek", json_object_new_string ("success")); - afb_req_success (request, jresp, "Media - Sought"); -} - -static char *renamed_filename(struct afb_arg argfile) -{ - char *result; - const char *e = strrchr(argfile.path, '/'); - if (e == NULL) - result = strdup(argfile.value); - else { - result = malloc((++e - argfile.path) + strlen(argfile.value) + 1); - if (result != NULL) - strcpy(stpncpy(result, argfile.path, e - argfile.path), argfile.value); - } - return result; -} - -static void on_uploaded(struct afb_req *prequest, int status) -{ - struct afb_req request = afb_req_unstore(prequest); - struct afb_arg argfile = afb_req_get(request, "file-upload"); - char *file = renamed_filename(argfile); - if (file != NULL) - unlink(file); - free(file); - if (status) - afb_req_fail (request, "failed", "expected file not received"); - else - afb_req_success_f (request, NULL, "uploaded file %s", argfile.value); - afb_req_unref(request); -} - -static void upload (struct afb_req request) { /* AFB_SESSION_CHECK */ - - mediaCtxHandleT *ctx = afb_req_context_get(request); - struct afb_req *prequest; - struct afb_arg argfile; - char *path; - - /* check that context is initialized */ - if (ctx == NULL) { - afb_req_fail (request, "failed", "uninitialized"); - return; - } - - /* get the file */ - argfile = afb_req_get(request, "file-upload"); - if (!argfile.value || !argfile.path) { - afb_req_fail (request, "failed", "expected file not received"); - return; - } - - /* rename the file */ - path = renamed_filename(argfile); - if (path == NULL) { - afb_req_fail (request, "failed", "out of memory"); - return; - } - if (rename(argfile.path, path) != 0) { - free(path); - afb_req_fail (request, "failed", "system error"); - return; - } - - /* for asynchronous processing */ - prequest = afb_req_store(request); - if (path == NULL) { - unlink(path); - afb_req_fail (request, "failed", "out of memory"); - } - else if (!_rygel_upload (ctx, path, (void*)on_uploaded, prequest)) { - afb_req_unref(afb_req_unstore(prequest)); - unlink(path); - afb_req_fail (request, "failed", "Error when uploading file to media server... could not complete"); - } - free(path); -} - -static void ping (struct afb_req request) { /* AFB_SESSION_NONE */ - afb_req_success (request, NULL, "Media - Ping succeeded"); -} - - -static const struct afb_verb_desc_v1 verbs[]= { - {"init" , AFB_SESSION_CHECK, init , "Media API - init" }, - {"list" , AFB_SESSION_CHECK, list , "Media API - list" }, - {"select" , AFB_SESSION_CHECK, selecting , "Media API - select" }, - {"play" , AFB_SESSION_CHECK, play , "Media API - play" }, - {"stop" , AFB_SESSION_CHECK, stop , "Media API - stop" }, - {"pause" , AFB_SESSION_CHECK, pausing , "Media API - pause" }, - {"seek" , AFB_SESSION_CHECK, seek , "Media API - seek" }, -// {"upload" , AFB_SESSION_CHECK, upload , "Media API - upload" }, - {"ping" , AFB_SESSION_NONE, ping , "Media API - ping" }, - {NULL} -}; - -static const struct afb_binding pluginDesc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder - Media plugin", - .prefix = "media", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &pluginDesc; -} diff --git a/bindings/media/media-api.h b/bindings/media/media-api.h deleted file mode 100644 index 1c7af678..00000000 --- a/bindings/media/media-api.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MEDIA_API_H -#define MEDIA_API_H - -/* -------------- PLUGIN DEFINITIONS ----------------- */ - -/* private client context [will be destroyed when client leaves] */ -typedef struct { - void *media_server; /* handle to implementation (Rygel...) */ - unsigned int index; /* currently selected media file */ -} mediaCtxHandleT; - -#endif /* MEDIA_API_H */ diff --git a/bindings/media/media-rygel.c b/bindings/media/media-rygel.c deleted file mode 100644 index be191921..00000000 --- a/bindings/media/media-rygel.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include - -#include "media-api.h" -#include "media-rygel.h" - -static void _rygel_device_cb (GUPnPControlPoint *, GUPnPDeviceProxy *, gpointer); -static void _rygel_av_transport_cb (GUPnPControlPoint *, GUPnPDeviceProxy *, gpointer); -static void _rygel_content_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); -static void _rygel_metadata_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); -static void _rygel_select_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); -static void _rygel_upload_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); -static void _rygel_transfer_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); -static void _rygel_do_cb (GUPnPServiceProxy *, GUPnPServiceProxyAction *, gpointer); - -static unsigned int client_count = 0; -static struct dev_ctx **dev_ctx = NULL; - -/* -------------- MEDIA RYGEL IMPLEMENTATION ---------------- */ - -/* --- PUBLIC FUNCTIONS --- */ - -unsigned char _rygel_init (mediaCtxHandleT *ctx) { - - GMainContext *loop; - GUPnPContext *context; - GUPnPControlPoint *control_point; - gint handler_cb; - struct timeval tv_start, tv_now; - - context = gupnp_context_new (NULL, NULL, 0, NULL); - - control_point = gupnp_control_point_new (context, URN_MEDIA_SERVER); - - handler_cb = g_signal_connect (control_point, "device-proxy-available", - G_CALLBACK (_rygel_device_cb), ctx); - - /* start searching for servers */ - gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (control_point), TRUE); - - loop = g_main_context_default (); - - /* 5 seconds should be sufficient to find Rygel */ - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (loop, FALSE); - - if (ctx->media_server) - break; - gettimeofday (&tv_now, NULL); - } - /* fail if we found no server */ - if (!ctx->media_server) - return 0; - - /* we have found the server ; stop looking for it... */ - g_signal_handler_disconnect (control_point, handler_cb); - - dev_ctx[client_count]->loop = loop; - dev_ctx[client_count]->context = context; - dev_ctx[client_count]->av_transport = NULL; - dev_ctx[client_count]->state = STOP; - dev_ctx[client_count]->target_state = STOP; - dev_ctx[client_count]->action_args = NULL; - dev_ctx[client_count]->transfer_started = 0; - - client_count++; - - return 1; -} - -void _rygel_free (mediaCtxHandleT *ctx) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server; - - client_count--; - - g_main_context_unref (dev_ctx_c->loop); - dev_ctx_c->loop = NULL; - dev_ctx_c->context = NULL; - dev_ctx_c->device_info = NULL; - dev_ctx_c->av_transport = NULL; - dev_ctx_c->content_dir = NULL; - dev_ctx_c->content_res = NULL; -} - -json_object* _rygel_list (mediaCtxHandleT *ctx) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server; - json_object *json_o, *json_a; - char *raw, *start, *end, *id, *title; - int length, i = 0; - - if (!dev_ctx_c) - return NULL; - - raw = _rygel_list_raw (dev_ctx_c, NULL); - if (!raw) - return NULL; - - start = strstr (raw, ""); - if (!start) - return NULL; - - json_o = json_object_new_object (); - json_a = json_object_new_array (); - while (start) { - json_object *json_i, *json_id, *json_title; - - start = strstr (start, ""); - if (!start) break; - end = strstr (start, ""); - start += 10; - length = end - start; - - asprintf (&id, "%02d", i); - - title = (char*) malloc (length+1); - strncpy (title, start, length); - title[length] = '\0'; - - json_i = json_object_new_object (); - json_id = json_object_new_string (id); - json_title = json_object_new_string (title); - json_object_object_add (json_i, "id", json_id); - json_object_object_add (json_i, "title", json_title); - json_object_array_add (json_a, json_i); - - free (id); free (title); - i++; - } - - json_object_object_add (json_o, "list", json_a); - - return json_o; -} - -unsigned char _rygel_select (mediaCtxHandleT *ctx, unsigned int index) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server; - unsigned int count; - - if (!dev_ctx_c) - return 0; - - if (!_rygel_list_raw (dev_ctx_c, &count) || - index >= count) - return 0; - - if (ctx->index != index) - dev_ctx_c->state = STOP; - - return 1; -} - -unsigned char _rygel_upload (mediaCtxHandleT *ctx, const char *path, void (*oncompletion)(void*,int), void *closure) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server; - char *raw, *upload_id; - - if (!dev_ctx_c) - return 0; - - raw = _rygel_list_raw (dev_ctx_c, NULL); - if (!raw) - return 0; - - /* for now, we always use the same upload container id */ - upload_id = _rygel_find_upload_id (dev_ctx_c, raw); - - return _rygel_start_uploading (dev_ctx_c, strdup(path), upload_id); -} - -unsigned char _rygel_do (mediaCtxHandleT *ctx, State state, char *args) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)ctx->media_server; - unsigned int index = ctx->index; - unsigned int count; - char *raw, *id, *metadata, *uri; - - if (!dev_ctx_c || dev_ctx_c->state == state) - return 0; - - raw = _rygel_list_raw (dev_ctx_c, &count); - if (!raw || index >= count) - return 0; - - id = _rygel_find_id_for_index (dev_ctx_c, raw, index); - metadata = _rygel_find_metadata_for_id (dev_ctx_c, id); - uri = _rygel_find_uri_for_metadata (dev_ctx_c, metadata); - - return _rygel_start_doing (dev_ctx_c, uri, metadata, state, args); -} - -/* --- LOCAL HELPER FUNCTIONS --- */ - -char* _rygel_list_raw (dev_ctx_T* dev_ctx_c, unsigned int *count) { - - GUPnPServiceProxy *content_dir_proxy; - struct timeval tv_start, tv_now; - - dev_ctx_c->content_res = NULL; - dev_ctx_c->content_num = 0; - content_dir_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->content_dir); - - gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, dev_ctx_c, - "ObjectID", G_TYPE_STRING, "Filesystem", - "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren", - "Filter", G_TYPE_STRING, "@childCount", - "StartingIndex", G_TYPE_UINT, 0, - "RequestedCount", G_TYPE_UINT, 64, - "SortCriteria", G_TYPE_STRING, "", - NULL); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->content_res) - break; - gettimeofday (&tv_now, NULL); - } - - if (count) *count = dev_ctx_c->content_num; - return dev_ctx_c->content_res; -} - -char* _rygel_find_upload_id (dev_ctx_T* dev_ctx_c, char *raw) { - - char *found; - char id[33]; - - found = strstr (raw, "parentID=\""); - found += 10; - - /* IDs are 32-bit strings */ - strncpy (id, found, 32); - id[32] = '\0'; - - return strdup (id); -} - -char* _rygel_find_id_for_index (dev_ctx_T* dev_ctx_c, char *raw, unsigned int index) { - - char *found = raw; - char id[33]; - int i; - - for (i = 0; i <= index; i++) { - found = strstr (found, "item id="); - found += 9; - - if (i == index) { - /* IDs are 32-bit strings */ - strncpy (id, found, 32); - id[32] = '\0'; - } - } - - return strdup (id); -} - -char* _rygel_find_metadata_for_id (dev_ctx_T* dev_ctx_c, char *id) { - - GUPnPServiceProxy *content_dir_proxy; - struct timeval tv_start, tv_now; - - dev_ctx_c->content_res = NULL; - - content_dir_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->content_dir); - - gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_metadata_cb, dev_ctx_c, - "ObjectID", G_TYPE_STRING, id, - "BrowseFlag", G_TYPE_STRING, "BrowseMetadata", - "Filter", G_TYPE_STRING, "*", - "StartingIndex", G_TYPE_UINT, 0, - "RequestedCount", G_TYPE_UINT, 0, - "SortCriteria", G_TYPE_STRING, "", - NULL); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->content_res) - break; - gettimeofday (&tv_now, NULL); - } - - return dev_ctx_c->content_res; -} - -char* _rygel_find_uri_for_metadata (dev_ctx_T* dev_ctx_c, char *metadata) { - - char *start, *end, *uri = NULL; - int length; - - /* position ourselves after the first ""); - length = end - start; - - - uri = (char *)malloc (length + 1); - strncpy (uri, start, length); - uri[length] = '\0'; - /* if the URI contains "primary_http", it is the main one ; stop here...*/ - if (strstr (uri, "primary_http")) - break; - - free (uri); start = end; - } - - return uri; -} - -char * _rygel_time_for_string (char *string) { - - int total_seconds; - unsigned int hours, minutes, seconds; - char *time; - - total_seconds = atoi (string); - hours = total_seconds / 3600; - minutes = (total_seconds / 60) - (hours * 60); - seconds = total_seconds - (hours * 3600) - (minutes * 60); - - asprintf (&time, "%u:%02u:%02u", hours, minutes, seconds); - - return time; -} - -unsigned char _rygel_start_uploading (dev_ctx_T* dev_ctx_c, char *path, char *upload_id) { - - GUPnPServiceProxy *content_dir_proxy; - GUPnPDIDLLiteWriter *didl_writer; - GUPnPDIDLLiteObject *didl_object; - char *didl, *content_type, *mime_type, *upnp_class; - struct timeval tv_start, tv_now; - - didl_writer = gupnp_didl_lite_writer_new (NULL); - didl_object = GUPNP_DIDL_LITE_OBJECT (gupnp_didl_lite_writer_add_item (didl_writer)); - - /* create the metadata for the file */ - gupnp_didl_lite_object_set_parent_id (didl_object, upload_id); - gupnp_didl_lite_object_set_id (didl_object, ""); - gupnp_didl_lite_object_set_restricted (didl_object, FALSE); - gupnp_didl_lite_object_set_title (didl_object, g_path_get_basename (path)); - /* deduce the UPnP class from the MIME type ("audio/ogg" e.g.) */ - content_type = g_content_type_guess (path, NULL, 0, NULL); - mime_type = g_content_type_get_mime_type (content_type); - if (strstr (mime_type, "audio/")) - upnp_class = strdup ("object.item.audioItem.musicTrack"); - else if (strstr (mime_type, "video/")) - upnp_class = strdup ("object.item.videoItem"); - else if (strstr (mime_type, "image/")) - upnp_class = strdup ("object.item.imageItem"); - else - upnp_class = strdup ("object.item"); - gupnp_didl_lite_object_set_upnp_class (didl_object, upnp_class); - didl = gupnp_didl_lite_writer_get_string (didl_writer); - - dev_ctx_c->transfer_path = path; - dev_ctx_c->transfer_started = 0; - content_dir_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->content_dir); - - gupnp_service_proxy_begin_action (content_dir_proxy, "CreateObject", _rygel_upload_cb, dev_ctx_c, - "ContainerID", G_TYPE_STRING, upload_id, - "Elements", G_TYPE_STRING, didl, - NULL); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->transfer_started) - break; - gettimeofday (&tv_now, NULL); - } - if (!dev_ctx_c->transfer_started) - return 0; - - return 1; -} - -unsigned char _rygel_start_doing (dev_ctx_T* dev_ctx_c, char *uri, char *metadata, State state, char *args) { - - GUPnPServiceProxy *av_transport_proxy; - struct timeval tv_start, tv_now; - - if (!dev_ctx_c->av_transport) { - if (!_rygel_find_av_transport (dev_ctx_c)) - return 0; - } - dev_ctx_c->target_state = state; - dev_ctx_c->action_args = args; - av_transport_proxy = GUPNP_SERVICE_PROXY (dev_ctx_c->av_transport); - - gupnp_service_proxy_begin_action (av_transport_proxy, "SetAVTransportURI", _rygel_select_cb, dev_ctx_c, - "InstanceID", G_TYPE_UINT, 0, - "CurrentURI", G_TYPE_STRING, uri, - "CurrentURIMetaData", G_TYPE_STRING, metadata, - NULL); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->state == state) - break; - gettimeofday (&tv_now, NULL); - } - if (dev_ctx_c->state != state) - return 0; - - return 1; -} - -unsigned char _rygel_find_av_transport (dev_ctx_T* dev_ctx_c) { - - GUPnPControlPoint *control_point; - gint handler_cb; - struct timeval tv_start, tv_now; - - control_point = gupnp_control_point_new (dev_ctx_c->context, URN_MEDIA_RENDERER); - - handler_cb = g_signal_connect (control_point, "device-proxy-available", - G_CALLBACK (_rygel_av_transport_cb), dev_ctx_c); - - gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (control_point), TRUE); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->av_transport) - break; - gettimeofday (&tv_now, NULL); - } - g_signal_handler_disconnect (control_point, handler_cb); - - if (!dev_ctx_c->av_transport) - return 0; - - return 1; -} - - - /* ---- LOCAL CALLBACK FUNCTIONS ---- */ - -static void _rygel_device_cb (GUPnPControlPoint *point, GUPnPDeviceProxy *proxy, - gpointer data) { - - mediaCtxHandleT *ctx = (mediaCtxHandleT*)data; - GUPnPDeviceInfo *device_info; - GUPnPServiceInfo *content_dir; - const char *device_name; - - device_info = GUPNP_DEVICE_INFO (proxy); - device_name = gupnp_device_info_get_model_name (device_info); - content_dir = gupnp_device_info_get_service (device_info, URN_CONTENT_DIR); - - if (strcmp (device_name, "Rygel") != 0) - return; - if (!content_dir) - return; - - /* allocate the global array if it has not been not done */ - if (!dev_ctx) - dev_ctx = (dev_ctx_T**) malloc (sizeof(dev_ctx_T)); - else - dev_ctx = (dev_ctx_T**) realloc (dev_ctx, (client_count+1)*sizeof(dev_ctx_T)); - - /* create an element for the client in the global array */ - dev_ctx[client_count] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T)); - dev_ctx[client_count]->device_info = device_info; - dev_ctx[client_count]->content_dir = content_dir; - - /* make the client context aware of it */ - ctx->media_server = (void*)dev_ctx[client_count]; -} - -static void _rygel_av_transport_cb (GUPnPControlPoint *point, GUPnPDeviceProxy *proxy, - gpointer data) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GUPnPDeviceInfo *device_info; - GUPnPServiceInfo *av_transport; - - device_info = GUPNP_DEVICE_INFO (proxy); - av_transport = gupnp_device_info_get_service (device_info, URN_AV_TRANSPORT); - - dev_ctx_c->av_transport = av_transport; -} - -static void _rygel_content_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action, - gpointer data) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GUPnPServiceProxy *content_dir_proxy = GUPNP_SERVICE_PROXY (content_dir); - GError *error; - char *result; - guint32 number_returned; - guint32 total_matches; - char *found; - char subid[33]; - - gupnp_service_proxy_end_action (content_dir, action, &error, - "Result", G_TYPE_STRING, &result, - "NumberReturned", G_TYPE_UINT, &number_returned, - "TotalMatches", G_TYPE_UINT, &total_matches, - NULL); - - if (number_returned == 0) - return; - - if (number_returned == 1) { - found = strstr (result, "id=\""); - found += 4; - strncpy (subid, found, 32); subid[32] = '\0'; - - gupnp_service_proxy_begin_action (content_dir_proxy, "Browse", _rygel_content_cb, dev_ctx_c, - "ObjectID", G_TYPE_STRING, subid, - "BrowseFlag", G_TYPE_STRING, "BrowseDirectChildren", - "Filter", G_TYPE_STRING, "@childCount", - "StartingIndex", G_TYPE_UINT, 0, - "RequestedCount", G_TYPE_UINT, 64, - "SortCriteria", G_TYPE_STRING, "", - NULL); - return; - } - - if (number_returned > 1) { - dev_ctx_c->content_res = result; - dev_ctx_c->content_num = number_returned; - } -} - -static void _rygel_metadata_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action, - gpointer data) { - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GError *error; - char *result; - - gupnp_service_proxy_end_action (content_dir, action, &error, - "Result", G_TYPE_STRING, &result, - NULL); - - dev_ctx_c->content_res = result; -} - -static void _rygel_select_cb (GUPnPServiceProxy *av_transport, GUPnPServiceProxyAction *action, - gpointer data) -{ - - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GUPnPServiceProxy *av_transport_proxy; - GError *error; - char *time; - struct timeval tv_start, tv_now; - - av_transport_proxy = GUPNP_SERVICE_PROXY (av_transport); - - gupnp_service_proxy_end_action (av_transport, action, &error, NULL); - - switch (dev_ctx_c->target_state) { - case PLAY: - gupnp_service_proxy_begin_action (av_transport_proxy, "Play", _rygel_do_cb, dev_ctx_c, - "InstanceID", G_TYPE_UINT, 0, - "Speed", G_TYPE_STRING, "1", - NULL); - break; - case PAUSE: - gupnp_service_proxy_begin_action (av_transport_proxy, "Pause", _rygel_do_cb, dev_ctx_c, - "InstanceID", G_TYPE_UINT, 0, - NULL); - break; - case STOP: - gupnp_service_proxy_begin_action (av_transport_proxy, "Stop", _rygel_do_cb, dev_ctx_c, - "InstanceID", G_TYPE_UINT, 0, - NULL); - break; - case SEEK: - time = _rygel_time_for_string (dev_ctx_c->action_args); - gupnp_service_proxy_begin_action (av_transport_proxy, "Seek", _rygel_do_cb, dev_ctx_c, - "InstanceID", G_TYPE_UINT, 0, - "Unit", G_TYPE_STRING, "ABS_TIME", - "Target", G_TYPE_STRING, time, - NULL); - default: - break; - } - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->state == dev_ctx_c->target_state) - break; - gettimeofday (&tv_now, NULL); - } -} - -static void _rygel_upload_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action, - gpointer data) -{ - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GUPnPServiceProxy *content_dir_proxy; - GError *error; - char *result, *start, *end, *dst_uri, *src_uri; - int length; - struct timeval tv_start, tv_now; - - content_dir_proxy = GUPNP_SERVICE_PROXY (content_dir); - - if (!gupnp_service_proxy_end_action (content_dir, action, &error, - "Result", G_TYPE_STRING, &result, - NULL)) - return; - - start = strstr (result, "context), - gupnp_context_get_port (dev_ctx_c->context), - dev_ctx_c->transfer_path); - - /* host the file */ - gupnp_context_host_path (dev_ctx_c->context, dev_ctx_c->transfer_path, - dev_ctx_c->transfer_path); - - gupnp_service_proxy_begin_action (content_dir_proxy, "ImportResource", _rygel_transfer_cb, dev_ctx_c, - "SourceURI", G_TYPE_STRING, src_uri, - "DestinationURI", G_TYPE_STRING, dst_uri, - NULL); - - gettimeofday (&tv_start, NULL); - gettimeofday (&tv_now, NULL); - while (tv_now.tv_sec - tv_start.tv_sec <= 5) { - - g_main_context_iteration (dev_ctx_c->loop, FALSE); - - if (dev_ctx_c->transfer_started) - break; - gettimeofday (&tv_now, NULL); - } -} - -static void _rygel_transfer_cb (GUPnPServiceProxy *content_dir, GUPnPServiceProxyAction *action, - gpointer data) -{ - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GError *error; - guint transfer_id; - - if (!gupnp_service_proxy_end_action (content_dir, action, &error, - "TransferID", G_TYPE_UINT, &transfer_id, - NULL)) - return; - - dev_ctx_c->transfer_started = 1; -} - -static void _rygel_do_cb (GUPnPServiceProxy *av_transport, GUPnPServiceProxyAction *action, - gpointer data) -{ - dev_ctx_T *dev_ctx_c = (dev_ctx_T*)data; - GError *error; - - if (!gupnp_service_proxy_end_action (av_transport, action, &error, - NULL)) - return; - - dev_ctx_c->state = dev_ctx_c->target_state; -} diff --git a/bindings/media/media-rygel.h b/bindings/media/media-rygel.h deleted file mode 100644 index 82a758ac..00000000 --- a/bindings/media/media-rygel.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MEDIA_RYGEL_H -#define MEDIA_RYGEL_H - -/* --------------- MEDIA RYGEL DEFINITIONS ------------------ */ - -#include -#include -#include -#include - -#include "media-api.h" - -#define URN_MEDIA_SERVER "urn:schemas-upnp-org:device:MediaServer:1" -#define URN_MEDIA_RENDERER "urn:schemas-upnp-org:device:MediaRenderer:1" -#define URN_CONTENT_DIR "urn:schemas-upnp-org:service:ContentDirectory" -#define URN_AV_TRANSPORT "urn:schemas-upnp-org:service:AVTransport" - -typedef enum { PLAY, PAUSE, STOP, SEEK } State; -typedef struct dev_ctx dev_ctx_T; - -struct dev_ctx { - GMainContext *loop; - GUPnPContext *context; - GUPnPDeviceInfo *device_info; - GUPnPServiceInfo *content_dir; - GUPnPServiceInfo *av_transport; - char *content_res; - int content_num; - State state; - State target_state; - char *action_args; - char *transfer_path; - unsigned char transfer_started; -}; - -unsigned char _rygel_init (mediaCtxHandleT *); -void _rygel_free (mediaCtxHandleT *); -json_object* _rygel_list (mediaCtxHandleT *); -unsigned char _rygel_select (mediaCtxHandleT *, unsigned int); -unsigned char _rygel_upload (mediaCtxHandleT *ctx, const char *path, void (*oncompletion)(void*,int), void *closure); -unsigned char _rygel_do (mediaCtxHandleT *, State, char *); - -char* _rygel_list_raw (dev_ctx_T *, unsigned int *); -char* _rygel_find_upload_id (dev_ctx_T *, char *); -char* _rygel_find_id_for_index (dev_ctx_T *, char *, unsigned int); -char* _rygel_find_metadata_for_id (dev_ctx_T *, char *); -char* _rygel_find_uri_for_metadata (dev_ctx_T *, char *); -unsigned char _rygel_start_uploading (dev_ctx_T *, char *, char *); -unsigned char _rygel_start_doing (dev_ctx_T *, char *, char *, State, char *); -unsigned char _rygel_find_av_transport (dev_ctx_T *); -#endif /* MEDIA_RYGEL_H */ diff --git a/bindings/radio/CMakeLists.txt b/bindings/radio/CMakeLists.txt deleted file mode 100644 index 4df7adb2..00000000 --- a/bindings/radio/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -INCLUDE(FindPkgConfig) -PKG_CHECK_MODULES(librtlsdr librtlsdr>=0.5.0) - -IF(librtlsdr_FOUND) - - MESSAGE(STATUS "librtlsdr found ; will compile Radio binding... (binding)") - INCLUDE_DIRECTORIES(${include_dirs} ${librtlsdr_INCLUDE_DIRS}) - ADD_LIBRARY(radio-api MODULE radio-api.c radio-rtlsdr.c) - SET_TARGET_PROPERTIES(radio-api PROPERTIES - PREFIX "" - LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/export.map" - ) - TARGET_LINK_LIBRARIES(radio-api ${link_libraries} ${librtlsdr_LIBRARIES} -lm) - INSTALL(TARGETS radio-api - LIBRARY DESTINATION ${binding_install_dir}) - -ENDIF(librtlsdr_FOUND) diff --git a/bindings/radio/export.map b/bindings/radio/export.map deleted file mode 100644 index 0ef1ac79..00000000 --- a/bindings/radio/export.map +++ /dev/null @@ -1 +0,0 @@ -{ global: afbBindingV1Register; local: *; }; diff --git a/bindings/radio/radio-api.c b/bindings/radio/radio-api.c deleted file mode 100644 index 9c1fef6c..00000000 --- a/bindings/radio/radio-api.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include - -#include "radio-api.h" -#include "radio-rtlsdr.h" - -#include -#include - -/* ******************************************************** - - FULUP integration proposal with client session context - - ******************************************************** */ - -/* ------ LOCAL HELPER FUNCTIONS --------- */ - -static pluginHandleT *the_radio = NULL; - -/* detect new radio devices */ -void updateRadioDevList(pluginHandleT *handle) { - - int idx; - - // loop on existing radio if any - for (idx = 0; idx < _radio_dev_count(); idx++) { - if (idx == MAX_RADIO) break; - handle->radios[idx] = calloc(1, sizeof(radioDevT)); /* use calloc to set "used" to FALSE */ - handle->radios[idx]->name = (char *) _radio_dev_name(idx); - } - handle->devCount = _radio_dev_count(); -} - -/* global plugin context creation ; at loading time [radio devices might not be visible] */ -static void initRadioPlugin() { - - pluginHandleT *handle; - - handle = calloc (1, sizeof(pluginHandleT)); - updateRadioDevList (handle); - the_radio = handle; -} - -/* private client context creation ; default values */ -static radioCtxHandleT* initRadioCtx () { - - radioCtxHandleT *ctx; - - ctx = malloc (sizeof(radioCtxHandleT)); - ctx->radio = NULL; - ctx->idx = -1; - ctx->mode = FM; - ctx->freq = 100.0; - ctx->mute = 0; - ctx->is_playing = 0; - - return ctx; -} - -/* reserve a radio device for requesting client, power it on */ -unsigned char reserveRadio (pluginHandleT *handle, radioCtxHandleT *ctx) { - - unsigned int idx; - - /* loop on all devices, find an unused one */ - for (idx = 0; idx < _radio_dev_count(); idx++) { - if (idx == MAX_RADIO) break; - if (handle->radios[idx]->used == FALSE) goto found_radio; /* found one */ - } - return 0; - - found_radio: - /* try to power it on, passing client context info such as frequency... */ - - _radio_on (idx, ctx); - /* TODO : try to re-iterate from the next ones if it failed ! */ - - /* globally mark it as reserved */ - handle->radios[idx]->used = TRUE; - - /* store relevant info to client context (direct pointer, index) */ - ctx->radio = handle->radios[idx]; - ctx->idx = idx; - - return 1; -} - -/* free a radio device from requesting client, power it off */ -unsigned char releaseRadio (pluginHandleT *handle, radioCtxHandleT *ctx) { - - /* stop playing if it was doing this (blocks otherwise) */ - if (ctx->is_playing) { - ctx->is_playing = 0; - _radio_stop (ctx->idx); - } - - /* power it off */ - _radio_off (ctx->idx); - - /* globally mark it as free */ - handle->radios[ctx->idx]->used = FALSE; - - /* clean client context */ - ctx->radio = NULL; - ctx->idx = -1; - - return 1; -} - -/* called when client session dies [e.g. client quits for more than 15mns] */ -static void freeRadio (void *context) { - - releaseRadio (the_radio, context); - free (context); -} - - -/* ------ PUBLIC PLUGIN FUNCTIONS --------- */ - -static void init (struct afb_req request) { /* AFB_SESSION_CHECK */ - - radioCtxHandleT *ctx = afb_req_context_get (request); - json_object *jresp; - - /* create a global plugin handle */ - if (!the_radio) - initRadioPlugin(); - - /* create a private client context */ - if (!ctx) { - ctx = initRadioCtx(); - afb_req_context_set (request, ctx, free); - } - - jresp = json_object_new_object(); - json_object_object_add(jresp, "init", json_object_new_string ("success")); - afb_req_success (request, jresp, "Radio initialized"); -} - -static void power (struct afb_req request) { /* AFB_SESSION_CHECK */ - - pluginHandleT *handle = the_radio; - radioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value) { - ctx->radio ? - json_object_object_add (jresp, "power", json_object_new_string ("on")) - : json_object_object_add (jresp, "power", json_object_new_string ("off")); - afb_req_success (request, jresp, "Radio - Power status obtained"); - return; - } - - /* "?value=" parameter is "1" or "true" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) { - if (!ctx->radio) { - if (!reserveRadio (handle, ctx)) { - afb_req_fail (request, "failed", "no more radio devices available"); - return; - } - } - json_object_object_add (jresp, "power", json_object_new_string ("on")); - } - - /* "?value=" parameter is "0" or "false" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) { - if (ctx->radio) { - if (!releaseRadio (handle, ctx)) { - afb_req_fail (request, "failed", "Unable to release radio device"); - return; - } - } - json_object_object_add (jresp, "power", json_object_new_string ("off")); - } - else - jresp = NULL; - - afb_req_success (request, jresp, "Radio - Power set"); -} - -static void mode (struct afb_req request) { /* AFB_SESSION_CHECK */ - - radioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value || !ctx->radio) { - ctx->mode ? - json_object_object_add (jresp, "mode", json_object_new_string ("AM")) - : json_object_object_add (jresp, "mode", json_object_new_string ("FM")); - } - - /* "?value=" parameter is "1" or "AM" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "AM") ) { - ctx->mode = AM; - _radio_set_mode (ctx->idx, ctx->mode); - json_object_object_add (jresp, "mode", json_object_new_string ("AM")); - } - - /* "?value=" parameter is "0" or "FM" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "FM") ) { - ctx->mode = FM; - _radio_set_mode (ctx->idx, ctx->mode); - json_object_object_add (jresp, "mode", json_object_new_string ("FM")); - } - - afb_req_success (request, jresp, "Radio - Mode set"); -} - -static void freq (struct afb_req request) { /* AFB_SESSION_CHECK */ - - radioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp; - double freq; - char freq_str[256]; - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - jresp = json_object_new_object(); - - /* no "?value=" parameter : return current state */ - if (!value || !ctx->radio) { - snprintf (freq_str, sizeof(freq_str), "%f", ctx->freq); - json_object_object_add (jresp, "freq", json_object_new_string (freq_str)); - } - - /* "?value=" parameter, set frequency */ - else { - freq = strtod (value, NULL); - _radio_set_freq (ctx->idx, freq); - ctx->freq = (float)freq; - - snprintf (freq_str, sizeof(freq_str), "%f", ctx->freq); - json_object_object_add (jresp, "freq", json_object_new_string (freq_str)); - } - - afb_req_success (request, jresp, "Radio - Frequency Set"); -} - -static void mute (struct afb_req request) { /* AFB_SESSION_CHECK */ - - radioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp = json_object_new_object(); - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - - /* no "?value=" parameter : return current state */ - if (!value || !ctx->radio) { - ctx->mute ? - json_object_object_add (jresp, "mute", json_object_new_string ("on")) - : json_object_object_add (jresp, "mute", json_object_new_string ("off")); - } - - /* "?value=" parameter is "1" or "true" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) { - ctx->mute = 1; - _radio_set_mute (ctx->idx, ctx->mute); - json_object_object_add (jresp, "mute", json_object_new_string ("on")); - } - - /* "?value=" parameter is "0" or "false" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "off") ) { - ctx->mute = 0; - _radio_set_mute (ctx->idx, ctx->mute); - json_object_object_add (jresp, "mute", json_object_new_string ("off")); - } - - afb_req_success (request, jresp, "Radio - Mute set"); -} - -static void play (struct afb_req request) { /* AFB_SESSION_CHECK */ - - radioCtxHandleT *ctx = afb_req_context_get (request); - const char *value = afb_req_value (request, "value"); - json_object *jresp = json_object_new_object(); - - if (!ctx) { - afb_req_fail (request, "failed", "you must call 'init' first"); - return; - } - - /* no "?value=" parameter : return current state */ - if (!value || !ctx->radio) { - ctx->is_playing ? - json_object_object_add (jresp, "play", json_object_new_string ("on")) - : json_object_object_add (jresp, "play", json_object_new_string ("off")); - } - - /* "?value=" parameter is "1" or "true" */ - else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) { - /* radio playback */ - ctx->is_playing = 1; - _radio_play (ctx->idx); - json_object_object_add (jresp, "play", json_object_new_string ("on")); - } - - /* "?value=" parameter is "0" or "false" */ - else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) { - /* radio stop */ - ctx->is_playing = 0; - _radio_stop (ctx->idx); - json_object_object_add (jresp, "play", json_object_new_string ("off")); - } - - afb_req_success (request, jresp, "Radio - Play succeeded"); -} - -static void ping (struct afb_req request) { /* AFB_SESSION_NONE */ - afb_req_success (request, NULL, "Radio - Ping succeeded"); -} - - -static const struct afb_verb_desc_v1 verbs[] = { - {"init" , AFB_SESSION_CHECK, init , "Radio API - init"}, - {"power" , AFB_SESSION_CHECK, power , "Radio API - power"}, - {"mode" , AFB_SESSION_CHECK, mode , "Radio API - mode"}, - {"freq" , AFB_SESSION_CHECK, freq , "Radio API - freq"}, - {"mute" , AFB_SESSION_CHECK, mute , "Radio API - mute"}, - {"play" , AFB_SESSION_CHECK, play , "Radio API - play"}, - {"ping" , AFB_SESSION_NONE, ping , "Radio API - ping"}, - {NULL} -}; - -static const struct afb_binding pluginDesc = { - .type = AFB_BINDING_VERSION_1, - .v1 = { - .info = "Application Framework Binder - Radio plugin", - .prefix = "radio", - .verbs = verbs - } -}; - -const struct afb_binding *afbBindingV1Register (const struct afb_binding_interface *itf) -{ - return &pluginDesc; -} diff --git a/bindings/radio/radio-api.h b/bindings/radio/radio-api.h deleted file mode 100644 index e2e7ab20..00000000 --- a/bindings/radio/radio-api.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RADIO_API_H -#define RADIO_API_H - -/* -------------- PLUGIN DEFINITIONS ----------------- */ - -#define MAX_RADIO 10 -typedef enum { FM, AM } Mode; - -/* structure holding one radio device with current usage status */ -typedef struct { - int idx; - char *name; - int used; -} radioDevT; - -/* global plugin handle, should store everything we may need */ -typedef struct { - radioDevT *radios[MAX_RADIO]; // pointer to existing radio - unsigned int devCount; -} pluginHandleT; - -/* private client context [will be destroyed when client leaves] */ -typedef struct { - radioDevT *radio; /* pointer to client radio */ - int idx; /* radio index within global array */ - Mode mode; /* radio mode: AM/FM */ - float freq; /* radio frequency (Mhz) */ - unsigned char mute; /* radio muted: 0(false)/1(true) */ - unsigned char is_playing; /* radio is playing: 0(false)/1(true) */ -} radioCtxHandleT; - -#endif /* RADIO_API_H */ diff --git a/bindings/radio/radio-rtlsdr.c b/bindings/radio/radio-rtlsdr.c deleted file mode 100644 index 3f705cbc..00000000 --- a/bindings/radio/radio-rtlsdr.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -#include "radio-api.h" -#include "radio-rtlsdr.h" - -static void* _dongle_thread_fn (void *); -static void* _demod_thread_fn (void *); -static void* _output_thread_fn (void *); - -static unsigned int init_dev_count = 0; -static struct dev_ctx **dev_ctx = NULL; - -/* ------------- RADIO RTLSDR IMPLEMENTATION ---------------- */ - -/* --- PUBLIC FUNCTIONS --- */ - -/* Radio initialization should be done only when user start the radio and not at plugin initialization - Making this call too early would impose to restart the binder to detect a radio */ -unsigned char _radio_on (unsigned int num, radioCtxHandleT *ctx) { - - if (num >= _radio_dev_count()) - return 0; - - if (init_dev_count < _radio_dev_count()) { - init_dev_count = _radio_dev_count(); - dev_ctx = (dev_ctx_T**) realloc (dev_ctx, init_dev_count * sizeof(dev_ctx_T*)); - } - - dev_ctx[num] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T)); - dev_ctx[num]->dev = NULL; - dev_ctx[num]->mode = ctx->mode; - dev_ctx[num]->freq = ctx->freq; - dev_ctx[num]->mute = ctx->mute; - dev_ctx[num]->should_run = 0; - dev_ctx[num]->dongle = NULL; - dev_ctx[num]->demod = NULL; - dev_ctx[num]->output = NULL; - _radio_dev_init (dev_ctx[num], num); - - return 1; -} - -void _radio_off (unsigned int num) { - - if (num >= _radio_dev_count()) - return; - - if (dev_ctx[num]) { - _radio_dev_free (dev_ctx[num]); - free (dev_ctx[num]); - } - - /* free(dev_ctx); */ -} - -void _radio_set_mode (unsigned int num, Mode mode) { - if (!dev_ctx || !dev_ctx[num]) - return; - - dev_ctx[num]->mode = mode; - _radio_apply_params (dev_ctx[num]); -} - -void _radio_set_freq (unsigned int num, double freq) { - if (!dev_ctx || !dev_ctx[num]) - return; - - dev_ctx[num]->freq = (float)freq; - _radio_apply_params (dev_ctx[num]); -} - -void _radio_set_mute (unsigned int num, unsigned char mute) { - if (!dev_ctx || !dev_ctx[num]) - return; - - dev_ctx[num]->mute = mute; - _radio_apply_params (dev_ctx[num]); -} - -void _radio_play (unsigned int num) { - if (!dev_ctx || !dev_ctx[num]) - return; - - _radio_start_threads (dev_ctx[num]); -} - -void _radio_stop (unsigned int num) { - if (!dev_ctx || !dev_ctx[num]) - return; - - _radio_stop_threads (dev_ctx[num]); -} - -unsigned int _radio_dev_count () { - return rtlsdr_get_device_count(); -} - -const char* _radio_dev_name (unsigned int num) { - return rtlsdr_get_device_name (num); -} - - -/* --- LOCAL HELPER FUNCTIONS --- */ - -unsigned char _radio_dev_init (dev_ctx_T *dev_ctx, unsigned int num) { - rtlsdr_dev_t *dev = dev_ctx->dev; - - if (rtlsdr_open (&dev, num) < 0) - return 0; - - rtlsdr_set_tuner_gain_mode (dev, 0); - - if (rtlsdr_reset_buffer (dev) < 0) - return 0; - - dev_ctx->dev = dev; - - _radio_apply_params (dev_ctx); - - return 1; -} - -unsigned char _radio_dev_free (dev_ctx_T *dev_ctx) { - rtlsdr_dev_t *dev = dev_ctx->dev; - - if (rtlsdr_close (dev) < 0) - return 0; - dev = NULL; - - dev_ctx->dev = dev; - - return 1; -} - -void _radio_apply_params (dev_ctx_T *dev_ctx) { - rtlsdr_dev_t *dev = dev_ctx->dev; - Mode mode = dev_ctx->mode; - float freq = dev_ctx->freq; - int rate; - - freq *= 1000000; - rate = ((1000000 / 200000) + 1) * 200000; - - if (mode == FM) - freq += 16000; - freq += rate / 4; - - rtlsdr_set_center_freq (dev, freq); - rtlsdr_set_sample_rate (dev, rate); - - dev_ctx->dev = dev; -} - -void _radio_start_threads (dev_ctx_T *dev_ctx) { - dev_ctx->dongle = (dongle_ctx*) malloc (sizeof(dongle_ctx)); - dev_ctx->demod = (demod_ctx*) malloc (sizeof(demod_ctx)); - dev_ctx->output = (output_ctx*) malloc (sizeof(output_ctx)); - - dongle_ctx *dongle = dev_ctx->dongle; - demod_ctx *demod = dev_ctx->demod; - output_ctx *output = dev_ctx->output; - - pthread_rwlock_init (&demod->lck, NULL); - pthread_cond_init (&demod->ok, NULL); - pthread_mutex_init (&demod->ok_m, NULL); - pthread_rwlock_init (&output->lck, NULL); - pthread_cond_init (&output->ok, NULL); - pthread_mutex_init (&output->ok_m, NULL); - - dev_ctx->should_run = 1; - - /* dongle thread */ - dongle->thr_finished = 0; - pthread_create (&dongle->thr, NULL, _dongle_thread_fn, (void*)dev_ctx); - - /* demod thread */ - demod->pre_r = demod->pre_j = 0; - demod->now_r = demod->now_j = 0; - demod->index = demod->pre_index = demod->now_index = 0; - demod->thr_finished = 0; - pthread_create (&demod->thr, NULL, _demod_thread_fn, (void*)dev_ctx); - - /* output thread */ - output->thr_finished = 0; - pthread_create (&output->thr, NULL, _output_thread_fn, (void*)dev_ctx); -} - -void _radio_stop_threads (dev_ctx_T *dev_ctx) { - rtlsdr_dev_t *dev = dev_ctx->dev; - dongle_ctx *dongle = dev_ctx->dongle; - demod_ctx *demod = dev_ctx->demod; - output_ctx *output = dev_ctx->output; - - if (!dongle || !demod || !output) - return; - - /* stop each "while" loop in threads */ - dev_ctx->should_run = 0; - - rtlsdr_cancel_async (dev); - pthread_signal (&demod->ok, &demod->ok_m); - pthread_signal (&output->ok, &output->ok_m); - - while (!dongle->thr_finished || - !demod->thr_finished || - !output->thr_finished) - usleep (100000); - - pthread_join (dongle->thr, NULL); - pthread_join (demod->thr, NULL); - pthread_join (output->thr, NULL); - pthread_rwlock_destroy (&demod->lck); - pthread_cond_destroy (&demod->ok); - pthread_mutex_destroy (&demod->ok_m); - pthread_rwlock_destroy (&output->lck); - pthread_cond_destroy (&output->ok); - pthread_mutex_destroy (&output->ok_m); - - free (dongle); dev_ctx->dongle = NULL; - free (demod); dev_ctx->demod = NULL; - free (output); dev_ctx->output = NULL; -} - - /* ---- LOCAL THREADED FUNCTIONS ---- */ - -static void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) { - dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; - dongle_ctx *dongle = dev_ctx->dongle; - demod_ctx *demod = dev_ctx->demod; - unsigned char tmp; - int i; - - if (!dev_ctx->should_run) - return; - - /* rotate 90° */ - for (i = 0; i < (int)len; i += 8) { - tmp = 255 - buf[i+3]; - buf[i+3] = buf[i+2]; - buf[i+2] = tmp; - - buf[i+4] = 255 - buf[i+4]; - buf[i+5] = 255 - buf[i+5]; - - tmp = 255 - buf[i+6]; - buf[i+6] = buf[i+7]; - buf[i+7] = tmp; - } - - /* write data */ - for (i = 0; i < (int)len; i++) - dongle->buf[i] = (int16_t)buf[i] - 127; - - /* lock demod thread, write to it, unlock */ - pthread_rwlock_wrlock (&demod->lck); - memcpy (demod->buf, dongle->buf, 2 * len); - demod->buf_len = len; - pthread_rwlock_unlock (&demod->lck); - pthread_signal (&demod->ok, &demod->ok_m); -} - /**/ -static void* _dongle_thread_fn (void *ctx) { - dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; - dongle_ctx *dongle = dev_ctx->dongle; - - rtlsdr_read_async (dev_ctx->dev, _rtlsdr_callback, dev_ctx, 0, 0); - - dongle->thr_finished = 1; - return 0; -} - -static void _lowpass_demod (void *ctx) { - demod_ctx *demod = (demod_ctx *)ctx; - int i=0, i2=0; - - while (i < demod->buf_len) { - demod->now_r += demod->buf[i]; - demod->now_j += demod->buf[i+1]; - i += 2; - demod->index++; - if (demod->index < ((1000000 / 200000) + 1)) - continue; - demod->buf[i2] = demod->now_r; - demod->buf[i2+1] = demod->now_j; - demod->index = 0; - demod->now_r = demod->now_j = 0; - i2 += 2; - } - demod->buf_len = i2; -} - /**/ -static void _lowpassreal_demod (void *ctx) { - demod_ctx *demod = (demod_ctx *)ctx; - int i=0, i2=0; - int fast = 200000; - int slow = 48000; - - while (i < demod->res_len) { - demod->now_index += demod->res[i]; - i++; - demod->pre_index += slow; - if (demod->pre_index < fast) - continue; - demod->res[i2] = (int16_t)(demod->now_index / (fast/slow)); - demod->pre_index -= fast; - demod->now_index = 0; - i2 += 1; - } - demod->res_len = i2; -} - /**/ -static void _multiply (int ar, int aj, int br, int bj, int *cr, int *cj) { - *cr = ar*br - aj*bj; - *cj = aj*br + ar*bj; -} - /**/ -static int _polar_discriminant (int ar, int aj, int br, int bj) { - int cr, cj; - double angle; - _multiply (ar, aj, br, -bj, &cr, &cj); - angle = atan2 ((double)cj, (double)cr); - return (int)(angle / 3.14159 * (1<<14)); -} - /**/ -static void _fm_demod (void *ctx) { - demod_ctx *demod = (demod_ctx *)ctx; - int16_t *buf = demod->buf; - int buf_len = demod->buf_len; - int pcm, i; - - pcm = _polar_discriminant (buf[0], buf[1], demod->pre_r, demod->pre_j); - demod->res[0] = (int16_t)pcm; - - for (i = 2; i < (buf_len-1); i += 2) { - pcm = _polar_discriminant (buf[i], buf[i+1], buf[i-2], buf[i-1]); - demod->res[i/2] = (int16_t)pcm; - } - demod->pre_r = buf[buf_len - 2]; - demod->pre_j = buf[buf_len - 1]; - demod->res_len = buf_len/2; -} - /**/ -static void _am_demod (void *ctx) { - demod_ctx *demod = (demod_ctx *)ctx; - int16_t *buf = demod->buf; - int buf_len = demod->buf_len; - int pcm, i; - - for (i = 0; i < buf_len; i += 2) { - pcm = buf[i] * buf[i]; - pcm += buf[i+1] * buf[i+1]; - demod->res[i/2] = (int16_t)sqrt(pcm); - } - demod->res_len = buf_len/2; -} - /**/ -static void* _demod_thread_fn (void *ctx) { - dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; - demod_ctx *demod = dev_ctx->demod; - output_ctx *output = dev_ctx->output; - - while(dev_ctx->should_run) { - pthread_wait (&demod->ok, &demod->ok_m); - pthread_rwlock_wrlock (&demod->lck); - _lowpass_demod (demod); - if (dev_ctx->mode == FM) - _fm_demod (demod); - else - _am_demod (demod); - _lowpassreal_demod (demod); - pthread_rwlock_unlock (&demod->lck); - - /* lock demod thread, write to it, unlock */ - pthread_rwlock_wrlock (&output->lck); - memcpy (output->buf, demod->res, 2 * demod->res_len); - output->buf_len = demod->res_len; - pthread_rwlock_unlock (&output->lck); - pthread_signal (&output->ok, &output->ok_m); - } - - demod->thr_finished = 1; - return 0; -} - -static void* _output_thread_fn (void *ctx) { - dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; - output_ctx *output = dev_ctx->output; - FILE *file; - - file = fopen (AUDIO_BUFFER, "wb"); - - while (dev_ctx->should_run) { - pthread_wait (&output->ok, &output->ok_m); - pthread_rwlock_rdlock (&output->lck); - if (!dev_ctx->mute && file) { - fwrite (output->buf, 2, output->buf_len, file); - fflush (file); - fseek (file, 0, SEEK_SET); - } - pthread_rwlock_unlock (&output->lck); - } - if (file) fclose(file); - unlink (AUDIO_BUFFER); - - output->thr_finished = 1; - return 0; -} diff --git a/bindings/radio/radio-rtlsdr.h b/bindings/radio/radio-rtlsdr.h deleted file mode 100644 index 3ee80af8..00000000 --- a/bindings/radio/radio-rtlsdr.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Manuel Bachmann" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RADIO_RTLSDR_H -#define RADIO_RTLSDR_H - -/* -------------- RADIO RTLSDR DEFINITIONS ------------------ */ - -#include -#include -#include - -#include "radio-api.h" - -#define pthread_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m) -#define pthread_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m) -#define BUF_LEN 16*16384 -#define AUDIO_BUFFER "/tmp/audio_buf" - -typedef struct dongle_ctx dongle_ctx; -typedef struct demod_ctx demod_ctx; -typedef struct output_ctx output_ctx; -typedef struct dev_ctx dev_ctx_T; - -struct dongle_ctx { - pthread_t thr; - unsigned char thr_finished; - uint16_t buf[BUF_LEN]; - uint32_t buf_len; -}; - -struct demod_ctx { - pthread_t thr; - unsigned char thr_finished; - pthread_rwlock_t lck; - pthread_cond_t ok; - pthread_mutex_t ok_m; - int pre_r, pre_j, now_r, now_j, index; - int pre_index, now_index; - int16_t buf[BUF_LEN]; - int buf_len; - int16_t res[BUF_LEN]; - int res_len; -}; - -struct output_ctx { - pthread_t thr; - unsigned char thr_finished; - pthread_rwlock_t lck; - pthread_cond_t ok; - pthread_mutex_t ok_m; - int16_t buf[BUF_LEN]; - int buf_len; -}; - -struct dev_ctx { - int used; /* TODO: radio is free ??? */ - rtlsdr_dev_t* dev; - Mode mode; - float freq; - unsigned char mute; - unsigned char should_run; - /* thread contexts */ - dongle_ctx *dongle; - demod_ctx *demod; - output_ctx *output; -}; - -unsigned int _radio_dev_count (void); -const char* _radio_dev_name (unsigned int); - -unsigned char _radio_on (unsigned int, radioCtxHandleT *); -void _radio_off (unsigned int); -void _radio_stop (unsigned int); -void _radio_play (unsigned int); -void _radio_set_mode (unsigned int, Mode); -void _radio_set_freq (unsigned int, double); -void _radio_set_mute (unsigned int, unsigned char); - -unsigned char _radio_dev_init (struct dev_ctx *, unsigned int); -unsigned char _radio_dev_free (struct dev_ctx *); -void _radio_apply_params (struct dev_ctx *); -void _radio_start_threads (struct dev_ctx *); -void _radio_stop_threads (struct dev_ctx *); - -#endif /* RADIO_RTLSDR_H */ -- 2.16.6