diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 71f7100b0c..6dfa1e2531 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -579,7 +579,8 @@ SWITCH_DECLARE(dtls_state_t) switch_rtp_dtls_state(switch_rtp_t *rtp_session, dt SWITCH_DECLARE(int) switch_rtp_has_dtls(void); -SWITCH_DECLARE(switch_status_t) switch_rtp_req_bandwidth(switch_rtp_t *rtp_session, uint32_t bps); +SWITCH_DECLARE(switch_status_t) switch_rtp_req_bitrate(switch_rtp_t *rtp_session, uint32_t bps); +SWITCH_DECLARE(switch_status_t) switch_rtp_ack_bitrate(switch_rtp_t *rtp_session, uint32_t bps); SWITCH_DECLARE(void) switch_rtp_video_refresh(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_video_loss(switch_rtp_t *rtp_session); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index cec2f605bc..108b03e33c 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1069,6 +1069,8 @@ typedef enum { SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, SWITCH_MESSAGE_INDICATE_KEEPALIVE, SWITCH_MESSAGE_INDICATE_HARD_MUTE, + SWITCH_MESSAGE_INDICATE_BITRATE_REQ, + SWITCH_MESSAGE_INDICATE_BITRATE_ACK, SWITCH_MESSAGE_REFER_EVENT, SWITCH_MESSAGE_ANSWER_EVENT, SWITCH_MESSAGE_PROGRESS_EVENT, diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index cae64d20a7..60bcda10d0 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -3952,6 +3952,49 @@ SWITCH_STANDARD_API(uuid_video_refresh_function) return SWITCH_STATUS_SUCCESS; } +#define VIDEO_BITRATE_SYNTAX " " +SWITCH_STANDARD_API(uuid_video_bitrate_function) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + char *mycmd = NULL, *argv[2] = { 0 }; + int argc = 0; + + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc < 2) { + stream->write_function(stream, "-USAGE: %s\n", VIDEO_REFRESH_SYNTAX); + } else { + switch_core_session_t *lsession = NULL; + + if ((lsession = switch_core_session_locate(argv[0]))) { + int kps = switch_parse_bandwidth_string(argv[1]); + switch_core_session_message_t msg = { 0 }; + + msg.message_id = SWITCH_MESSAGE_INDICATE_BITRATE_REQ; + msg.numeric_arg = kps * 1024; + msg.from = __FILE__; + + switch_core_session_receive_message(lsession, &msg); + switch_core_session_video_reinit(lsession); + switch_channel_video_sync(switch_core_session_get_channel(lsession)); + status = SWITCH_STATUS_SUCCESS; + switch_core_session_rwunlock(lsession); + } + } + + if (status == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Success\n"); + } else { + stream->write_function(stream, "-ERR Operation Failed\n"); + } + + switch_safe_free(mycmd); + + return SWITCH_STATUS_SUCCESS; +} + #define DEBUG_MEDIA_SYNTAX " " SWITCH_STANDARD_API(uuid_debug_media_function) @@ -6799,6 +6842,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_send_message", "Send MESSAGE to the endpoint", uuid_send_message_function, SEND_MESSAGE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_send_info", "Send info to the endpoint", uuid_send_info_function, INFO_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_set_media_stats", "Set media stats", uuid_set_media_stats, UUID_MEDIA_STATS_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_video_bitrate", "Send video bitrate req.", uuid_video_bitrate_function, VIDEO_BITRATE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_video_refresh", "Send video refresh.", uuid_video_refresh_function, VIDEO_REFRESH_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_outgoing_answer", "Answer outgoing channel", outgoing_answer_function, OUTGOING_ANSWER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_limit", "Increase limit resource", uuid_limit_function, LIMIT_SYNTAX); @@ -7004,6 +7048,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_transfer ::console::list_uuid"); switch_console_set_complete("add uuid_dual_transfer ::console::list_uuid"); switch_console_set_complete("add uuid_video_refresh ::console::list_uuid"); + switch_console_set_complete("add uuid_video_bitrate ::console::list_uuid"); switch_console_set_complete("add version"); switch_console_set_complete("add uuid_warning ::console::list_uuid"); switch_console_set_complete("add ..."); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 1d810706ad..e437a2347d 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -48,7 +48,7 @@ static void gen_ice(switch_core_session_t *session, switch_media_type_t type, co #define MAX_CODEC_CHECK_FRAMES 50//x:mod_sofia.h #define MAX_MISMATCH_FRAMES 5//x:mod_sofia.h #define type2str(type) type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio" -#define VIDEO_REFRESH_FREQ 1000000 +#define VIDEO_REFRESH_FREQ 100000 typedef enum { SMF_INIT = (1 << 0), @@ -8614,6 +8614,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se break; + case SWITCH_MESSAGE_INDICATE_BITRATE_REQ: + { + if (v_engine->rtp_session) { + switch_rtp_req_bitrate(v_engine->rtp_session, msg->numeric_arg); + } + } + break; + + case SWITCH_MESSAGE_INDICATE_BITRATE_ACK: + { + if (v_engine->rtp_session) { + switch_rtp_ack_bitrate(v_engine->rtp_session, msg->numeric_arg); + } + } + break; + case SWITCH_MESSAGE_INDICATE_DEBUG_MEDIA: { switch_rtp_t *rtp = a_engine->rtp_session; @@ -10270,6 +10286,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor switch_goto_status(vstatus, done); } + /* When desired, scale video to match the input signal (if output is bigger) */ if (switch_channel_test_flag(session->channel, CF_VIDEO_READY) && smh->vid_params.width && switch_channel_test_flag(session->channel, CF_VIDEO_MIRROR_INPUT) && diff --git a/src/switch_rtp.c b/src/switch_rtp.c index f35b48c70f..d8392ae980 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -127,26 +127,13 @@ typedef struct { #pragma pack(push, r1, 1) #endif -#if SWITCH_BYTE_ORDER == __BIG_ENDIAN + typedef struct { uint32_t ssrc; - unsigned exp:6; - unsigned mantissa:17; - unsigned overhead:9; + uint8_t parts[4]; } rtcp_tmmbx_t; -#else - -typedef struct { - uint32_t ssrc; - unsigned overhead:9; - unsigned mantissa:17; - unsigned exp:6; -} rtcp_tmmbx_t; - -#endif - #if SWITCH_BYTE_ORDER == __BIG_ENDIAN typedef struct { @@ -322,6 +309,7 @@ struct switch_rtp { uint16_t fir_count; uint16_t pli_count; uint32_t cur_nack; + uint32_t cur_tmmbr; uint32_t tmmbr; uint32_t tmmbn; @@ -1854,6 +1842,31 @@ static int rtcp_stats(switch_rtp_t *rtp_session) return 1; } +static void calc_bw_exp(uint32_t bps, uint8_t bits, rtcp_tmmbx_t *tmmbx) +{ + uint32_t mantissa_max, i = 0; + uint8_t exp = 0; + uint32_t mantissa = 0; + uint16_t overhead = 0; + + mantissa_max = (1 << bits) - 1; + + for (i = 0; i < 64; ++i) { + if (bps <= (mantissa_max << i)) { + exp = i; + break; + } + } + + mantissa = (bps >> exp); + + tmmbx->parts[0] = (uint8_t) ((exp << 2) + ((mantissa >> 15) & 0x03)); + tmmbx->parts[1] = (uint8_t) (mantissa >> 7); + tmmbx->parts[2] = (uint8_t) ((mantissa >> 1) + ((overhead >> 8) & 0x01)); + tmmbx->parts[3] = (uint8_t) (overhead); +} + + static int check_rtcp_and_ice(switch_rtp_t *rtp_session) { int ret = 0; @@ -2018,10 +2031,14 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) rtp_session->fir_count--; } + //if (!rtp_session->tmmbr && rtp_session->cur_tmmbr) { + // rtp_session->tmmbr = rtp_session->cur_tmmbr; + //} + while (rtp_session->tmmbr || rtp_session->tmmbn) { switch_rtcp_ext_hdr_t *ext_hdr; rtcp_tmmbx_t *tmmbx; - uint32_t body = 0; + uint32_t bps = 0; p = (uint8_t *) (&rtp_session->rtcp_send_msg) + rtcp_bytes; ext_hdr = (switch_rtcp_ext_hdr_t *) p; @@ -2030,25 +2047,27 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) ext_hdr->version = 2; ext_hdr->p = 0; - ext_hdr->pt = RTCP_PT_PSFB; + ext_hdr->pt = RTCP_PT_RTPFB; ext_hdr->send_ssrc = htonl(rtp_session->ssrc); ext_hdr->recv_ssrc = 0; if (rtp_session->tmmbr) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP TMMBR %u\n", rtp_session->tmmbr); ext_hdr->fmt = RTCP_RTPFB_TMMBR; - body = rtp_session->tmmbr; + bps = rtp_session->tmmbr; rtp_session->tmmbr = 0; } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP TMMBN %u\n", rtp_session->tmmbr); ext_hdr->fmt = RTCP_RTPFB_TMMBN; - body = rtp_session->tmmbn; + bps = rtp_session->tmmbn; rtp_session->tmmbn = 0; } tmmbx->ssrc = htonl(rtp_session->remote_ssrc); - memcpy(p+4, &body, sizeof(body)); + calc_bw_exp(bps, 17, tmmbx); - ext_hdr->length = htons((uint8_t)((sizeof(switch_rtcp_ext_hdr_t) + sizeof(rtcp_fir_t)) / 4) - 1); - rtcp_bytes += sizeof(switch_rtcp_ext_hdr_t) + sizeof(rtcp_tmmbx_t); + ext_hdr->length = htons((uint8_t)((sizeof(switch_rtcp_ext_hdr_t) + sizeof(rtcp_tmmbx_t)) / 4) - 1); + rtcp_bytes += sizeof(switch_rtcp_ext_hdr_t) + sizeof(rtcp_tmmbx_t); } } @@ -4162,38 +4181,24 @@ SWITCH_DECLARE(void) switch_rtp_flush(switch_rtp_t *rtp_session) switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH); } -static uint32_t calc_bw_exp(uint32_t bps, uint8_t bits) -{ - uint32_t r = 0; - rtcp_tmmbx_t *tmmbx; - uint32_t mantissa_max, i = 0; - - tmmbx = (rtcp_tmmbx_t *) &r; - - mantissa_max = (1 << bits) - 1; - - for (i = 0; i < 64; ++i) { - if (bps <= (mantissa_max << i)) { - tmmbx->exp = i; - break; - } - } - - tmmbx->mantissa = (bps >> tmmbx->exp); - - - - return r; -} - - -SWITCH_DECLARE(switch_status_t) switch_rtp_req_bandwidth(switch_rtp_t *rtp_session, uint32_t bps) +SWITCH_DECLARE(switch_status_t) switch_rtp_req_bitrate(switch_rtp_t *rtp_session, uint32_t bps) { if (!rtp_write_ready(rtp_session, 0, __LINE__) || rtp_session->tmmbr) { return SWITCH_STATUS_FALSE; } - rtp_session->tmmbr = calc_bw_exp(bps, 17); + rtp_session->tmmbr = bps; + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_ack_bitrate(switch_rtp_t *rtp_session, uint32_t bps) +{ + if (!rtp_write_ready(rtp_session, 0, __LINE__) || rtp_session->tmmbn) { + return SWITCH_STATUS_FALSE; + } + + rtp_session->tmmbn = bps; return SWITCH_STATUS_SUCCESS; }