]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Adding mod_vlc initial working version
authorWilliam King <william.king@quentustech.com>
Fri, 24 Feb 2012 00:16:55 +0000 (16:16 -0800)
committerWilliam King <william.king@quentustech.com>
Fri, 24 Feb 2012 00:16:55 +0000 (16:16 -0800)
src/mod/formats/mod_vlc/Makefile [new file with mode: 0644]
src/mod/formats/mod_vlc/TODO [new file with mode: 0644]
src/mod/formats/mod_vlc/mod_vlc.c [new file with mode: 0644]

diff --git a/src/mod/formats/mod_vlc/Makefile b/src/mod/formats/mod_vlc/Makefile
new file mode 100644 (file)
index 0000000..a41d9b3
--- /dev/null
@@ -0,0 +1,4 @@
+BASE=../../../..
+include $(BASE)/build/modmake.rules
+
+LOCAL_LDFLAGS= -lvlc
diff --git a/src/mod/formats/mod_vlc/TODO b/src/mod/formats/mod_vlc/TODO
new file mode 100644 (file)
index 0000000..ea3aacd
--- /dev/null
@@ -0,0 +1,14 @@
+Following list not in priority order.
+
+1. Determine if a new instance is needed for each independant inbound stream, or if a global instance can handle all inbound and outbound streams
+2. Look into libvlc imem and determine if it is possible to stream parts of a call at a time, or if imem requires all of the buffer to be loaded.
+      a. Add and confirm stream over network functionality
+      b. Add and confirm stream to file
+      c. Confirm transcode works to mp3, wav, aac, etc.
+3. Test multiple concurrent listeners to the same stream. 
+      a. Look into have a single libvlc thread stream the file and write to the audio buffer, and multiple readers
+      b. Test multiple input streams simultaniously
+      c. Load test multiple requests(both multiple to the same stream, and multiple unique streams) to look for issues
+4. Enable proper seeking support
+5. Add video support
+6. Confirm streaming from file works on differnt sample rates. 8k, 16k, etc.
diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c
new file mode 100644 (file)
index 0000000..995b202
--- /dev/null
@@ -0,0 +1,218 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * William King william.king@quentustech.com
+ *
+ * mod_vlc.c -- VLC streaming module
+ *
+ * Examples:
+ *
+ * File: vlc:///path/to/file
+ * Stream: http://path.to.file.com:port/file.pls
+ * Stream: vlc://ftp://path.to.file.com:port/file.mp3
+ *
+ * Notes: 
+ *
+ * Requires at least libvlc version 1.2
+ *
+ */
+#include <switch.h>
+#include <vlc/vlc.h>
+#include <vlc/libvlc_media_player.h>
+
+#define VLC_BUFFER_SIZE 4096
+
+static char *vlc_file_supported_formats[SWITCH_MAX_CODECS] = { 0 };
+
+libvlc_instance_t *inst;
+
+struct vlc_file_context {
+       libvlc_media_player_t *mp;
+       libvlc_media_t *m;
+       switch_file_handle_t fh;
+       switch_memory_pool_t *pool;
+       switch_buffer_t *audio_buffer;
+       switch_mutex_t *audio_mutex;
+       char *path;
+       int samples;
+       int playing;
+       int err;
+};
+
+typedef struct vlc_file_context vlc_file_context_t;
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vlc_shutdown);
+SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load);
+SWITCH_MODULE_DEFINITION(mod_vlc, mod_vlc_load, mod_vlc_shutdown, NULL);
+
+void vlc_auto_play_callback(void *data, const void *samples, unsigned count, int64_t pts) {
+       vlc_file_context_t *context = (vlc_file_context_t *) data;
+       
+       switch_mutex_lock(context->audio_mutex);
+       if (context->audio_buffer) {
+               if (!switch_buffer_write(context->audio_buffer, samples, count * 2)) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer error\n");
+               }
+       }
+       switch_mutex_unlock(context->audio_mutex);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC callback for %s %d \n", context->path, count);
+}
+
+static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *path)
+{
+       vlc_file_context_t *context;
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s\n", path);
+       
+       context = switch_core_alloc(handle->memory_pool, sizeof(*context));
+       context->pool = handle->memory_pool;
+
+       context->path = switch_core_strdup(context->pool, path);
+       switch_buffer_create_dynamic(&(context->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 2, 0);
+       
+       /* Determine if this is a url or a path */
+       /* TODO: Change this so that it tries local files first, and then if it fails try location. */
+       if(! strncmp(context->path, "http", 4)){
+               context->m = libvlc_media_new_location(inst, context->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", context->path);
+       } else if (! strncmp(context->path, "/", 1)){
+               context->m = libvlc_media_new_path(inst, context->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", context->path);
+       } else {
+               context->m = libvlc_media_new_location(inst, context->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", context->path);
+       }
+       
+       context->playing = 0;
+       context->err = 0;
+       
+       context->mp = libvlc_media_player_new_from_media(context->m);
+       
+       if ( !handle->samplerate)
+               handle->samplerate = 16000;
+       libvlc_audio_set_format(context->mp, "S16N", handle->samplerate, 1);
+
+       libvlc_audio_set_callbacks(context->mp, vlc_auto_play_callback, NULL,NULL,NULL,NULL, (void *) context);
+       
+       switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool);
+
+       handle->private_info = context;
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       vlc_file_context_t *context = handle->private_info;
+       size_t bytes = *len * sizeof(int16_t);
+       libvlc_state_t status;
+       
+       if (!context) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC read handle context is NULL\n");
+               return SWITCH_STATUS_GENERR;
+       }
+
+       if (context->err) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error\n");
+               return SWITCH_STATUS_GENERR;
+       }
+       
+       if(! context->playing ) {
+               context->playing = 1;
+               libvlc_media_player_play(context->mp);
+       }
+
+       status = libvlc_media_get_state(context->m);
+       if (status == 6 || status == 7) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC media state: %d\n", (int) status);
+               return SWITCH_STATUS_GENERR;
+       }
+       
+       switch_mutex_lock(context->audio_mutex);
+       switch_buffer_read(context->audio_buffer, data, bytes);
+       switch_mutex_unlock(context->audio_mutex);
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t vlc_file_close(switch_file_handle_t *handle)
+{
+       vlc_file_context_t *context = handle->private_info;
+
+       libvlc_media_player_stop(context->mp);
+       libvlc_media_release(context->m);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* Macro expands to: switch_status_t mod_vlc_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
+SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load)
+{
+       switch_file_interface_t *file_interface;
+       const char *args = "-vvv";
+       
+       /* connect my internal structure to the blank pointer passed to me */
+       *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+       vlc_file_supported_formats[0] = "vlc";
+       vlc_file_supported_formats[1] = "http";
+
+       file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
+       file_interface->interface_name = modname;
+       file_interface->extens = vlc_file_supported_formats;
+       file_interface->file_open = vlc_file_open;
+       file_interface->file_close = vlc_file_close;
+       file_interface->file_read = vlc_file_read;
+
+       /* load the vlc engine. */
+       inst = libvlc_new(1, &args);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initialized VLC instance\n");
+
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+  Called when the system shuts down
+  Macro expands to: switch_status_t mod_vlc_shutdown() */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vlc_shutdown)
+{
+       libvlc_release(inst);
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */