mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-03-13 12:40:17 +00:00
Adding mod_vlc initial working version
This commit is contained in:
parent
2ac4557ffc
commit
77f3bd2402
4
src/mod/formats/mod_vlc/Makefile
Normal file
4
src/mod/formats/mod_vlc/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
LOCAL_LDFLAGS= -lvlc
|
14
src/mod/formats/mod_vlc/TODO
Normal file
14
src/mod/formats/mod_vlc/TODO
Normal 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.
|
218
src/mod/formats/mod_vlc/mod_vlc.c
Normal file
218
src/mod/formats/mod_vlc/mod_vlc.c
Normal 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
|
||||
*/
|
Loading…
x
Reference in New Issue
Block a user