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}
This commit is contained in:
parent
13e60c420d
commit
52d15f6398
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
} else {
|
||||
new_fp = fp;
|
||||
|
||||
fp = parsed;
|
||||
}
|
||||
|
||||
file_path = new_fp;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
/* 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;
|
||||
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue