SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(_In_ switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags,
int stream_id);
+SWITCH_DECLARE(switch_bool_t) switch_core_session_transcoding(switch_core_session_t *session_a, switch_core_session_t *session_b, switch_media_type_t type);
+SWITCH_DECLARE(void) switch_core_session_passthru(switch_core_session_t *session, switch_media_type_t type, switch_bool_t on);
+
/*!
\brief Read a video frame from a session
\param session the session to read from
unsigned int samples;
/*! current sample count based on samples parameter */
uint32_t samplecount;
+ uint32_t last_samplecount;
/*! the timer interface provided from a loadable module */
switch_timer_interface_t *timer_interface;
/*! the timer's memory pool */
SWITCH_RTP_FLAG_MUTE,
SWITCH_RTP_FLAG_NACK,
SWITCH_RTP_FLAG_TMMBR,
- SWITCH_RTP_FLAG_GEN_TS_DELTA,
- SWITCH_RTP_FLAG_GEN_TS_MANUAL,
SWITCH_RTP_FLAG_DETECT_SSRC,
SWITCH_RTP_FLAG_TEXT,
SWITCH_RTP_FLAG_OLD_FIR,
+ SWITCH_RTP_FLAG_PASSTHRU,
SWITCH_RTP_FLAG_INVALID
} switch_rtp_flag_t;
*/
-
} switch_rtp_bug_flag_t;
#ifdef _MSC_VER
uint32_t width;
uint32_t height;
uint32_t fps;
+ uint32_t d_width;
+ uint32_t d_height;
} switch_vid_params_t;
SFF_USE_VIDEO_TIMESTAMP = (1 << 16),
SFF_ENCODED = (1 << 17),
SFF_TEXT_LINE_BREAK = (1 << 18),
- SFF_IS_KEYFRAME = (1 << 19)
+ SFF_IS_KEYFRAME = (1 << 19),
+ SFF_EXTERNAL = (1 << 20)
} switch_frame_flag_enum_t;
typedef uint32_t switch_frame_flag_t;
if (conference->canvases[node->canvas_id]->timer.timer_interface) {
conference->canvases[node->canvas_id]->timer.interval = conference->video_fps.ms;
conference->canvases[node->canvas_id]->timer.samples = conference->video_fps.samples;
- switch_core_timer_sync(&conference->canvases[node->canvas_id]->timer);
conference->canvases[node->canvas_id]->send_keyframe = 1;
}
conference->playing_video_file = 0;
}
if (frame->timestamp) {
- switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
+ switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME|SFF_USE_VIDEO_TIMESTAMP);
}
frame->packetlen = frame->datalen + 12;
switch_core_session_request_video_refresh(imember->session);
}
- if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
+ if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY ||
+ switch_channel_test_flag(imember->channel, CF_VIDEO_WRITING) ||
+ switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
switch_core_session_rwunlock(imember->session);
continue;
}
if (!imember->rec &&
(!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO_READY) || !imember->canvas ||
+ switch_channel_test_flag(imember->channel, CF_VIDEO_WRITING) ||
switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS)) {
continue;
}
switch_core_session_request_video_refresh(imember->session);
}
- if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
+ if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY ||
+ switch_channel_test_flag(imember->channel, CF_VIDEO_WRITING) ||
+ switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
switch_core_session_rwunlock(imember->session);
continue;
}
conference_video_set_canvas_fgimg(canvas, NULL);
}
- switch_set_flag(&write_frame, SFF_RAW_RTP);
+ switch_set_flag(&write_frame, SFF_RAW_RTP|SFF_USE_VIDEO_TIMESTAMP|SFF_RAW_RTP_PARSE_FRAME);
write_frame.img = write_img;
write_frame.packet = packet;
write_frame.data = ((uint8_t *)packet) + 12;
write_frame.datalen = 0;
write_frame.buflen = SWITCH_RTP_MAX_BUF_LEN - 12;
write_frame.packetlen = 0;
+ write_frame.timestamp = timestamp;
//switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
switch_core_session_request_video_refresh(imember->session);
}
- if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
+ if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY ||
+ switch_channel_test_flag(imember->channel, CF_VIDEO_WRITING) ||
+ switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
switch_core_session_rwunlock(imember->session);
continue;
}
}
+SWIGEXPORT void SWIGSTDCALL CSharp_switch_vid_params_t_d_width_set(void * jarg1, unsigned long jarg2) {
+ switch_vid_params_s *arg1 = (switch_vid_params_s *) 0 ;
+ uint32_t arg2 ;
+
+ arg1 = (switch_vid_params_s *)jarg1;
+ arg2 = (uint32_t)jarg2;
+ if (arg1) (arg1)->d_width = arg2;
+}
+
+
+SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_vid_params_t_d_width_get(void * jarg1) {
+ unsigned long jresult ;
+ switch_vid_params_s *arg1 = (switch_vid_params_s *) 0 ;
+ uint32_t result;
+
+ arg1 = (switch_vid_params_s *)jarg1;
+ result = (uint32_t) ((arg1)->d_width);
+ jresult = (unsigned long)result;
+ return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_switch_vid_params_t_d_height_set(void * jarg1, unsigned long jarg2) {
+ switch_vid_params_s *arg1 = (switch_vid_params_s *) 0 ;
+ uint32_t arg2 ;
+
+ arg1 = (switch_vid_params_s *)jarg1;
+ arg2 = (uint32_t)jarg2;
+ if (arg1) (arg1)->d_height = arg2;
+}
+
+
+SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_vid_params_t_d_height_get(void * jarg1) {
+ unsigned long jresult ;
+ switch_vid_params_s *arg1 = (switch_vid_params_s *) 0 ;
+ uint32_t result;
+
+ arg1 = (switch_vid_params_s *)jarg1;
+ result = (uint32_t) ((arg1)->d_height);
+ jresult = (unsigned long)result;
+ return jresult;
+}
+
+
SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_vid_params_t() {
void * jresult ;
switch_vid_params_s *result = 0 ;
}
+SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_transcoding(void * jarg1, void * jarg2, int jarg3) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_core_session_t *arg2 = (switch_core_session_t *) 0 ;
+ switch_media_type_t arg3 ;
+ switch_bool_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (switch_core_session_t *)jarg2;
+ arg3 = (switch_media_type_t)jarg3;
+ result = (switch_bool_t)switch_core_session_transcoding(arg1,arg2,arg3);
+ jresult = result;
+ return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_switch_core_session_passthru(void * jarg1, int jarg2, int jarg3) {
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_media_type_t arg2 ;
+ switch_bool_t arg3 ;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (switch_media_type_t)jarg2;
+ arg3 = (switch_bool_t)jarg3;
+ switch_core_session_passthru(arg1,arg2,arg3);
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_read_video_frame(void * jarg1, void * jarg2, unsigned long jarg3, int jarg4) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
}
+SWIGEXPORT void SWIGSTDCALL CSharp_switch_timer_last_samplecount_set(void * jarg1, unsigned long jarg2) {
+ switch_timer *arg1 = (switch_timer *) 0 ;
+ uint32_t arg2 ;
+
+ arg1 = (switch_timer *)jarg1;
+ arg2 = (uint32_t)jarg2;
+ if (arg1) (arg1)->last_samplecount = arg2;
+}
+
+
+SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_timer_last_samplecount_get(void * jarg1) {
+ unsigned long jresult ;
+ switch_timer *arg1 = (switch_timer *) 0 ;
+ uint32_t result;
+
+ arg1 = (switch_timer *)jarg1;
+ result = (uint32_t) ((arg1)->last_samplecount);
+ jresult = (unsigned long)result;
+ return jresult;
+}
+
+
SWIGEXPORT void SWIGSTDCALL CSharp_switch_timer_timer_interface_set(void * jarg1, void * jarg2) {
switch_timer *arg1 = (switch_timer *) 0 ;
switch_timer_interface_t *arg2 = (switch_timer_interface_t *) 0 ;
return ret;
}
+ public static switch_bool_t switch_core_session_transcoding(SWIGTYPE_p_switch_core_session session_a, SWIGTYPE_p_switch_core_session session_b, switch_media_type_t type) {
+ switch_bool_t ret = (switch_bool_t)freeswitchPINVOKE.switch_core_session_transcoding(SWIGTYPE_p_switch_core_session.getCPtr(session_a), SWIGTYPE_p_switch_core_session.getCPtr(session_b), (int)type);
+ return ret;
+ }
+
+ public static void switch_core_session_passthru(SWIGTYPE_p_switch_core_session session, switch_media_type_t type, switch_bool_t on) {
+ freeswitchPINVOKE.switch_core_session_passthru(SWIGTYPE_p_switch_core_session.getCPtr(session), (int)type, (int)on);
+ }
+
public static switch_status_t switch_core_session_read_video_frame(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_frame frame, uint flags, int stream_id) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_read_video_frame(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_frame.getCPtr(frame), flags, stream_id);
return ret;
[DllImport("mod_managed", EntryPoint="CSharp_switch_vid_params_t_fps_get")]
public static extern uint switch_vid_params_t_fps_get(HandleRef jarg1);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_vid_params_t_d_width_set")]
+ public static extern void switch_vid_params_t_d_width_set(HandleRef jarg1, uint jarg2);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_vid_params_t_d_width_get")]
+ public static extern uint switch_vid_params_t_d_width_get(HandleRef jarg1);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_vid_params_t_d_height_set")]
+ public static extern void switch_vid_params_t_d_height_set(HandleRef jarg1, uint jarg2);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_vid_params_t_d_height_get")]
+ public static extern uint switch_vid_params_t_d_height_get(HandleRef jarg1);
+
[DllImport("mod_managed", EntryPoint="CSharp_new_switch_vid_params_t")]
public static extern IntPtr new_switch_vid_params_t();
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_read_frame")]
public static extern int switch_core_session_read_frame(HandleRef jarg1, HandleRef jarg2, uint jarg3, int jarg4);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_transcoding")]
+ public static extern int switch_core_session_transcoding(HandleRef jarg1, HandleRef jarg2, int jarg3);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_passthru")]
+ public static extern void switch_core_session_passthru(HandleRef jarg1, int jarg2, int jarg3);
+
[DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_read_video_frame")]
public static extern int switch_core_session_read_video_frame(HandleRef jarg1, HandleRef jarg2, uint jarg3, int jarg4);
[DllImport("mod_managed", EntryPoint="CSharp_switch_timer_samplecount_get")]
public static extern uint switch_timer_samplecount_get(HandleRef jarg1);
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_timer_last_samplecount_set")]
+ public static extern void switch_timer_last_samplecount_set(HandleRef jarg1, uint jarg2);
+
+ [DllImport("mod_managed", EntryPoint="CSharp_switch_timer_last_samplecount_get")]
+ public static extern uint switch_timer_last_samplecount_get(HandleRef jarg1);
+
[DllImport("mod_managed", EntryPoint="CSharp_switch_timer_timer_interface_set")]
public static extern void switch_timer_timer_interface_set(HandleRef jarg1, HandleRef jarg2);
SFF_USE_VIDEO_TIMESTAMP = (1 << 16),
SFF_ENCODED = (1 << 17),
SFF_TEXT_LINE_BREAK = (1 << 18),
- SFF_IS_KEYFRAME = (1 << 19)
+ SFF_IS_KEYFRAME = (1 << 19),
+ SFF_EXTERNAL = (1 << 20)
}
}
SWITCH_RTP_FLAG_MUTE,
SWITCH_RTP_FLAG_NACK,
SWITCH_RTP_FLAG_TMMBR,
- SWITCH_RTP_FLAG_GEN_TS_DELTA,
- SWITCH_RTP_FLAG_GEN_TS_MANUAL,
SWITCH_RTP_FLAG_DETECT_SSRC,
SWITCH_RTP_FLAG_TEXT,
SWITCH_RTP_FLAG_OLD_FIR,
+ SWITCH_RTP_FLAG_PASSTHRU,
SWITCH_RTP_FLAG_INVALID
}
}
}
+ public uint last_samplecount {
+ set {
+ freeswitchPINVOKE.switch_timer_last_samplecount_set(swigCPtr, value);
+ }
+ get {
+ uint ret = freeswitchPINVOKE.switch_timer_last_samplecount_get(swigCPtr);
+ return ret;
+ }
+ }
+
public switch_timer_interface timer_interface {
set {
freeswitchPINVOKE.switch_timer_timer_interface_set(swigCPtr, switch_timer_interface.getCPtr(value));
}
}
+ public uint d_width {
+ set {
+ freeswitchPINVOKE.switch_vid_params_t_d_width_set(swigCPtr, value);
+ }
+ get {
+ uint ret = freeswitchPINVOKE.switch_vid_params_t_d_width_get(swigCPtr);
+ return ret;
+ }
+ }
+
+ public uint d_height {
+ set {
+ freeswitchPINVOKE.switch_vid_params_t_d_height_set(swigCPtr, value);
+ }
+ get {
+ uint ret = freeswitchPINVOKE.switch_vid_params_t_d_height_get(swigCPtr);
+ return ret;
+ }
+ }
+
public switch_vid_params_t() : this(freeswitchPINVOKE.new_switch_vid_params_t(), true) {
}
typedef enum {
SMF_INIT = (1 << 0),
SMF_READY = (1 << 1),
- SMF_JB_PAUSED = (1 << 2)
+ SMF_JB_PAUSED = (1 << 2),
+ SMF_VB_PAUSED = (1 << 3)
} smh_flag_t;
switch_media_flow_t rmode;
switch_media_flow_t smode;
switch_thread_id_t thread_id;
+ switch_thread_id_t thread_write_lock;
uint8_t new_ice;
uint8_t new_dtls;
uint32_t sdp_bw;
engine = &smh->engines[type];
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ if (engine->thread_write_lock && engine->thread_write_lock != switch_thread_self()) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+ }
if (switch_channel_test_flag(session->channel, CF_VIDEO_ONLY) && type == SWITCH_MEDIA_TYPE_AUDIO) {
return SWITCH_STATUS_SUCCESS;
return fh;
}
-static void switch_core_session_write_blank_video(switch_core_session_t *session, uint32_t ms)
+SWITCH_DECLARE(void) switch_core_session_write_blank_video(switch_core_session_t *session, uint32_t ms)
{
switch_frame_t fr = { 0 };
int i = 0;
}
+typedef struct core_fps_s {
+ float fps;
+ int ms;
+ int samples;
+} core_fps_t;
+
+static struct core_fps_s FPS_VALS[] = {
+ {1.0f, 1000, 90},
+ {5.0f, 200, 450},
+ {10.0f, 100, 900},
+ {15.0f, 66, 1364},
+ {16.60f, 60, 1500},
+ {20.0f, 50, 4500},
+ {25.0f, 40, 2250},
+ {30.0f, 33, 2700},
+ {33.0f, 30, 2790},
+ {66.60f, 15, 6000},
+ {100.0f, 10, 9000},
+ {0,0,0}
+};
+
+
+static int video_get_fps(core_fps_t *fpsP, float fps)
+{
+ uint32_t i = 0;
+
+ for (i = 0; FPS_VALS[i].ms; i++) {
+ if (FPS_VALS[i].fps == fps) {
+ *fpsP = FPS_VALS[i];
+ return 1;
+ }
+ }
+
+ return 0;
+}
static void *SWITCH_THREAD_FUNC video_write_thread(switch_thread_t *thread, void *obj)
{
int buflen = SWITCH_RTP_MAX_BUF_LEN;
switch_timer_t timer = { 0 };
int fps;
- switch_video_read_flag_t read_flags = SVR_FLUSH|SVR_BLOCK;
+ switch_video_read_flag_t read_flags = SVR_FLUSH;
switch_core_session_t *b_session = NULL;
-
+ core_fps_t fps_data = { 0 };
+ switch_image_t *last_frame = NULL;
+
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
return NULL;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ switch_mutex_lock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]);
+ v_engine->thread_write_lock = switch_thread_self();
+
buf = switch_core_session_alloc(session, buflen);
fr.packet = buf;
fr.packetlen = buflen;
}
- switch_core_timer_init(&timer, "soft", (int)(1000 / fps) , 1, switch_core_session_get_pool(session));
+ video_get_fps(&fps_data, fps);
+ switch_core_timer_init(&timer, "soft", (int)(1000 / fps) , fps_data.samples, switch_core_session_get_pool(session));
while (smh->video_write_thread_running > 0 &&
switch_channel_up_nosig(session->channel) && smh->video_write_fh && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) {
if (smh->video_write_fh && smh->video_write_fh->mm.source_fps && smh->video_write_fh->mm.source_fps != fps) {
switch_core_timer_destroy(&timer);
- switch_core_timer_init(&timer, "soft", (int)(1000 / fps) , 1, switch_core_session_get_pool(session));
+ video_get_fps(&fps_data, fps);
+ switch_core_timer_init(&timer, "soft", (int)(1000 / fps) , fps_data.samples, switch_core_session_get_pool(session));
}
if (smh->video_write_fh && !switch_test_flag(smh->video_write_fh, SWITCH_FILE_FLAG_VIDEO_EOF)) {
wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, read_flags);
if (wstatus == SWITCH_STATUS_SUCCESS) {
- switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_FORCE, SVR_FLUSH);
- switch_img_free(&fr.img);
+ fr.timestamp = timer.samplecount;
+ fr.flags = SFF_USE_VIDEO_TIMESTAMP|SFF_RAW_RTP|SFF_RAW_RTP_PARSE_FRAME;
+
+ if (smh->vid_params.d_width && smh->vid_params.d_height) {
+ switch_img_fit(&fr.img, smh->vid_params.d_width, smh->vid_params.d_height, SWITCH_FIT_SIZE);
+ }
+
+ switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_FORCE, 0);
+
+ switch_img_free(&last_frame);
+ last_frame = fr.img;
+ fr.img = NULL;
+
} else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) {
switch_set_flag_locked(smh->video_write_fh, SWITCH_FILE_FLAG_VIDEO_EOF);
}
switch_mutex_unlock(v_engine->mh.file_write_mutex);
}
+ if (last_frame) {
+ int x = 0;
+ switch_rgb_color_t bgcolor;
+ switch_color_set_rgb(&bgcolor, "#000000");
+ switch_img_fill(last_frame, 0, 0, last_frame->d_w, last_frame->d_h, &bgcolor);
+ fr.img = last_frame;
+
+ for (x = 0; x < fps / 2; x++) {
+ switch_core_timer_next(&timer);
+ fr.timestamp = timer.samplecount;
+ fr.flags = SFF_USE_VIDEO_TIMESTAMP|SFF_RAW_RTP|SFF_RAW_RTP_PARSE_FRAME;
+ switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_FORCE, 0);
+ }
+ switch_core_media_gen_key_frame(session);
+ switch_core_session_request_video_refresh(session);
+ switch_img_free(&last_frame);
+ }
+
+
switch_core_timer_destroy(&timer);
switch_core_session_rwunlock(session);
switch_core_session_rwunlock(b_session);
}
+
+ v_engine->thread_write_lock = 0;
+ switch_mutex_unlock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]);
+
switch_channel_clear_flag(session->channel, CF_VIDEO_WRITING);
smh->video_write_thread_running = 0;
if (fh) {
switch_threadattr_t *thd_attr = NULL;
- switch_core_session_write_blank_video(session, 500);
+ //switch_core_session_write_blank_video(session, 500);
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
smh->video_write_thread_running = 1;
switch_thread_join(&st, smh->video_write_thread);
switch_mutex_lock(v_engine->mh.file_write_mutex);
smh->video_write_thread = NULL;
- switch_core_session_write_blank_video(session, 500);
+ //switch_core_session_write_blank_video(session, 500);
}
smh->video_write_fh = fh;
}
- if ((val = switch_channel_get_variable(session->channel, "rtp_gen_ts_delta_audio")) && switch_true(val)) {
- flags[SWITCH_RTP_FLAG_GEN_TS_MANUAL] = 1;
- flags[SWITCH_RTP_FLAG_GEN_TS_DELTA] = 1;
- }
-
if (switch_channel_up(session->channel)) {
switch_channel_set_variable(session->channel, "rtp_use_timer_name", timer_name);
flags[SWITCH_RTP_FLAG_AUTOADJ]++;
}
- if ((val = switch_channel_get_variable(session->channel, "rtp_gen_ts_delta_video")) && switch_true(val)) {
- flags[SWITCH_RTP_FLAG_GEN_TS_MANUAL] = 1;
- flags[SWITCH_RTP_FLAG_GEN_TS_DELTA] = 1;
- }
-
if (switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) {
flags[SWITCH_RTP_FLAG_PROXY_MEDIA]++;
}
case SWITCH_MESSAGE_INDICATE_BRIDGE:
{
+#if 0
+ if (switch_rtp_ready(v_engine->rtp_session)) {
+ const char *val;
+
+ if ((!(val = switch_channel_get_variable(session->channel, "rtp_jitter_buffer_during_bridge")) || switch_false(val))) {
+ if (switch_rtp_get_jitter_buffer(v_engine->rtp_session) && switch_channel_test_cap_partner(session->channel, CC_FS_RTP)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+ "%s PAUSE Jitterbuffer\n", switch_channel_get_name(session->channel));
+ switch_rtp_pause_jitter_buffer(v_engine->rtp_session, SWITCH_TRUE);
+ switch_set_flag(smh, SMF_VB_PAUSED);
+ }
+ }
+ }
+#endif
+
if (switch_rtp_ready(a_engine->rtp_session)) {
const char *val;
int ok = 0;
- if (!switch_channel_test_flag(session->channel, CF_VIDEO) &&
- (!(val = switch_channel_get_variable(session->channel, "rtp_jitter_buffer_during_bridge")) || switch_false(val))) {
+ if ((!(val = switch_channel_get_variable(session->channel, "rtp_jitter_buffer_during_bridge")) || switch_false(val))) {
if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(session->channel, CC_FS_RTP)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s PAUSE Jitterbuffer\n", switch_channel_get_name(session->channel));
}
goto end;
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+
+#if 0
+ if (switch_rtp_ready(v_engine->rtp_session)) {
+
+ if (switch_test_flag(smh, SMF_VB_PAUSED)) {
+ switch_clear_flag(smh, SMF_VB_PAUSED);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+ "%s RESUME Video Jitterbuffer\n", switch_channel_get_name(session->channel));
+ switch_rtp_pause_jitter_buffer(v_engine->rtp_session, SWITCH_FALSE);
+
+ }
+ }
+#endif
+
if (switch_rtp_ready(a_engine->rtp_session)) {
if (switch_test_flag(smh, SMF_JB_PAUSED)) {
switch_image_t *dup_img = NULL, *img = frame->img;
switch_status_t encode_status;
switch_frame_t write_frame = {0};
- switch_rtp_engine_t *v_engine;
-
+ switch_rtp_engine_t *v_engine = NULL;
switch_assert(session);
if (!(smh = session->media_handle)) {
return SWITCH_STATUS_FALSE;
}
- if (switch_channel_test_flag(session->channel, CF_VIDEO_WRITING) && !(flags & SWITCH_IO_FLAG_FORCE)) {
- return SWITCH_STATUS_SUCCESS;
- }
if (switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY || switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG3, "Writing video to RECVONLY/INACTIVE session\n");
return SWITCH_STATUS_SUCCESS;
}
- v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO] && switch_mutex_trylock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) != SWITCH_STATUS_SUCCESS) {
/* return CNG, another thread is already writing */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being written to for %s\n",
return SWITCH_STATUS_INUSE;
}
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ if (v_engine->thread_write_lock && v_engine->thread_write_lock != switch_thread_self()) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
if (!smh->video_init && smh->mparams->video_key_first && (now - smh->video_last_key_time) > smh->mparams->video_key_first) {
switch_core_media_gen_key_frame(session);
if (!img) {
switch_status_t vstatus;
- if (!switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_GEN_TS_MANUAL)) {
- switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA);
- }
-
vstatus = switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id);
switch_goto_status(vstatus, done);
- } else {
- if (!switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_GEN_TS_MANUAL)) {
- switch_rtp_clear_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA);
- }
}
img = dup_img;
}
+ if (!switch_channel_test_flag(session->channel, CF_VIDEO_WRITING)) {
+ smh->vid_params.d_width = img->d_w;
+ smh->vid_params.d_height = img->d_h;
+ }
+
if (session->bugs) {
switch_media_bug_t *bp;
int prune = 0;
}
+SWITCH_DECLARE(switch_bool_t) switch_core_session_transcoding(switch_core_session_t *session_a, switch_core_session_t *session_b, switch_media_type_t type)
+{
+ switch_bool_t transcoding = SWITCH_FALSE;
+
+ switch(type) {
+ case SWITCH_MEDIA_TYPE_AUDIO:
+ transcoding = (session_a->read_codec->implementation->impl_id != session_b->read_codec->implementation->impl_id || session_a->read_impl.decoded_bytes_per_packet != session_b->read_impl.decoded_bytes_per_packet);
+ break;
+ case SWITCH_MEDIA_TYPE_VIDEO:
+ transcoding = (switch_channel_test_flag(session_a->channel, CF_VIDEO_DECODED_READ) ||
+ switch_channel_test_flag(session_b->channel, CF_VIDEO_DECODED_READ));
+ break;
+ default:
+ break;
+ }
+
+ return transcoding;
+
+}
+
+SWITCH_DECLARE(void) switch_core_session_passthru(switch_core_session_t *session, switch_media_type_t type, switch_bool_t on)
+{
+ switch_rtp_engine_t *engine;
+
+ if (!session->media_handle) return;
+
+ engine = &session->media_handle->engines[type];
+
+
+ if (switch_rtp_ready(engine->rtp_session)) {
+ if (on) {
+ switch_rtp_set_flag(engine->rtp_session, SWITCH_RTP_FLAG_PASSTHRU);
+ } else {
+ switch_rtp_clear_flag(engine->rtp_session, SWITCH_RTP_FLAG_PASSTHRU);
+ }
+
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ switch_core_session_request_video_refresh(session);
+ if (!on) {
+ switch_core_media_gen_key_frame(session);
+ }
+ }
+
+ }
+
+}
+
SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags,
int stream_id)
{
switch_frame_t *read_frame = 0;
int set_decoded_read = 0, refresh_timer = 0;
int refresh_cnt = 300;
+ int pass_val = 0, last_pass_val = 0;
vh->up = 1;
if (switch_channel_media_up(channel)) {
switch_codec_t *a_codec = switch_core_session_get_video_read_codec(vh->session_a);
switch_codec_t *b_codec = switch_core_session_get_video_write_codec(vh->session_b);
+
+ if (switch_core_session_transcoding(vh->session_a, vh->session_b, SWITCH_MEDIA_TYPE_VIDEO)) {
+ pass_val = 1;
+ } else {
+ pass_val = 2;
+ }
-
+ if (pass_val != last_pass_val) {
+ switch_core_session_passthru(session, SWITCH_MEDIA_TYPE_VIDEO, pass_val == 2 ? SWITCH_TRUE : SWITCH_FALSE);
+ last_pass_val = pass_val;
+ }
+
if (switch_channel_test_flag(channel, CF_VIDEO_REFRESH_REQ)) {
switch_channel_clear_flag(channel, CF_VIDEO_REFRESH_REQ);
refresh_timer = refresh_cnt;
switch_core_session_request_video_refresh(vh->session_a);
switch_core_session_request_video_refresh(vh->session_b);
+ switch_core_session_passthru(vh->session_a, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_FALSE);
+
switch_core_session_rwunlock(vh->session_a);
switch_core_session_rwunlock(vh->session_b);
struct vid_helper th = { 0 };
const char *banner_file = NULL;
int played_banner = 0, banner_counter = 0;
+ int pass_val = 0, last_pass_val = 0;
#ifdef SWITCH_VIDEO_IN_THREADS
struct vid_helper vh = { 0 };
switch_status_t status;
switch_event_t *event;
+ if (switch_core_session_transcoding(session_a, session_b, SWITCH_MEDIA_TYPE_AUDIO)) {
+ pass_val = 1;
+ } else {
+ pass_val = 2;
+ }
+
+ if (pass_val != last_pass_val) {
+ switch_core_session_passthru(session_a, SWITCH_MEDIA_TYPE_AUDIO, pass_val == 2 ? SWITCH_TRUE : SWITCH_FALSE);
+ last_pass_val = pass_val;
+ }
+
if (switch_channel_test_flag(chan_a, CF_TRANSFER)) {
data->clean_exit = 1;
}
end_of_bridge_loop:
+ switch_core_session_passthru(session_a, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_FALSE);
+
#ifdef SWITCH_VIDEO_IN_THREADS
if (vh.up > 0) {
struct switch_jb_node_s *node_list;
uint32_t last_target_seq;
uint32_t highest_read_ts;
+ uint32_t highest_dropped_ts;
uint32_t highest_read_seq;
uint32_t highest_wrote_ts;
- uint32_t highest_wrote_seq;
+ uint16_t highest_wrote_seq;
uint16_t target_seq;
uint32_t target_ts;
uint32_t last_target_ts;
switch_channel_t *channel;
uint32_t buffer_lag;
uint32_t flush;
+ uint32_t packet_count;
+ uint32_t max_packet_len;
};
}
if (!np) {
+ int mult = 25;
+
+ if (jb->type != SJB_VIDEO) {
+ mult = 2;
+ } else {
+ if (jb->max_packet_len > mult) {
+ mult = jb->max_packet_len;
+ }
+ }
+
+ if (jb->allocated_nodes > jb->max_frame_len * mult) {
+ jb_debug(jb, 2, "ALLOCATED FRAMES TOO HIGH! %d\n", jb->allocated_nodes);
+ switch_jb_reset(jb);
+ switch_mutex_unlock(jb->list_mutex);
+ return NULL;
+ }
np = switch_core_alloc(jb->pool, sizeof(*np));
jb->allocated_nodes++;
}
if (switch_core_inthash_delete(jb->node_hash, node->packet.header.seq)) {
- if (node->packet.header.m && jb->type == SJB_VIDEO) {
+ if (node->packet.header.version == 1 && jb->type == SJB_VIDEO) {
jb->complete_frames--;
}
}
}
#endif
+static inline int check_seq(uint16_t a, uint16_t b)
+{
+ a = ntohs(a);
+ b = ntohs(b);
+
+ if (a >= b || (b > a && b > USHRT_MAX / 2 && a < USHRT_MAX / 2)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int check_ts(uint32_t a, uint32_t b)
+{
+ a = ntohl(a);
+ b = ntohl(b);
+
+ if (a > b || (b > a && b > UINT_MAX / 2 && a < UINT_MAX / 2)) {
+ return 1;
+ }
+
+ return 0;
+}
+
static inline void add_node(switch_jb_t *jb, switch_rtp_packet_t *packet, switch_size_t len)
{
switch_jb_node_t *node = new_node(jb);
+ if (!node) {
+ return;
+ }
+
+
node->packet = *packet;
node->len = len;
memcpy(node->packet.body, packet->body, len);
switch_core_inthash_insert(jb->node_hash, node->packet.header.seq, node);
- if (packet->header.m && jb->type == SJB_VIDEO) {
- jb->complete_frames++;
- }
-
if (jb->node_hash_ts) {
switch_core_inthash_insert(jb->node_hash_ts, node->packet.header.ts, node);
}
}
if (jb->type == SJB_VIDEO) {
- if (jb->write_init && ((htons(packet->header.seq) >= htons(jb->highest_wrote_seq) && (ntohl(node->packet.header.ts) > ntohl(jb->highest_wrote_ts))) ||
- (ntohl(jb->highest_wrote_ts) > (UINT_MAX - 1000) && ntohl(node->packet.header.ts) < 1000))) {
+ if (!switch_test_flag(jb, SJB_QUEUE_ONLY)) {
+ jb->packet_count++;
+ }
+
+ if (jb->write_init && check_seq(packet->header.seq, jb->highest_wrote_seq) && check_ts(node->packet.header.ts, jb->highest_wrote_ts)) {
jb_debug(jb, 2, "WRITE frame ts: %u complete=%u/%u n:%u\n", ntohl(node->packet.header.ts), jb->complete_frames , jb->frame_len, jb->visible_nodes);
jb->highest_wrote_ts = packet->header.ts;
- //verify_oldest_frame(jb);
+ jb->complete_frames++;
+
+ if (!switch_test_flag(jb, SJB_QUEUE_ONLY)) {
+ if (jb->packet_count > jb->max_packet_len) {
+ jb->max_packet_len = jb->packet_count;
+ }
+
+ jb->packet_count = 0;
+ }
+ node->packet.header.version = 1;
} else if (!jb->write_init) {
jb->highest_wrote_ts = packet->header.ts;
}
jb_frame_inc(jb, 1);
}
- //if (jb->session) {
- // switch_core_session_request_video_refresh(jb->session);
- //}
+ if (jb->session) {
+ switch_core_session_request_video_refresh(jb->session);
+ }
for (x = 0; x < 10; x++) {
increment_seq(jb);
jb_debug(jb, 2, "%s", "SAME FRAME DROPPING\n");
jb->dropped++;
drop_ts(jb, node->packet.header.ts);
+ jb->highest_dropped_ts = ntohl(node->packet.header.ts);
node = NULL;
goto top;
}
jb_debug(jb, 2, "MISSING incremental seq: %u\n", ntohs(jb->target_seq));
}
}
+
} else {
increment_seq(jb);
}
jb->session = session;
jb->channel = switch_core_session_get_channel(session);
- if (jb->type == SJB_VIDEO && (var = switch_channel_get_variable_dup(jb->channel, "jb_video_low_bitrate", SWITCH_FALSE, -1))) {
+ if (jb->type == SJB_VIDEO && !switch_test_flag(jb, SJB_QUEUE_ONLY) &&
+ (var = switch_channel_get_variable_dup(jb->channel, "jb_video_low_bitrate", SWITCH_FALSE, -1))) {
int tmp = atoi(var);
- if (tmp > 128 && tmp < 10240) {
+ if (tmp >= 128 && tmp <= 10240) {
jb->video_low_bitrate = (uint32_t)tmp;
}
}
switch_mutex_lock(jb->mutex);
+ if (jb->highest_dropped_ts) {
+ if (ntohl(packet->header.ts) < jb->highest_dropped_ts) {
+ jb_debug(jb, 2, "%s", "TS ALREADY DROPPED, DROPPING PACKET\n");
+ switch_mutex_unlock(jb->mutex);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ jb->highest_dropped_ts = 0;
+ }
+
+
if (!want) want = got;
if (switch_test_flag(jb, SJB_QUEUE_ONLY) || jb->type == SJB_AUDIO || jb->type == SJB_TEXT) {
*packet = node->packet;
*len = node->len;
memcpy(packet->body, node->packet.body, node->len);
+ packet->header.version = 2;
status = SWITCH_STATUS_SUCCESS;
} else {
jb_debug(jb, 2, "Missing buffered seq: %u\n", ntohs(seq));
return jb->last_len;
}
-
SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp_packet_t *packet, switch_size_t *len)
{
switch_jb_node_t *node = NULL;
if (jb->session) {
switch_core_session_request_video_refresh(jb->session);
}
- } else if (!switch_channel_test_flag(jb->channel, CF_VIDEO_BITRATE_UNMANAGABLE) && jb->frame_len > jb->min_frame_len * 2) {
+ } else if (!switch_channel_test_flag(jb->channel, CF_VIDEO_BITRATE_UNMANAGABLE) && jb->frame_len > jb->max_frame_len / 2) {
switch_core_session_message_t msg = { 0 };
jb->bitrate_control = jb->video_low_bitrate;
-
+
msg.message_id = SWITCH_MESSAGE_INDICATE_BITRATE_REQ;
msg.numeric_arg = jb->bitrate_control * 1024;
msg.from = __FILE__;
jb_debug(jb, 2, "Force BITRATE to %d\n", jb->bitrate_control);
+
switch_core_session_receive_message(jb->session, &msg);
switch_channel_set_flag(jb->channel, CF_VIDEO_BITRATE_UNMANAGABLE);
if (jb->session) {
if ((status = jb_next_packet(jb, &node)) == SWITCH_STATUS_SUCCESS) {
jb_debug(jb, 2, "Found next frame cur ts: %u seq: %u\n", htonl(node->packet.header.ts), htons(node->packet.header.seq));
- if (!jb->read_init || ntohs(node->packet.header.seq) > ntohs(jb->highest_read_seq) ||
- (ntohs(jb->highest_read_seq) > USHRT_MAX - 10 && ntohs(node->packet.header.seq) <= 10) ) {
+ if (!jb->read_init || check_seq(node->packet.header.seq, jb->highest_read_seq)) {
jb->highest_read_seq = node->packet.header.seq;
}
- if (jb->type == SJB_TEXT || jb->type == SJB_AUDIO ||
- (jb->read_init && htons(node->packet.header.seq) >= htons(jb->highest_read_seq) && (ntohl(node->packet.header.ts) > ntohl(jb->highest_read_ts)))) {
+ if (jb->type != SJB_VIDEO ||
+ (jb->read_init && check_seq(node->packet.header.seq, jb->highest_read_seq) && check_ts(node->packet.header.ts, jb->highest_read_ts))) {
- if (jb->type == SJB_TEXT || jb->type == SJB_AUDIO) {
+ if (jb->type != SJB_VIDEO) {
jb->complete_frames--;
}
jb_debug(jb, 2, "READ frame ts: %u complete=%u/%u n:%u\n", ntohl(node->packet.header.ts), jb->complete_frames , jb->frame_len, jb->visible_nodes);
*len = node->len;
jb->last_len = *len;
memcpy(packet->body, node->packet.body, node->len);
+ packet->header.version = 2;
hide_node(node, SWITCH_TRUE);
jb_debug(jb, 1, "GET packet ts:%u seq:%u %s\n", ntohl(packet->header.ts), ntohs(packet->header.seq), packet->header.m ? " <MARK>" : "");
uint32_t last_frame;
uint32_t ts;
uint32_t delta;
- uint32_t delta_ct;
uint32_t delta_ttl;
+ int last_external;
} ts_normalize_t;
struct switch_rtp {
switch_byte_t rtcp_auto_adj_used;
uint8_t pause_jb;
uint16_t last_seq;
+ uint16_t last_write_seq;
switch_time_t last_read_time;
switch_size_t last_flush_packet_count;
uint32_t interdigit_delay;
(rtp_session->stats.inbound.last_processed_seq + 1), lost);
rtp_session->stats.inbound.last_loss++;
+ if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
+ switch_core_session_request_video_refresh(rtp_session->session);
+ }
+
if (rtp_session->stats.inbound.last_loss > 0 && rtp_session->stats.inbound.last_loss < LOST_BURST_CAPTURE) {
rtp_session->stats.inbound.loss[rtp_session->stats.inbound.last_loss] += lost;
}
SWITCH_DECLARE(switch_status_t) switch_rtp_pause_jitter_buffer(switch_rtp_t *rtp_session, switch_bool_t pause)
{
+ int new_val;
- if (!switch_rtp_ready(rtp_session) || !rtp_session->jb) {
- return SWITCH_STATUS_FALSE;
- }
+ if (rtp_session->pause_jb && !pause) {
+ if (rtp_session->jb) {
+ switch_jb_reset(rtp_session->jb);
+ }
- if (!!pause == !!rtp_session->pause_jb) {
- return SWITCH_STATUS_FALSE;
+ if (rtp_session->vb) {
+ switch_jb_reset(rtp_session->vb);
+ }
}
- if (rtp_session->pause_jb && !pause) {
- switch_jb_reset(rtp_session->jb);
- }
+ new_val = pause ? 1 : -1;
- rtp_session->pause_jb = pause ? 1 : 0;
+ if (rtp_session->pause_jb + new_val > -1) {
+ rtp_session->pause_jb += new_val;
+ }
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1,
+ "Jitterbuffer %s is %s\n", rtp_type(rtp_session), rtp_session->pause_jb ? "paused" : "enabled");
+
return SWITCH_STATUS_SUCCESS;
}
for(i = 0; i < SWITCH_RTP_FLAG_INVALID; i++) {
if (flags[i]) {
- rtp_session->flags[i] = flags[i];
-
- if (i == SWITCH_RTP_FLAG_AUTOADJ) {
- rtp_session->autoadj_window = 20;
- rtp_session->autoadj_threshold = 10;
- rtp_session->autoadj_tally = 0;
- if (rtp_session->session) {
- switch_channel_t *channel = switch_core_session_get_channel(rtp_session->session);
- const char *x = switch_channel_get_variable(channel, "rtp_auto_adjust_threshold");
- if (x && *x) {
- int xn = atoi(x);
- if (xn > 0 && xn <= 65535) {
- rtp_session->autoadj_window = xn*2;
- rtp_session->autoadj_threshold = xn;
- }
- }
- }
-
-
- rtp_session->flags[SWITCH_RTP_FLAG_RTCP_AUTOADJ] = 1;
-
-
- rtp_session->rtcp_autoadj_window = 20;
- rtp_session->rtcp_autoadj_threshold = 1;
- rtp_session->rtcp_autoadj_tally = 0;
-
-
- rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE);
- } else if (i == SWITCH_RTP_FLAG_NOBLOCK && rtp_session->sock_input) {
- switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE);
- }
+ switch_rtp_set_flag(rtp_session, i);
}
}
}
for(i = 0; i < SWITCH_RTP_FLAG_INVALID; i++) {
if (flags[i]) {
- rtp_session->flags[i] = 0;
+ switch_rtp_clear_flag(rtp_session, i);
}
}
}
SWITCH_DECLARE(void) switch_rtp_set_flag(switch_rtp_t *rtp_session, switch_rtp_flag_t flag)
{
+ int old_flag = rtp_session->flags[flag];
switch_mutex_lock(rtp_session->flag_mutex);
rtp_session->flags[flag] = 1;
switch_mutex_unlock(rtp_session->flag_mutex);
- if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
+ if (flag == SWITCH_RTP_FLAG_PASSTHRU) {
+ if (!old_flag) {
+ switch_rtp_pause_jitter_buffer(rtp_session, SWITCH_TRUE);
+ }
+ } else if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
rtp_session->stats.inbound.last_processed_seq = 0;
} else if (flag == SWITCH_RTP_FLAG_FLUSH) {
reset_jitter_seq(rtp_session);
SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp_flag_t flag)
{
+ int old_flag = rtp_session->flags[flag];
switch_mutex_lock(rtp_session->flag_mutex);
rtp_session->flags[flag] = 0;
switch_mutex_unlock(rtp_session->flag_mutex);
- if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
+ if (flag == SWITCH_RTP_FLAG_PASSTHRU) {
+ if (old_flag) {
+ switch_rtp_pause_jitter_buffer(rtp_session, SWITCH_FALSE);
+ }
+ } else if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
rtp_session->stats.inbound.last_processed_seq = 0;
} else if (flag == SWITCH_RTP_FLAG_PAUSE) {
reset_jitter_seq(rtp_session);
return SWITCH_STATUS_SUCCESS;
}
- if (rtp_session->vb && jb_valid(rtp_session)) {
+ if (rtp_session->vb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
status = switch_jb_put_packet(rtp_session->vb, (switch_rtp_packet_t *) &rtp_session->recv_msg, *bytes);
if (status == SWITCH_STATUS_TOO_LATE) {
}
}
- if (rtp_session->vb && jb_valid(rtp_session)) {
+ if (rtp_session->vb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
switch_status_t vstatus = switch_jb_get_packet(rtp_session->vb, (switch_rtp_packet_t *) &rtp_session->recv_msg, bytes);
status = vstatus;
pt = 100000;
}
- if (rtp_session->vb) {
+ if (rtp_session->vb && !rtp_session->pause_jb) {
if (switch_jb_poll(rtp_session->vb)) {
pt = 1000;
}
}
if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
- got_jb = (rtp_session->vb && switch_jb_poll(rtp_session->vb));
+ got_jb = (rtp_session->vb && !rtp_session->pause_jb && switch_jb_poll(rtp_session->vb));
} else {
got_jb = SWITCH_TRUE;
}
process_rtcp_packet(rtp_session, &rtcp_bytes);
ret = 1;
- if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
+ if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
switch_core_timer_sync(&rtp_session->timer);
reset_jitter_seq(rtp_session);
}
frame->source = __FILE__;
switch_set_flag(frame, SFF_RAW_RTP);
+ switch_set_flag(frame, SFF_EXTERNAL);
if (frame->payload == rtp_session->recv_te) {
switch_set_flag(frame, SFF_RFC2833);
}
}
}
-
- if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA) || switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
+ if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
+ int external = (*flags & SFF_EXTERNAL);
/* Normalize the timestamps to our own base by generating a made up starting point then adding the measured deltas to that base
so if the timestamps and ssrc of the source change, it will not break the other end's jitter bufffer / decoder etc *cough* CHROME *cough*
*/
if (!rtp_session->ts_norm.ts) {
- if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA)) {
- rtp_session->ts_norm.ts = (uint32_t) rand() % 1000000 + 1;
- } else {
- switch_core_timer_sync(&rtp_session->timer);
- rtp_session->ts_norm.ts = rtp_session->timer.samplecount;
- }
+ rtp_session->ts_norm.ts = (uint32_t) rand() % 1000000 + 1;
}
- if (!rtp_session->ts_norm.last_ssrc || send_msg->header.ssrc != rtp_session->ts_norm.last_ssrc) {
- if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA)) {
- if (rtp_session->ts_norm.last_ssrc) {
- rtp_session->ts_norm.delta_ct = 1;
- rtp_session->ts_norm.delta_ttl = 0;
- if (rtp_session->ts_norm.delta) {
- rtp_session->ts_norm.ts += rtp_session->ts_norm.delta;
- }
- }
+ if (!rtp_session->ts_norm.last_ssrc || send_msg->header.ssrc != rtp_session->ts_norm.last_ssrc || rtp_session->ts_norm.last_external != external) {
+ switch_core_session_t *other_session;
+
+ switch_core_session_request_video_refresh(rtp_session->session);
+ switch_core_media_gen_key_frame(rtp_session->session);
+
+ if (switch_core_session_get_partner(rtp_session->session, &other_session) == SWITCH_STATUS_SUCCESS) {
+ switch_core_session_request_video_refresh(other_session);
+ switch_core_media_gen_key_frame(other_session);
+ switch_core_session_rwunlock(other_session);
+ }
+
+ if (rtp_session->ts_norm.last_ssrc) {
+ rtp_session->ts_norm.delta_ttl = 0;
+ rtp_session->ts_norm.ts++;
}
rtp_session->ts_norm.last_ssrc = send_msg->header.ssrc;
rtp_session->ts_norm.last_frame = ntohl(send_msg->header.ts);
}
+ rtp_session->ts_norm.last_external = external;
if (ntohl(send_msg->header.ts) != rtp_session->ts_norm.last_frame) {
- int32_t delta = (int32_t) (ntohl(send_msg->header.ts) - rtp_session->ts_norm.last_frame);
+ int32_t delta;
+ int64_t x, y;
- if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO) && delta > 0 && delta < 90000) {
- rtp_session->ts_norm.delta = delta;
+ x = rtp_session->ts_norm.last_frame;
+ y = ntohl(send_msg->header.ts);
+
+ if (x > UINT32_MAX / 2 && y < UINT32_MAX / 2) {
+ x -= (int64_t)UINT32_MAX+1;
}
+
+ delta = (int32_t)y-x;
- if (switch_rtp_test_flag(rtp_session, SWITCH_RTP_FLAG_GEN_TS_DELTA)) {
- rtp_session->ts_norm.ts += rtp_session->ts_norm.delta;
+ if (delta < 0 || delta > 90000) {
+ switch_core_media_gen_key_frame(rtp_session->session);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1,
+ "Timestamp shift detected last: %d this: %d delta: %d stick with prev delta: %d\n",
+ rtp_session->ts_norm.last_frame, ntohl(send_msg->header.ts), delta, rtp_session->ts_norm.delta);
} else {
- switch_core_timer_sync(&rtp_session->timer);
- if (rtp_session->ts_norm.ts == rtp_session->timer.samplecount) {
- rtp_session->ts_norm.ts = rtp_session->timer.samplecount + 1;
- } else {
- rtp_session->ts_norm.ts = rtp_session->timer.samplecount;
- }
- if (send_msg->header.m) {
- rtp_session->ts_norm.last_frame++;
- }
+ rtp_session->ts_norm.delta = delta;
}
- }
+ rtp_session->ts_norm.ts += rtp_session->ts_norm.delta;
+
+ }
+
rtp_session->ts_norm.last_frame = ntohl(send_msg->header.ts);
send_msg->header.ts = htonl(rtp_session->ts_norm.ts);
}
}
if (send) {
- send_msg->header.seq = htons(++rtp_session->seq);
+ int delta = 1;
+ if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && (*flags & SFF_EXTERNAL) && rtp_session->stats.outbound.packet_count && rtp_session->flags[SWITCH_RTP_FLAG_PASSTHRU]) {
+ int32_t x;
+ int32_t y;
+
+ x = rtp_session->last_write_seq;
+ y = ntohs(send_msg->header.seq);
+
+ if (x > UINT16_MAX / 2 && y < UINT16_MAX / 2) {
+ x -= (int32_t)UINT16_MAX+1;
+ }
+
+ delta = y-x;
+ }
+
+ rtp_session->seq += delta;
+
+ send_msg->header.seq = htons(rtp_session->seq);
+ rtp_session->last_write_seq = rtp_session->seq;
+
if (rtp_session->flags[SWITCH_RTP_FLAG_BYTESWAP] && send_msg->header.pt == rtp_session->payload) {
switch_swap_linear((int16_t *)send_msg->body, (int) datalen);
}
// //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SEND %u\n", ntohs(send_msg->header.seq));
//}
if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, (void *) send_msg, &bytes) != SWITCH_STATUS_SUCCESS) {
- rtp_session->seq--;
+ rtp_session->seq -= delta;
+
ret = -1;
goto end;
}
fwd = (rtp_session->flags[SWITCH_RTP_FLAG_RAW_WRITE] &&
(switch_test_flag(frame, SFF_RAW_RTP) || switch_test_flag(frame, SFF_RAW_RTP_PARSE_FRAME))) ? 1 : 0;
- if (!fwd && !rtp_session->sending_dtmf && !rtp_session->queue_delay &&
+ if (!fwd && !rtp_session->sending_dtmf && !rtp_session->queue_delay && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] &&
rtp_session->flags[SWITCH_RTP_FLAG_RAW_WRITE] && (rtp_session->rtp_bugs & RTP_BUG_GEN_ONE_GEN_ALL)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "Generating RTP locally but timestamp passthru is configured, disabling....\n");
if (switch_test_flag(frame, SFF_RAW_RTP_PARSE_FRAME)) {
send_msg->header.version = 2;
send_msg->header.m = frame->m;
+
send_msg->header.ts = htonl(frame->timestamp);
if (frame->ssrc) {
send_msg->header.ssrc = htonl(frame->ssrc);
timer->tick = (elapsed / timer->interval) / 1000;
timer->samplecount = (uint32_t)(timer->tick * timer->samples);
+ if (timer->interval == 1 && timer->samplecount == timer->last_samplecount) {
+ timer->samplecount++;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Timer sync too often\n");
+ }
+ timer->last_samplecount = timer->samplecount;
+
+
+
return SWITCH_STATUS_SUCCESS;
}