Adding mod_vlc initial working version

This commit is contained in:
William King 2012-02-23 16:16:55 -08:00
parent 2ac4557ffc
commit 77f3bd2402
3 changed files with 236 additions and 0 deletions

View File

@ -0,0 +1,4 @@
BASE=../../../..
include $(BASE)/build/modmake.rules
LOCAL_LDFLAGS= -lvlc

View File

@ -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.

View File

@ -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
*/