\param name the name of the file format
\return the desired file format interface
*/
-SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name);
+SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name, const char *modname);
/*!
\brief Retrieve the speech interface by it's registered name
struct switch_file_interface *next;
};
+typedef struct switch_mm_s {
+ int samplerate;
+ int channels;
+ int keyint;
+ int ab;
+ int vb;
+ int vw;
+ int vh;
+ float fps;
+} switch_mm_t;
+
/*! an abstract representation of a file handle (some parameters based on compat with libsndfile) */
struct switch_file_handle {
/*! the interface of the module that implemented the current file type */
uint32_t cur_channels;
uint32_t cur_samplerate;
char *stream_name;
+ char *modname;
+ switch_mm_t mm;
};
/*! \brief Abstract interface to an asr module */
static inline void switch_separate_file_params(const char *file, char **file_portion, char **params_portion)
{
char *e = NULL;
- int x;
char *space = strdup(file);
file = space;
*file_portion = NULL;
*params_portion = NULL;
- for (x = 0; x < 2; x++) {
- if (*file == '[' && *(file + 1) == *SWITCH_PATH_SEPARATOR) {
- e = switch_find_end_paren(file, '[', ']');
- } else if (*file == '{') {
- e = switch_find_end_paren(file, '{', '}');
- } else {
- break;
- }
+ while (*file == '{') {
+ e = switch_find_end_paren(file, '{', '}');
+ file = e + 1;
+ while(*file == ' ') file++;
}
+
if (e) {
- file = e + 1;
*file_portion = strdup((char *)file);
*++e = '\0';
*params_portion = (char *)space;
static inline switch_bool_t switch_is_file_path(const char *file)
{
const char *e;
- int r, x;
+ int r;
- for (x = 0; x < 2; x++) {
- if (*file == '[' && *(file + 1) == *SWITCH_PATH_SEPARATOR) {
- if ((e = switch_find_end_paren(file, '[', ']'))) {
- file = e + 1;
- }
- } else if (*file == '{') {
- if ((e = switch_find_end_paren(file, '{', '}'))) {
- file = e + 1;
- }
- } else {
- break;
+ while(*file == '{') {
+ if ((e = switch_find_end_paren(file, '{', '}'))) {
+ file = e + 1;
+ while(*file == ' ') file++;
}
}
if (conference->members_with_video && switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) {
flags |= SWITCH_FILE_FLAG_VIDEO;
- if (*rec->path != '{' && conference->canvas) {
+ if (conference->canvas) {
char *orig_path = rec->path;
rec->path = switch_core_sprintf(rec->pool, "{channels=%d,samplerate=%d,vw=%d,vh=%d,fps=%0.2f}%s",
conference->channels,
}
/* Add an output stream. */
-static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
+static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id, switch_mm_t *mm)
{
AVCodecContext *c;
switch_status_t status = SWITCH_STATUS_FALSE;
c->sample_rate = ost->sample_rate = 44100;
c->channels = ost->channels;
c->channel_layout = av_get_default_channel_layout(c->channels);
+
+ if (mm) {
+ if (mm->ab) {
+ c->bit_rate = mm->ab * 1024;
+ }
+ if (mm->samplerate) {
+ c->sample_rate = ost->sample_rate = mm->samplerate;
+ }
+ }
+
break;
case AVMEDIA_TYPE_VIDEO:
c->codec_id = codec_id;
- c->bit_rate = 450000;
+ c->bit_rate = 1000000;
/* Resolution must be a multiple of two. */
c->width = ost->width;
c->height = ost->height;
if (codec_id == AV_CODEC_ID_VP8) {
av_set_options_string(c, "quality=realtime", "=", ":");
}
+
+ if (mm) {
+ if (mm->vb) {
+ c->bit_rate = mm->vb * 1000;
+ }
+ if (mm->keyint) {
+ c->gop_size = mm->keyint;
+ }
+ }
+
break;
default:
break;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "sample_rate: %d nb_samples: %d\n", ost->frame->sample_rate, ost->frame->nb_samples);
- // disable resampler for now before we figure out the correct params
- if (0 && c->sample_fmt != AV_SAMPLE_FMT_S16) {
+
+ if (c->sample_fmt != AV_SAMPLE_FMT_S16) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "sample_fmt %d != AV_SAMPLE_FMT_S16, start resampler\n", c->sample_fmt);
ost->resample_ctx = avresample_alloc_context();
continue;
}
- switch_mutex_lock(eh->mutex);
+ //switch_mutex_lock(eh->mutex);
eh->in_callback = 1;
}
if (got_packet) {
+ switch_mutex_lock(eh->mutex);
ret = write_frame(eh->oc, &eh->video_st->st->codec->time_base, eh->video_st->st, &pkt);
+ switch_mutex_unlock(eh->mutex);
av_free_packet(&pkt);
}
eh->in_callback = 0;
- switch_mutex_unlock(eh->mutex);
+ //switch_mutex_unlock(eh->mutex);
}
switch_img_free(&last_img);
video_st.width = vid_params.width;
video_st.height = vid_params.height;
video_st.next_pts = switch_time_now() / 1000;
- if (add_stream(&video_st, oc, &video_codec, fmt->video_codec) == SWITCH_STATUS_SUCCESS &&
+ if (add_stream(&video_st, oc, &video_codec, fmt->video_codec, NULL) == SWITCH_STATUS_SUCCESS &&
open_video(oc, video_codec, &video_st) == SWITCH_STATUS_SUCCESS) {
avcodec_string(codec_str, sizeof(codec_str), video_st.st->codec, 1);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "use video codec implementation %s\n", codec_str);
audio_st.channels = read_impl.number_of_channels;
audio_st.sample_rate = force_sample_rate;
- add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
+ add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec, NULL);
if (open_audio(oc, audio_codec, &audio_st) != SWITCH_STATUS_SUCCESS) {
goto end;
}
{
switch_log_level_t switch_level = SWITCH_LOG_DEBUG;
- if (level > AV_LOG_INFO) return;
+ /* naggy messages */
+ if (level == AV_LOG_DEBUG || level == AV_LOG_WARNING) return;
switch(level) {
case AV_LOG_QUIET: switch_level = SWITCH_LOG_CONSOLE; break;
memset(context, 0, sizeof(av_file_context_t));
- context->offset = 0; // 1200 ?
+ context->offset = 1200;
if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) {
context->offset = atoi(tmp);
}
if (fmt->audio_codec != AV_CODEC_ID_AAC) {
fmt->audio_codec = AV_CODEC_ID_AAC; // force AAC
}
+
+
+ handle->mm.samplerate = 44100;
+ handle->mm.ab = 128;
+
+ if (handle->mm.vw && handle->mm.vh) {
+ switch(handle->mm.vh) {
+ case 240:
+ handle->mm.vb = 400;
+ break;
+ case 360:
+ handle->mm.vb = 750;
+ break;
+ case 480:
+ handle->mm.vb = 1000;
+ break;
+ case 720:
+ handle->mm.vb = 2500;
+ break;
+ case 1080:
+ handle->mm.vb = 4500;
+ break;
+ default:
+ handle->mm.vb = (handle->mm.vw * handle->mm.vh) / 175;
+ break;
+ }
+ }
+
+ if (handle->mm.fps > 0.0f) {
+ handle->mm.keyint = (int) 2.0f * handle->mm.fps;
+ }
+
}
desc = avcodec_descriptor_get(fmt->video_codec);
context->audio_st.channels = handle->channels;
context->audio_st.sample_rate = handle->samplerate;
- add_stream(&context->audio_st, context->oc, &context->audio_codec, fmt->audio_codec);
+ add_stream(&context->audio_st, context->oc, &context->audio_codec, fmt->audio_codec, &handle->mm);
if (open_audio(context->oc, context->audio_codec, &context->audio_st) != SWITCH_STATUS_SUCCESS) {
goto end;
}
context->offset = 0;
}
- if (context->mutex) switch_mutex_lock(context->mutex);
+
switch_buffer_write(context->audio_buffer, data, datalen);
bytes = context->audio_st.frame->nb_samples * 2 * context->audio_st.st->codec->channels;
- inuse = switch_buffer_inuse(context->audio_buffer);
- while (inuse >= bytes) {
+ //inuse = switch_buffer_inuse(context->audio_buffer);
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "inuse: %d samples: %d bytes: %d\n", inuse, context->audio_st.frame->nb_samples, bytes);
+
+ while ((inuse = switch_buffer_inuse(context->audio_buffer)) >= bytes) {
AVPacket pkt = { 0 };
int got_packet = 0;
int ret;
av_init_packet(&pkt);
- // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "inuse: %d samples: %d bytes: %d\n", inuse, audio_st.frame->nb_samples, bytes);
-
- if (0 && context->audio_st.resample_ctx) { // need resample
+ if (context->audio_st.resample_ctx) { // need resample
int out_samples = avresample_get_out_samples(context->audio_st.resample_ctx, context->audio_st.frame->nb_samples);
av_frame_make_writable(context->audio_st.frame);
if (ret < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while converting %d samples, error text: %s\n",
context->audio_st.frame->nb_samples, get_error_text(ret));
- inuse = switch_buffer_inuse(context->audio_buffer);
continue;
}
if (ret < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error encoding audio frame: %d\n", ret);
- inuse = switch_buffer_inuse(context->audio_buffer);
continue;
}
if (got_packet) {
+ if (context->mutex) switch_mutex_lock(context->mutex);
ret = write_frame(context->oc, &context->audio_st.st->codec->time_base, context->audio_st.st, &pkt);
+ if (context->mutex) switch_mutex_unlock(context->mutex);
if (ret < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while writing audio frame: %s\n", get_error_text(ret));
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
}
-
- inuse = switch_buffer_inuse(context->audio_buffer);
}
- if (context->mutex) switch_mutex_unlock(context->mutex);
+
end:
return status;
context->video_st.width = frame->img->d_w;
context->video_st.height = frame->img->d_h;
context->video_st.next_pts = switch_time_now() / 1000;
- if (add_stream(&context->video_st, context->oc, &context->video_codec, context->oc->oformat->video_codec) == SWITCH_STATUS_SUCCESS &&
+ if (add_stream(&context->video_st, context->oc, &context->video_codec, context->oc->oformat->video_codec, &handle->mm) == SWITCH_STATUS_SUCCESS &&
open_video(context->oc, context->video_codec, &context->video_st) == SWITCH_STATUS_SUCCESS) {
char codec_str[256];
typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
/* Change value to -vvv for vlc related debug. Be careful since vlc is at least as verbose as FS about logging */
-const char *vlc_args[] = {"-vvvv"};
+const char *vlc_args[] = {"-v"};
//const char *vlc_args[] = {"--network-caching=0"};
//--sout-mux-caching
switch_log_level_t fslevel = SWITCH_LOG_DEBUG;
int ret;
- ret = switch_vasprintf(&ldata, fmt, args);
-
- if (ret == -1) return;
+ /* vlc abuses logging too much these leves spew nonsense (comment to do deep testing) */
+ if (level == LIBVLC_DEBUG || level == LIBVLC_WARNING) {
+ return;
+ }
switch(level) {
case LIBVLC_NOTICE:
break;
case LIBVLC_DEBUG:
default:
- fslevel = SWITCH_LOG_DEBUG;
+ fslevel = SWITCH_LOG_DEBUG1;
break;
}
+
+ ret = switch_vasprintf(&ldata, fmt, args);
+
+ if (ret == -1) return;
- switch_log_printf(SWITCH_CHANNEL_LOG, fslevel, "%s\n", ldata);
+ if (end_of(ldata) == '\n') {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, fslevel, "VLC: %s", ldata);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, fslevel, "VLC: %s\n", ldata);
+ }
switch_safe_free(ldata);
}
char *ext = NULL;
switch_file_t *fd = NULL;
const char *realpath = NULL;
- float fps = 0.0f;
int is_stream = 0;
- int samplerate = 44100;
- int channels = 1;
- int keyint = 60;
- int ab = 0;
- int vb = 0;
- int vw = 0;
- int vh = 0;
- int tmp;
- const char *val;
+
context = switch_core_alloc(handle->memory_pool, sizeof(*context));
context->pool = handle->memory_pool;
realpath = path;
- if (handle->params) {
- if ((val = switch_event_get_header(handle->params, "samplerate"))) {
- tmp = atoi(val);
- if (tmp > 8000) {
- samplerate = tmp;
- }
- }
-
- if ((val = switch_event_get_header(handle->params, "channels"))) {
- tmp = atoi(val);
- if (tmp == 1 || tmp == 2) {
- channels = tmp;
- }
- }
-
- if ((val = switch_event_get_header(handle->params, "ab"))) {
- tmp = atoi(val);
- if (tmp > 16) {
- ab = tmp;
- }
- }
-
- if ((val = switch_event_get_header(handle->params, "vw"))) {
- tmp = atoi(val);
- if (tmp > 0) {
- vw = tmp;
- }
- }
-
- if ((val = switch_event_get_header(handle->params, "vh"))) {
- tmp = atoi(val);
- if (tmp > 0) {
- vh = tmp;
- }
- }
-
- if ((val = switch_event_get_header(handle->params, "fps"))) {
- float ftmp = atof(val);
- if (ftmp > 0.0f) {
- fps = ftmp;
- }
- }
- }
-
if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) && switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
if ((ext = strrchr(path, '.')) && !strcasecmp(ext, ".mp4")) {
path = switch_core_sprintf(context->pool, "#transcode{vcodec=h264,acodec=mp3}:std{access=file,mux=mp4,dst=%s}", path);
} else if (handle->stream_name && (!strcasecmp(handle->stream_name, "rtmp") || !strcasecmp(handle->stream_name, "youtube"))) {
- samplerate = 44100;
- ab = 128;
+ handle->mm.samplerate = 44100;
+ handle->mm.ab = 128;
- if (vw && vh) {
- switch(vh) {
+ if (handle->mm.vw && handle->mm.vh) {
+ switch(handle->mm.vh) {
case 240:
- vb = 400;
+ handle->mm.vb = 400;
break;
case 360:
- vb = 750;
+ handle->mm.vb = 750;
break;
case 480:
- vb = 1000;
+ handle->mm.vb = 1000;
break;
case 720:
- vb = 2500;
+ handle->mm.vb = 2500;
break;
case 1080:
- vb = 4500;
+ handle->mm.vb = 4500;
break;
default:
- vb = (vw * vh) / 175;
+ handle->mm.vb = (handle->mm.vw * handle->mm.vh) / 175;
break;
}
}
- if (fps > 0.0f) {
- keyint = (int) 2.0f * fps;
+ if (handle->mm.fps > 0.0f) {
+ handle->mm.keyint = (int) 2.0f * handle->mm.fps;
}
path = switch_core_sprintf(context->pool,
"mux=flv,"
"dst=rtmp://%s"
"}",
- keyint, ab, vb, channels, samplerate, path);
+ handle->mm.keyint, handle->mm.ab, handle->mm.vb, handle->mm.channels, handle->mm.samplerate, path);
}
}
switch_set_flag(fh, SWITCH_FILE_FLAG_FREE_POOL);
}
+ fh->mm.samplerate = 44100;
+ fh->mm.channels = 1;
+ fh->mm.keyint = 60;
+ fh->mm.ab = 128;
+
if (*file_path == '{') {
char *timeout;
- char *new_fp;
+ char *modname;
+ const char *val;
+ int tmp;
+
fp = switch_core_strdup(fh->memory_pool, file_path);
- if (switch_event_create_brackets(fp, '{', '}', ',', &fh->params, &new_fp, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
- if ((timeout = switch_event_get_header(fh->params, "timeout"))) {
- if ((to = atoi(timeout)) < 1) {
- to = 0;
- }
+ while (*fp == '{') {
+ char *parsed = NULL;
+
+ if (switch_event_create_brackets(fp, '{', '}', ',', &fh->params, &parsed, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS || !parsed) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
+ goto fail;
+ }
+
+ fp = parsed;
+ }
+
+ file_path = fp;
+
+ if ((timeout = switch_event_get_header(fh->params, "timeout"))) {
+ if ((to = atoi(timeout)) < 1) {
+ to = 0;
+ }
+ }
+
+ if ((modname = switch_event_get_header(fh->params, "modname"))) {
+ fh->modname = switch_core_strdup(fh->memory_pool, modname);
+ }
+
+ if ((val = switch_event_get_header(fh->params, "samplerate"))) {
+ tmp = atoi(val);
+ if (tmp > 8000) {
+ fh->mm.samplerate = tmp;
+ }
+ }
+
+ if ((val = switch_event_get_header(fh->params, "channels"))) {
+ tmp = atoi(val);
+ if (tmp == 1 || tmp == 2) {
+ fh->mm.channels = tmp;
+ }
+ }
+
+ if ((val = switch_event_get_header(fh->params, "ab"))) {
+ tmp = atoi(val);
+ if (tmp > 16) {
+ fh->mm.ab = tmp;
+ }
+ }
+
+ if ((val = switch_event_get_header(fh->params, "vw"))) {
+ tmp = atoi(val);
+ if (tmp > 0) {
+ fh->mm.vw = tmp;
+ }
+ }
+
+ if ((val = switch_event_get_header(fh->params, "vh"))) {
+ tmp = atoi(val);
+ if (tmp > 0) {
+ fh->mm.vh = tmp;
}
- } else {
- new_fp = fp;
}
- file_path = new_fp;
+ if ((val = switch_event_get_header(fh->params, "fps"))) {
+ float ftmp = atof(val);
+ if (ftmp > 0.0f) {
+ fh->mm.fps = ftmp;
+ }
+ }
}
if (switch_directory_exists(file_path, fh->memory_pool) == SWITCH_STATUS_SUCCESS) {
} else {
if ((flags & SWITCH_FILE_FLAG_WRITE)) {
- char *p, *e;
-
- fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
- p = fh->file_path;
-
- if (*p == '[' && *(p + 1) == *SWITCH_PATH_SEPARATOR) {
- e = switch_find_end_paren(p, '[', ']');
-
- if (e) {
- *e = '\0';
- spool_path = p + 1;
- fh->file_path = e + 1;
- }
+ if (fh->params) {
+ spool_path = switch_event_get_header(fh->params, "spool_path");
}
if (!spool_path) {
spool_path = switch_core_get_variable_pdup(SWITCH_AUDIO_SPOOL_PATH_VARIABLE, fh->memory_pool);
}
-
- file_path = fh->file_path;
}
if ((ext = strrchr(file_path, '.')) == 0) {
- if ((fh->file_interface = switch_loadable_module_get_file_interface(ext)) == 0) {
+ if ((fh->file_interface = switch_loadable_module_get_file_interface(ext, fh->modname)) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid file format [%s] for [%s]!\n", ext, file_path);
switch_goto_status(SWITCH_STATUS_GENERR, fail);
}
char *tfile = NULL;
char *e;
- if (*file == '[') {
+ if (*file == '{') {
tfile = switch_core_session_strdup(session, file);
- if ((e = switch_find_end_paren(tfile, '[', ']'))) {
- *e = '\0';
- file = e + 1;
- } else {
- tfile = NULL;
+
+ while (*file == '{') {
+ if ((e = switch_find_end_paren(tfile, '{', '}'))) {
+ *e = '\0';
+ file = e + 1;
+ while(*file == ' ') file++;
+ } else {
+ tfile = NULL;
+ break;
+ }
}
}
-
- file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
+
+ file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "}" : "", prefix, SWITCH_PATH_SEPARATOR, file);
}
if ((ext = strrchr(file, '.'))) {
ext++;
if (!strstr(file, SWITCH_URL_SEPARATOR)) {
if (!switch_is_file_path(file)) {
- char *tfile = NULL, *tfile2 = NULL;
+ char *tfile = NULL;
char *e;
- int x;
- for (x = 0; x < 2; x++) {
- if (*file == '[') {
- tfile = switch_core_session_strdup(session, file);
- if ((e = switch_find_end_paren(tfile, '[', ']'))) {
+ if (*file == '{') {
+ tfile = switch_core_session_strdup(session, file);
+
+ while (*file == '{') {
+ if ((e = switch_find_end_paren(tfile, '{', '}'))) {
*e = '\0';
file = e + 1;
+ while(*file == ' ') file++;
} else {
tfile = NULL;
+ break;
}
- } else if (*file == '{') {
- tfile2 = switch_core_session_strdup(session, file);
- if ((e = switch_find_end_paren(tfile2, '{', '}'))) {
- *e = '\0';
- file = e + 1;
- } else {
- tfile2 = NULL;
- }
- } else {
- break;
}
}
- file = switch_core_session_sprintf(session, "%s%s%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", switch_str_nil(tfile2), tfile2 ? "}" : "", prefix, SWITCH_PATH_SEPARATOR, file);
+ file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "}" : "", prefix, SWITCH_PATH_SEPARATOR, file);
}
if ((ext = strrchr(file, '.'))) {
ext++;
/* for apr file and directory handling */
#include <apr_file_io.h>
+typedef struct switch_file_node_s {
+ const switch_file_interface_t *ptr;
+ const char *interface_name;
+ struct switch_file_node_s *next;
+} switch_file_node_t;
+
+
struct switch_loadable_module {
char *key;
char *filename;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load file interface from %s due to no file extensions.\n", key);
} else {
int i;
+ switch_file_node_t *node, *head;
+
for (i = 0; ptr->extens[i]; i++) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding File Format '%s'\n", ptr->extens[i]);
if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->extens[i]);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
switch_event_fire(&event);
added++;
}
- switch_core_hash_insert(loadable_modules.file_hash, ptr->extens[i], (const void *) ptr);
+ node = switch_core_alloc(new_module->pool, sizeof(*node));
+ node->ptr = ptr;
+ node->interface_name = switch_core_strdup(new_module->pool, new_module->module_interface->module_name);
+ if ((head = switch_core_hash_find(loadable_modules.file_hash, ptr->extens[i]))) {
+ node->next = head;
+ }
+
+ switch_core_hash_insert(loadable_modules.file_hash, ptr->extens[i], (const void *) node);
}
}
}
if (old_module->module_interface->file_interface) {
const switch_file_interface_t *ptr;
+ switch_file_node_t *node, *head, *last = NULL;
for (ptr = old_module->module_interface->file_interface; ptr; ptr = ptr->next) {
if (ptr->interface_name) {
if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "file");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->extens[i]);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", old_module->module_interface->module_name);
switch_event_fire(&event);
removed++;
}
- switch_core_hash_delete(loadable_modules.file_hash, ptr->extens[i]);
+
+ if ((head = switch_core_hash_find(loadable_modules.file_hash, ptr->extens[i]))) {
+ for(node = head; node; node = node->next) {
+ if (!strcmp(node->interface_name, old_module->module_interface->module_name)) {
+ if (node == head) {
+ if ((node = node->next)) {
+ switch_core_hash_insert(loadable_modules.file_hash, ptr->extens[i], (const void *) node);
+ } else {
+ switch_core_hash_delete(loadable_modules.file_hash, ptr->extens[i]);
+ }
+ } else {
+ if (last) {
+ last->next = node->next;
+ }
+ }
+ break;
+ }
+ last = node;
+ }
+ }
}
}
}
return ptr;
}
+SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name, const char *modname)
+{
+ switch_file_interface_t *i = NULL;
+ switch_file_node_t *node, *head;
+
+ switch_mutex_lock(loadable_modules.mutex);
+
+ if ((head = switch_core_hash_find(loadable_modules.file_hash, name))) {
+ if (modname) {
+ for (node = head; node; node = node->next) {
+ if (!strcasecmp(node->interface_name, modname)) {
+ i = (switch_file_interface_t *) node->ptr;
+ break;
+ }
+ }
+ } else {
+ i = (switch_file_interface_t *) head->ptr;
+ }
+ }
+
+ switch_mutex_unlock(loadable_modules.mutex);
+
+ if (i) PROTECT_INTERFACE(i);
+
+ return i;
+}
+
SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name)
{
char altname[256] = "";
HASH_FUNC(chat_application)
HASH_FUNC(api)
HASH_FUNC(json_api)
-HASH_FUNC(file)
HASH_FUNC(speech)
HASH_FUNC(asr)
HASH_FUNC(directory)