From: Anthony Minessale Date: Wed, 18 Mar 2015 22:58:23 +0000 (-0500) Subject: FS-7505: clean up and support multiple formats to same extensions {modname=mod_vlc... X-Git-Tag: v1.6.2~614^2~249 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=52d15f6398cb5d93167c0046a37b81ca4c76f5e8;p=thirdparty%2Ffreeswitch.git FS-7505: clean up and support multiple formats to same extensions {modname=mod_vlc}rtmp://foo.com/flvplayback also move [/tmp]file to be {spool_path=/tmp} --- diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index 89549241f7..f0ae57901c 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -203,7 +203,7 @@ SWITCH_DECLARE(switch_json_api_interface_t *) switch_loadable_module_get_json_ap \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 diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index e1199ca990..49328503c0 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -298,6 +298,17 @@ struct switch_file_interface { 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 */ @@ -360,6 +371,8 @@ struct switch_file_handle { uint32_t cur_channels; uint32_t cur_samplerate; char *stream_name; + char *modname; + switch_mm_t mm; }; /*! \brief Abstract interface to an asr module */ diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 3178d37f4d..b34c09d790 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -1032,7 +1032,6 @@ SWITCH_DECLARE(char *) switch_find_end_paren(const char *s, char open, char clos 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; @@ -1040,18 +1039,14 @@ static inline void switch_separate_file_params(const char *file, char **file_por *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; @@ -1065,19 +1060,12 @@ static inline void switch_separate_file_params(const char *file, char **file_por 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++; } } diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 860977d08e..4fa8a57121 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -6697,7 +6697,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th 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, diff --git a/src/mod/formats/mod_avformat/mod_avformat.c b/src/mod/formats/mod_avformat/mod_avformat.c index 57eeebc93c..5c65df1d52 100644 --- a/src/mod/formats/mod_avformat/mod_avformat.c +++ b/src/mod/formats/mod_avformat/mod_avformat.c @@ -171,7 +171,7 @@ static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AV } /* 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; @@ -203,11 +203,21 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode 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; @@ -220,6 +230,16 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode 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; @@ -307,8 +327,8 @@ static switch_status_t open_audio(AVFormatContext *oc, AVCodec *codec, OutputStr 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(); @@ -402,7 +422,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * continue; } - switch_mutex_lock(eh->mutex); + //switch_mutex_lock(eh->mutex); eh->in_callback = 1; @@ -435,12 +455,14 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * } 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); @@ -586,7 +608,7 @@ SWITCH_STANDARD_APP(record_av_function) 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); @@ -598,7 +620,7 @@ SWITCH_STANDARD_APP(record_av_function) 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; } @@ -1037,7 +1059,8 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl) { 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; @@ -1112,7 +1135,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa 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); } @@ -1170,6 +1193,38 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa 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); @@ -1181,7 +1236,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa 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; } @@ -1292,22 +1347,22 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s 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); @@ -1321,7 +1376,6 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s 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; } @@ -1340,22 +1394,21 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s 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; @@ -1379,7 +1432,7 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_ 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]; diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index af2d8d9403..3edfcdd29f 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -62,7 +62,7 @@ typedef int (*imem_get_t)(void *data, const char *cookie, 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 @@ -158,9 +158,10 @@ void log_cb(void *data, int level, const libvlc_log_t *ctx, const char *fmt, va_ 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: @@ -174,11 +175,19 @@ void log_cb(void *data, int level, const libvlc_log_t *ctx, const char *fmt, va_ 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); } @@ -753,17 +762,8 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p 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; @@ -772,50 +772,6 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p 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")) { @@ -823,34 +779,34 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p 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, @@ -868,7 +824,7 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p "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); } } diff --git a/src/switch_core_file.c b/src/switch_core_file.c index ca29b03bf2..356a96669c 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -80,22 +80,83 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, 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) { @@ -114,26 +175,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, } 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) { @@ -146,7 +194,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, - 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); } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 5ceeab3a28..8ca3769a79 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -477,17 +477,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se 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++; @@ -1210,33 +1215,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess 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++; diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index c9ec5f0e81..de9a42d81b 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -41,6 +41,13 @@ /* for apr file and directory handling */ #include +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; @@ -361,6 +368,8 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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) { @@ -368,10 +377,18 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable 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); } } } @@ -1112,6 +1129,7 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t 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) { @@ -1131,10 +1149,30 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t 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; + } + } } } } @@ -2041,6 +2079,33 @@ SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoin 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] = ""; @@ -2083,7 +2148,6 @@ HASH_FUNC(application) HASH_FUNC(chat_application) HASH_FUNC(api) HASH_FUNC(json_api) -HASH_FUNC(file) HASH_FUNC(speech) HASH_FUNC(asr) HASH_FUNC(directory)