summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2012-04-12 13:41:50 +0000
committerNanang Izzuddin <nanang@teluu.com>2012-04-12 13:41:50 +0000
commit64d1bed1542041370f054e693dcb131dac889618 (patch)
tree0f8cbd8452cb5bc88a5e9f07be9772ec7d2ff87d
parente3cf311ea66955482cc6c8197c685456aa7f41cc (diff)
Re #1476: Initial version of send rate control in video stream, added simple blocking method (block application thread to make send delay when delay is needed).
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4043 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/vid_stream.h57
-rw-r--r--pjmedia/src/pjmedia/vid_stream.c61
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h7
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c1
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c3
5 files changed, 127 insertions, 2 deletions
diff --git a/pjmedia/include/pjmedia/vid_stream.h b/pjmedia/include/pjmedia/vid_stream.h
index 634709a0..c812d37d 100644
--- a/pjmedia/include/pjmedia/vid_stream.h
+++ b/pjmedia/include/pjmedia/vid_stream.h
@@ -73,6 +73,51 @@ PJ_BEGIN_DECL
*/
+/**
+ * Enumeration of video stream sending rate control.
+ */
+typedef enum pjmedia_vid_stream_rc_method
+{
+ /**
+ * No sending rate control. All outgoing RTP packets will be transmitted
+ * immediately right after encoding process is done.
+ */
+ PJMEDIA_VID_STREAM_RC_NONE = 0,
+
+ /**
+ * Simple blocking. Each outgoing RTP packet transmission may be delayed
+ * to avoid peak bandwidth that is much higher than specified. The thread
+ * invoking the video stream put_frame(), e.g: video capture device thread,
+ * will be blocked whenever transmission delay takes place.
+ */
+ PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING = 1
+
+} pjmedia_vid_stream_rc_method;
+
+
+/**
+ * Structure of configuration settings for video stream sending rate control.
+ */
+typedef struct pjmedia_vid_stream_rc_config
+{
+ /**
+ * Rate control method.
+ *
+ * Default: PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING.
+ */
+ pjmedia_vid_stream_rc_method method;
+
+ /**
+ * Upstream/outgoing bandwidth. If this is set to zero, the video stream
+ * will use codec maximum bitrate setting.
+ *
+ * Default: 0 (follow codec maximum bitrate).
+ */
+ unsigned bandwidth;
+
+} pjmedia_vid_stream_rc_config;
+
+
/**
* This structure describes video stream information. Each video stream
* corresponds to one "m=" line in SDP session descriptor, and it has
@@ -117,6 +162,9 @@ typedef struct pjmedia_vid_stream_info
pj_bool_t rtcp_sdes_bye_disabled;
/**< Disable automatic sending of RTCP
SDES and BYE. */
+
+ pjmedia_vid_stream_rc_config rc_cfg;
+ /**< Stream send rate control settings. */
} pjmedia_vid_stream_info;
@@ -145,6 +193,15 @@ pjmedia_vid_stream_info_from_sdp(pjmedia_vid_stream_info *si,
unsigned stream_idx);
+/**
+ * Initialize the video stream rate control with default settings.
+ *
+ * @param cfg Video stream rate control structure to be initialized.
+ */
+PJ_DECL(void)
+pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config *cfg);
+
+
/*
* Opaque declaration for video stream.
*/
diff --git a/pjmedia/src/pjmedia/vid_stream.c b/pjmedia/src/pjmedia/vid_stream.c
index a813758e..af5a08dc 100644
--- a/pjmedia/src/pjmedia/vid_stream.c
+++ b/pjmedia/src/pjmedia/vid_stream.c
@@ -153,8 +153,11 @@ struct pjmedia_vid_stream
#endif
pjmedia_vid_codec *codec; /**< Codec instance being used. */
- pj_uint32_t last_dec_ts; /**< Last decoded timestamp. */
- int last_dec_seq; /**< Last decoded sequence. */
+ pj_uint32_t last_dec_ts; /**< Last decoded timestamp. */
+ int last_dec_seq; /**< Last decoded sequence. */
+
+
+ pj_timestamp ts_freq; /**< Timestamp frequency. */
};
/* Prototypes */
@@ -768,6 +771,8 @@ static pj_status_t put_frame(pjmedia_port *port,
pj_bool_t has_more_data = PJ_FALSE;
pj_size_t total_sent = 0;
pjmedia_vid_encode_opt enc_opt;
+ unsigned pkt_cnt = 0;
+ pj_timestamp initial_time;
#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0
/* If the interval since last sending packet is greater than
@@ -826,6 +831,8 @@ static pj_status_t put_frame(pjmedia_port *port,
&rtphdrlen);
return status;
}
+
+ pj_get_timestamp(&initial_time);
/* Loop while we have frame to send */
for (;;) {
@@ -864,6 +871,7 @@ static pj_status_t put_frame(pjmedia_port *port,
pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size);
total_sent += frame_out.size;
+ pkt_cnt++;
if (!has_more_data)
break;
@@ -885,8 +893,41 @@ static pj_status_t put_frame(pjmedia_port *port,
/* Ignore this error (?) */
break;
}
+
+ /* Send rate control */
+ if (stream->info.rc_cfg.method==PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING)
+ {
+ pj_timestamp now, next_send_ts, total_send_ts;
+
+ total_send_ts.u64 = total_sent * stream->ts_freq.u64 * 8 /
+ stream->info.rc_cfg.bandwidth;
+ next_send_ts = initial_time;
+ pj_add_timestamp(&next_send_ts, &total_send_ts);
+
+ pj_get_timestamp(&now);
+ if (pj_cmp_timestamp(&now, &next_send_ts) < 0) {
+ unsigned ms_sleep;
+ ms_sleep = pj_elapsed_msec(&now, &next_send_ts);
+
+ if (ms_sleep > 10)
+ ms_sleep = 10;
+
+ pj_thread_sleep(ms_sleep);
+ }
+ }
}
+#if 0
+ /* Trace log for rate control */
+ {
+ pj_timestamp end_time;
+ pj_get_timestamp(&end_time);
+ PJ_LOG(5, (stream->name.ptr, "total pkt=%d size=%d sleep=%d",
+ pkt_cnt, total_sent,
+ pj_elapsed_msec(&initial_time, &end_time)));
+ }
+#endif
+
/* Check if now is the time to transmit RTCP SR/RR report.
* We only do this when stream direction is not "decoding only", because
* when it is, check_tx_rtcp() will be handled by get_frame().
@@ -1413,6 +1454,11 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create(
stream->frame_ts_len = info->codec_info.clock_rate *
vfd_enc->fps.denum / vfd_enc->fps.num;
+ /* Initialize send rate states */
+ pj_get_timestamp_freq(&stream->ts_freq);
+ if (info->rc_cfg.bandwidth == 0)
+ info->rc_cfg.bandwidth = vfd_enc->max_bps * 150 / 100;
+
/* Override the initial framerate in the decoding direction. This initial
* value will be used by the renderer to configure its clock, and setting
* it to a bit higher value can avoid the possibility of high latency
@@ -1867,4 +1913,15 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_send_rtcp_bye(
}
+/*
+ * Initialize the video stream rate control with default settings.
+ */
+PJ_DEF(void)
+pjmedia_vid_stream_rc_config_default(pjmedia_vid_stream_rc_config *cfg)
+{
+ pj_bzero(cfg, sizeof(*cfg));
+ cfg->method = PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING;
+}
+
+
#endif /* PJMEDIA_HAS_VIDEO */
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 98942e3a..73dc9291 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -2882,6 +2882,13 @@ typedef struct pjsua_acc_config
pjmedia_vid_dev_index vid_rend_dev;
/**
+ * Specify the send rate control for video stream.
+ *
+ * Default: see #pjmedia_vid_stream_rc_config
+ */
+ pjmedia_vid_stream_rc_config vid_stream_rc_cfg;
+
+ /**
* Media transport config.
*/
pjsua_transport_config rtp_cfg;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 89f2b13d..aeb85ebf 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -218,6 +218,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->ka_data = pj_str("\r\n");
cfg->vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
cfg->vid_rend_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+ pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg);
pjsua_transport_config_default(&cfg->rtp_cfg);
cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index 24f0919f..b8ece7a8 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -747,6 +747,9 @@ pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
si->rtp_seq = call_med->rtp_tx_seq;
si->rtp_seq_ts_set = call_med->rtp_tx_seq_ts_set;
+ /* Set rate control config from account setting */
+ si->rc_cfg = acc->cfg.vid_stream_rc_cfg;
+
#if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA!=0
/* Enable/disable stream keep-alive and NAT hole punch. */
si->use_ka = pjsua_var.acc[call->acc_id].cfg.use_stream_ka;