Update WP8 build

Add 1500mils delay for outgoing SIP INFOs(fast update)
Detect RTCP-fb features at session start up after best codec is known
This commit is contained in:
bossiel 2015-07-05 18:34:37 +00:00
parent 8579d2ce82
commit b24ba08f11
7 changed files with 241 additions and 202 deletions

View File

@ -79,7 +79,7 @@ namespace doubango_rt
};
public enum class rt_tmedia_pref_video_size_t
{
{/* must be sorted like this */
tmedia_pref_video_size_sqcif = tmedia_pref_video_size_sqcif, // 128 x 98
tmedia_pref_video_size_qcif = tmedia_pref_video_size_qcif, // 176 x 144
tmedia_pref_video_size_qvga = tmedia_pref_video_size_qvga, // 320 x 240
@ -87,8 +87,10 @@ namespace doubango_rt
tmedia_pref_video_size_hvga = tmedia_pref_video_size_hvga, // 480 x 320
tmedia_pref_video_size_vga = tmedia_pref_video_size_vga, // 640 x 480
tmedia_pref_video_size_4cif = tmedia_pref_video_size_4cif, // 704 x 576
tmedia_pref_video_size_wvga = tmedia_pref_video_size_wvga, // 800 x 480
tmedia_pref_video_size_svga = tmedia_pref_video_size_svga, // 800 x 600
tmedia_pref_video_size_480p = tmedia_pref_video_size_480p, // 852 x 480
tmedia_pref_video_size_xga = tmedia_pref_video_size_xga, // 1024 x 768
tmedia_pref_video_size_720p = tmedia_pref_video_size_720p, // 1280 x 720
tmedia_pref_video_size_16cif = tmedia_pref_video_size_16cif, // 1408 x 1152
tmedia_pref_video_size_1080p = tmedia_pref_video_size_1080p, // 1920 x 1080

View File

@ -285,6 +285,10 @@ namespace doubango_rt
bool setRtcpMux(bool enabled);
bool setICE(bool enabled);
bool setQoS(rt_tmedia_qos_stype_t type, rt_tmedia_qos_strength_t strength);
bool setVideoFps(int32_t fps);
bool setVideoBandwidthUploadMax(int32_t max);
bool setVideoBandwidthDownloadMax(int32_t max);
bool setVideoPrefSize(rt_tmedia_pref_video_size_t pref_video_size);
bool hold(rtActionConfig^ config);
bool hold();
bool resume(rtActionConfig^ config);

View File

@ -161,6 +161,26 @@ bool rtCallSession::setQoS(rt_tmedia_qos_stype_t type, rt_tmedia_qos_strength_t
return m_pSipSession->setQoS((tmedia_qos_stype_t) type, (tmedia_qos_strength_t) strength);
}
bool rtCallSession::setVideoFps(int32_t fps)
{
return m_pSipSession->setVideoFps(fps);
}
bool rtCallSession::setVideoBandwidthUploadMax(int32_t max)
{
return m_pSipSession->setVideoBandwidthUploadMax(max);
}
bool rtCallSession::setVideoBandwidthDownloadMax(int32_t max)
{
return m_pSipSession->setVideoBandwidthDownloadMax(max);
}
bool rtCallSession::setVideoPrefSize(rt_tmedia_pref_video_size_t pref_video_size)
{
return m_pSipSession->setVideoPrefSize((tmedia_pref_video_size_t)pref_video_size);
}
bool rtCallSession::hold(rtActionConfig^ config)
{
return m_pSipSession->hold(config ? config->getWrappedActionConfig() : tsk_null);

View File

@ -590,6 +590,33 @@ int tdav_session_av_start(tdav_session_av_t* self, const tmedia_codec_t* best_co
}
}
}
// Check if "RTCP-NACK", "RTC-FIR", "RTCP-GOOG-REMB".... are supported by the selected encoder
self->is_fb_fir_neg = self->is_fb_nack_neg = self->is_fb_googremb_neg = tsk_false;
if (TMEDIA_SESSION(self)->M.ro) {
// a=rtcp-fb:* ccm fir
// a=rtcp-fb:* nack
// a=rtcp-fb:* goog-remb
char attr_fir[256], attr_nack[256], attr_goog_remb[256];
int index = 0;
const tsdp_header_A_t* A;
sprintf(attr_fir, "%s ccm fir", best_codec->neg_format);
sprintf(attr_nack, "%s nack", best_codec->neg_format);
sprintf(attr_goog_remb, "%s goog-remb", best_codec->neg_format);
while ((A = tsdp_header_M_findA_at(TMEDIA_SESSION(self)->M.ro, "rtcp-fb", index++))) {
if (!self->is_fb_fir_neg) {
self->is_fb_fir_neg = (tsk_striequals(A->value, "* ccm fir") || tsk_striequals(A->value, attr_fir));
}
if (!self->is_fb_nack_neg) {
self->is_fb_nack_neg = (tsk_striequals(A->value, "* nack") || tsk_striequals(A->value, attr_nack));
}
if (!self->is_fb_googremb_neg) {
self->is_fb_googremb_neg = (tsk_striequals(A->value, "* goog-remb") || tsk_striequals(A->value, attr_goog_remb));
}
}
}
if (self->rtp_manager) {
int ret;

View File

@ -21,9 +21,9 @@
*/
/**@file tdav_session_video.c
* @brief Video Session plugin.
*
*/
* @brief Video Session plugin.
*
*/
#include "tinydav/video/tdav_session_video.h"
#include "tinydav/video/tdav_converter_video.h"
#include "tinydav/video/jb/tdav_video_jb.h"
@ -79,51 +79,51 @@ static const tmedia_codec_action_t __action_encode_bw_down = tmedia_codec_action
// FIXME: lock ?
#define _tdav_session_video_codec_set(__self, key, value) \
{ \
static tmedia_param_t* __param = tsk_null; \
if(!__param){ \
__param = tmedia_param_create(tmedia_pat_set, \
tmedia_video, \
tmedia_ppt_codec, \
tmedia_pvt_int32, \
"action", \
(void*)&value); \
} \
if((__self)->encoder.codec && __param){ \
/*tsk_mutex_lock((__self)->encoder.h_mutex);*/ \
if(TDAV_SESSION_AV(__self)->producer && TDAV_SESSION_AV(__self)->producer->encoder.codec_id == (__self)->encoder.codec->id) { /* Whether the producer ourput encoded frames */ \
tmedia_producer_set(TDAV_SESSION_AV(__self)->producer, __param); \
} \
{ \
static tmedia_param_t* __param = tsk_null; \
if(!__param){ \
__param = tmedia_param_create(tmedia_pat_set, \
tmedia_video, \
tmedia_ppt_codec, \
tmedia_pvt_int32, \
"action", \
(void*)&value); \
} \
if((__self)->encoder.codec && __param){ \
/*tsk_mutex_lock((__self)->encoder.h_mutex);*/ \
if(TDAV_SESSION_AV(__self)->producer && TDAV_SESSION_AV(__self)->producer->encoder.codec_id == (__self)->encoder.codec->id) { /* Whether the producer ourput encoded frames */ \
tmedia_producer_set(TDAV_SESSION_AV(__self)->producer, __param); \
} \
else { \
tmedia_codec_set((tmedia_codec_t*)(__self)->encoder.codec, __param); \
} \
/*tsk_mutex_unlock((__self)->encoder.h_mutex);*/ \
} \
/* TSK_OBJECT_SAFE_FREE(param); */ \
}
tmedia_codec_set((tmedia_codec_t*)(__self)->encoder.codec, __param); \
} \
/*tsk_mutex_unlock((__self)->encoder.h_mutex);*/ \
} \
/* TSK_OBJECT_SAFE_FREE(param); */ \
}
#define _tdav_session_video_remote_requested_idr(__self, __ssrc_media) { \
uint64_t __now = tsk_time_now(); \
tsk_bool_t too_close = tsk_false; \
if((__now - (__self)->avpf.last_fir_time) > TDAV_SESSION_VIDEO_AVPF_FIR_HONOR_INTERVAL_MIN){ /* guard to avoid sending too many FIR */ \
_tdav_session_video_codec_set((__self), "action", __action_encode_idr); \
_tdav_session_video_codec_set((__self), "action", __action_encode_idr); \
}else { too_close = tsk_true; TSK_DEBUG_INFO("***IDR request tooo close(%llu ms)...ignoring****", (__now - (__self)->avpf.last_fir_time)); } \
if((__self)->cb_rtcpevent.func){ \
(__self)->cb_rtcpevent.func((__self)->cb_rtcpevent.context, tmedia_rtcp_event_type_fir, (__ssrc_media)); \
(__self)->cb_rtcpevent.func((__self)->cb_rtcpevent.context, tmedia_rtcp_event_type_fir, (__ssrc_media)); \
} \
if (!too_close) { /* if too close don't update "last_fir_time" to "now" to be sure interval will increase */ \
(__self)->avpf.last_fir_time = __now; \
(__self)->avpf.last_fir_time = __now; \
} \
}
#define _tdav_session_video_local_request_idr(_session, _reason, _ssrc) \
{ \
tdav_session_av_t* _base = (tdav_session_av_t*)_session; \
if ((_base)->avpf_mode_neg || (_base)->is_fb_fir_neg) { \
/*return*/ trtp_manager_signal_frame_corrupted((_base)->rtp_manager, _ssrc); \
} \
tdav_session_av_t* _base = (tdav_session_av_t*)_session; \
if ((_base)->avpf_mode_neg || (_base)->is_fb_fir_neg) { \
/*return*/ trtp_manager_signal_frame_corrupted((_base)->rtp_manager, _ssrc); \
} \
else if ((_session)->rfc5168_cb.fun) { \
/*return*/ (_session)->rfc5168_cb.fun((_session)->rfc5168_cb.usrdata, (_session), (_reason), tmedia_session_rfc5168_cmd_picture_fast_update); \
} \
/*return*/ (_session)->rfc5168_cb.fun((_session)->rfc5168_cb.usrdata, (_session), (_reason), tmedia_session_rfc5168_cmd_picture_fast_update); \
} \
}
#define _tdav_session_video_bw_up(__self) _tdav_session_video_codec_set(__self, "action", __action_encode_bw_up)
#define _tdav_session_video_bw_down(__self) _tdav_session_video_codec_set(__self, "action", __action_encode_bw_down)
@ -151,7 +151,7 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
trtp_rtp_packet_t* packet = tsk_null;
int ret = 0;
tsk_size_t s;
if(base->rtp_manager && base->rtp_manager->is_started){
if(rtp_header){
// uses negotiated SSRC (SDP)
@ -188,17 +188,17 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
packet = rtp_header
? trtp_rtp_packet_create_2(rtp_header)
: trtp_rtp_packet_create(base->rtp_manager->rtp.ssrc.local, base->rtp_manager->rtp.seq_num, base->rtp_manager->rtp.timestamp, base->rtp_manager->rtp.payload_type, result->last_chunck);
if(packet ){
tsk_size_t rtp_hdr_size;
if(result->last_chunck){
#if 1
#if 1
/* http://www.cs.columbia.edu/~hgs/rtp/faq.html#timestamp-computed
For video, time clock rate is fixed at 90 kHz. The timestamps generated depend on whether the application can determine the frame number or not.
If it can or it can be sure that it is transmitting every frame with a fixed frame rate, the timestamp is governed by the nominal frame rate. Thus, for a 30 f/s video, timestamps would increase by 3,000 for each frame, for a 25 f/s video by 3,600 for each frame.
If a frame is transmitted as several RTP packets, these packets would all bear the same timestamp.
If the frame number cannot be determined or if frames are sampled aperiodically, as is typically the case for software codecs, the timestamp has to be computed from the system clock (e.g., gettimeofday())
For video, time clock rate is fixed at 90 kHz. The timestamps generated depend on whether the application can determine the frame number or not.
If it can or it can be sure that it is transmitting every frame with a fixed frame rate, the timestamp is governed by the nominal frame rate. Thus, for a 30 f/s video, timestamps would increase by 3,000 for each frame, for a 25 f/s video by 3,600 for each frame.
If a frame is transmitted as several RTP packets, these packets would all bear the same timestamp.
If the frame number cannot be determined or if frames are sampled aperiodically, as is typically the case for software codecs, the timestamp has to be computed from the system clock (e.g., gettimeofday())
*/
if(!video->encoder.last_frame_time){
@ -219,7 +219,7 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
#else
base->rtp_manager->rtp.timestamp += result->duration;
#endif
}
packet->payload.data_const = result->buffer.ptr;
@ -288,9 +288,9 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
if(ret == 0 && video->red.codec){
// don't need to lock as the buffer is never used by other codecs
tsk_size_t red_pay_size = video->red.codec->plugin->encode(
video->red.codec,
buffer, size,
&video->encoder.buffer, &video->encoder.buffer_size
video->red.codec,
buffer, size,
&video->encoder.buffer, &video->encoder.buffer_size
);
if(red_pay_size > 1){
packet->header->payload_type = video->red.payload_type;
@ -309,7 +309,7 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
else{
//--TSK_DEBUG_WARN("Session not ready yet");
}
bail:
TSK_OBJECT_SAFE_FREE(packet);
return ret;
@ -339,7 +339,7 @@ static int tdav_session_video_decode_cb(const tmedia_video_decode_result_xt* res
_tdav_session_video_local_request_idr(TMEDIA_SESSION(video), "DECODED_FAILED", ((const trtp_rtp_header_t*)result->proto_hdr)->ssrc);
break;
}
default: break;
default: break;
}
return 0;
}
@ -404,7 +404,7 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
#define PRODUCER_OUTPUT_FIXSIZE (base->producer->video.chroma != tmedia_chroma_mjpeg) // whether the output data has a fixed size/length
#define PRODUCER_OUTPUT_RAW (base->producer->encoder.codec_id == tmedia_codec_id_none) // Otherwise, frames from the producer are already encoded
#define PRODUCER_SIZE_CHANGED ((video->conv.producerWidth && video->conv.producerWidth != base->producer->video.width) || (video->conv.producerHeight && video->conv.producerHeight != base->producer->video.height) \
|| (video->conv.xProducerSize && (video->conv.xProducerSize != size && PRODUCER_OUTPUT_FIXSIZE)))
|| (video->conv.xProducerSize && (video->conv.xProducerSize != size && PRODUCER_OUTPUT_FIXSIZE)))
#define ENCODED_NEED_FLIP (TMEDIA_CODEC_VIDEO(codec_encoder)->out.flip)
#define ENCODED_NEED_RESIZE (base->producer->video.width != TMEDIA_CODEC_VIDEO(codec_encoder)->out.width || base->producer->video.height != TMEDIA_CODEC_VIDEO(codec_encoder)->out.height)
#define PRODUCED_FRAME_NEED_ROTATION (base->producer->video.rotation != 0)
@ -418,16 +418,16 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
video->conv.producerWidth = base->producer->video.width;
video->conv.producerHeight = base->producer->video.height;
video->conv.xProducerSize = size;
TSK_DEBUG_INFO("producer size = (%d, %d)", (int)base->producer->video.width, (int)base->producer->video.height);
if (!(video->conv.toYUV420 = tmedia_converter_video_create(base->producer->video.width, base->producer->video.height, base->producer->video.chroma, TMEDIA_CODEC_VIDEO(codec_encoder)->out.width, TMEDIA_CODEC_VIDEO(codec_encoder)->out.height,
TMEDIA_CODEC_VIDEO(codec_encoder)->out.chroma))){
TSK_DEBUG_ERROR("Failed to create video converter");
ret = -5;
goto bail;
TSK_DEBUG_ERROR("Failed to create video converter");
ret = -5;
goto bail;
}
// restore/set rotation scaling info because producer size could change
tmedia_converter_video_set_scale_rotated_frames(video->conv.toYUV420, video->encoder.scale_rotated_frames);
// restore/set rotation scaling info because producer size could change
tmedia_converter_video_set_scale_rotated_frames(video->conv.toYUV420, video->encoder.scale_rotated_frames);
}
}
@ -438,11 +438,11 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
// it's up to the encoder to swap (w,h) and to track the rotation value
if(video->encoder.rotation != base->producer->video.rotation){
tmedia_param_t* param = tmedia_param_create(tmedia_pat_set,
tmedia_video,
tmedia_ppt_codec,
tmedia_pvt_int32,
"rotation",
(void*)&base->producer->video.rotation);
tmedia_video,
tmedia_ppt_codec,
tmedia_pvt_int32,
"rotation",
(void*)&base->producer->video.rotation);
if (!param) {
TSK_DEBUG_ERROR("Failed to create a media parameter");
return -1;
@ -456,7 +456,7 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
// update one-shot parameters
tmedia_converter_video_set(video->conv.toYUV420, base->producer->video.rotation, TMEDIA_CODEC_VIDEO(codec_encoder)->out.flip, base->producer->video.mirror, video->encoder.scale_rotated_frames);
yuv420p_size = tmedia_converter_video_process(video->conv.toYUV420, buffer, size, &video->encoder.conv_buffer, &video->encoder.conv_buffer_size);
if (!yuv420p_size || !video->encoder.conv_buffer) {
TSK_DEBUG_ERROR("Failed to convert XXX buffer to YUV42P");
@ -483,7 +483,7 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
/* Never called, see tdav_session_video_raw_cb() */
trtp_manager_send_rtp(base->rtp_manager, video->encoder.buffer, out_size, 6006, tsk_true, tsk_true);
}
bail:
bail:
TSK_OBJECT_SAFE_FREE(codec_encoder);
}
else {
@ -514,10 +514,10 @@ static int tdav_session_video_rtp_cb(const void* callback_data, const trtp_rtp_p
}
// Decode RED data
base->red.codec->plugin->decode(
base->red.codec,
(packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size,
&__red_buffer_ptr, &__red_buffer_size,
packet->header
base->red.codec,
(packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size,
&__red_buffer_ptr, &__red_buffer_size,
packet->header
);
return 0;
}
@ -542,47 +542,47 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
const trtp_rtcp_report_psfb_t* psfb;
const trtp_rtcp_report_rtpfb_t* rtpfb;
const trtp_rtcp_rblocks_L_t* blocks = tsk_null;
tdav_session_video_t* video = (tdav_session_video_t*)callback_data;
tdav_session_av_t* base = (tdav_session_av_t*)callback_data;
tsk_size_t i;
if((blocks = (packet->header->type == trtp_rtcp_packet_type_rr) ? ((const trtp_rtcp_report_rr_t*)packet)->blocks :
(packet->header->type == trtp_rtcp_packet_type_sr ? ((const trtp_rtcp_report_sr_t*)packet)->blocks : tsk_null))){
const tsk_list_item_t* item;
const trtp_rtcp_rblock_t* block;
tsk_list_foreach(item, blocks){
if(!(block = item->data)) continue;
if(base->rtp_manager->rtp.ssrc.local == block->ssrc){
tdav_session_video_pkt_loss_level_t pkt_loss_level = tdav_session_video_pkt_loss_level_low;
if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_HIGH) pkt_loss_level = tdav_session_video_pkt_loss_level_high;
else if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_MEDIUM) pkt_loss_level = tdav_session_video_pkt_loss_level_medium;
if(pkt_loss_level == tdav_session_video_pkt_loss_level_high || (pkt_loss_level > video->encoder.pkt_loss_level)){ // high or low -> medium
video->encoder.pkt_loss_level = pkt_loss_level;
if(video->encoder.pkt_loss_prob_bad-- <= 0){
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact + 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
TSK_DEBUG_INFO("Downgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
_tdav_session_video_bw_down(video);
const tsk_list_item_t* item;
const trtp_rtcp_rblock_t* block;
tsk_list_foreach(item, blocks){
if(!(block = item->data)) continue;
if(base->rtp_manager->rtp.ssrc.local == block->ssrc){
tdav_session_video_pkt_loss_level_t pkt_loss_level = tdav_session_video_pkt_loss_level_low;
if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_HIGH) pkt_loss_level = tdav_session_video_pkt_loss_level_high;
else if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_MEDIUM) pkt_loss_level = tdav_session_video_pkt_loss_level_medium;
if(pkt_loss_level == tdav_session_video_pkt_loss_level_high || (pkt_loss_level > video->encoder.pkt_loss_level)){ // high or low -> medium
video->encoder.pkt_loss_level = pkt_loss_level;
if(video->encoder.pkt_loss_prob_bad-- <= 0){
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact + 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
TSK_DEBUG_INFO("Downgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
_tdav_session_video_bw_down(video);
}
_tdav_session_video_reset_loss_prob(video);
}
_tdav_session_video_reset_loss_prob(video);
}
}
else{
if(video->encoder.pkt_loss_prob_good-- <= 0){
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact - 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
TSK_DEBUG_INFO("Upgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
_tdav_session_video_bw_up(video);
else{
if(video->encoder.pkt_loss_prob_good-- <= 0){
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact - 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
TSK_DEBUG_INFO("Upgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
_tdav_session_video_bw_up(video);
}
_tdav_session_video_reset_loss_prob(video);
}
_tdav_session_video_reset_loss_prob(video);
}
break;
}
break;
}
}
}
i = 0;
@ -622,7 +622,7 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
i = 0;
while((rtpfb = (const trtp_rtcp_report_rtpfb_t*)trtp_rtcp_packet_get_at(packet, trtp_rtcp_packet_type_rtpfb, i++))){
switch(rtpfb->fci_type){
default: break;
default: break;
case trtp_rtcp_rtpfb_fci_type_nack:
{
if(rtpfb->nack.blp && rtpfb->nack.pid){
@ -636,7 +636,7 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
int32_t blp_count;
blp = rtpfb->nack.blp[i];
blp_count = blp ? 16 : 0;
for(j = -1/*Packet ID (PID)*/; j < blp_count; ++j){
if(j == -1 || (blp & __Pow2[j])){
pid = (rtpfb->nack.pid[i] + (j + 1));
@ -645,7 +645,7 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
if(!(pkt_rtp = item->data)){
continue;
}
// Very Important: the seq_nums are not consecutive because of wrapping.
// For example, '65533, 65534, 65535, 0, 1' is a valid sequences which means we have to check all packets (probaly need somthing smarter)
if(pkt_rtp->header->seq_num == pid){
@ -664,10 +664,10 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
pid,
(int)video->avpf.max,
(int)video->avpf.count);
// FIR not really requested but needed
/*_tdav_session_video_remote_requested_idr(video, ((const trtp_rtcp_report_fb_t*)rtpfb)->ssrc_media);
tsk_list_clear_items(video->avpf.packets);
video->avpf.count = 0;*/
// FIR not really requested but needed
/*_tdav_session_video_remote_requested_idr(video, ((const trtp_rtcp_report_fb_t*)rtpfb)->ssrc_media);
tsk_list_clear_items(video->avpf.packets);
video->avpf.count = 0;*/
} // if(last_item)
}// foreach(pkt)
tsk_list_unlock(video->avpf.packets);
@ -685,24 +685,24 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
static int _tdav_session_video_set_defaults(tdav_session_video_t* self)
{
if (!self) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
self->jb_enabled = tmedia_defaults_get_videojb_enabled();
self->zero_artifacts = tmedia_defaults_get_video_zeroartifacts_enabled();
self->avpf.max = tmedia_defaults_get_avpf_tail_min();
self->encoder.pkt_loss_level = tdav_session_video_pkt_loss_level_low;
self->encoder.pkt_loss_prob_bad = 0; // honor first report
self->encoder.pkt_loss_prob_good = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_GOOD;
self->encoder.last_frame_time = 0;
// reset rotation info (MUST for reINVITE when mobile device in portrait[90 degrees])
self->encoder.rotation = 0;
TSK_DEBUG_INFO("Video 'zero-artifacts' option = %s", self->zero_artifacts ? "yes" : "no");
return 0;
if (!self) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
self->jb_enabled = tmedia_defaults_get_videojb_enabled();
self->zero_artifacts = tmedia_defaults_get_video_zeroartifacts_enabled();
self->avpf.max = tmedia_defaults_get_avpf_tail_min();
self->encoder.pkt_loss_level = tdav_session_video_pkt_loss_level_low;
self->encoder.pkt_loss_prob_bad = 0; // honor first report
self->encoder.pkt_loss_prob_good = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_GOOD;
self->encoder.last_frame_time = 0;
// reset rotation info (MUST for reINVITE when mobile device in portrait[90 degrees])
self->encoder.rotation = 0;
TSK_DEBUG_INFO("Video 'zero-artifacts' option = %s", self->zero_artifacts ? "yes" : "no");
return 0;
}
// From jitter buffer to codec
@ -713,7 +713,7 @@ static int _tdav_session_video_jb_cb(const tdav_video_jb_cb_data_xt* data)
tmedia_session_t* session = (tmedia_session_t*)data->usr_data;
switch(data->type){
default: break;
default: break;
case tdav_video_jb_cb_data_type_rtp:
{
return _tdav_session_video_decode(video, data->rtp.pkt);
@ -741,7 +741,7 @@ static int _tdav_session_video_jb_cb(const tdav_video_jb_cb_data_xt* data)
}
}
}
break;
}
case tdav_video_jb_cb_data_type_fps_changed:
@ -823,7 +823,7 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
ret = tmedia_consumer_consume(base->consumer, (packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size, packet->header);
goto bail;
}
// Check if stream is corrupted or not
if(video->decoder.last_seqnum && (video->decoder.last_seqnum + 1) != packet->header->seq_num){
TSK_DEBUG_INFO("/!\\Video stream corrupted because of packet loss [%u - %u]. Pause rendering if 'zero_artifacts' (supported = %s, enabled = %s).",
@ -850,10 +850,10 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
// Decode data
out_size = self->decoder.codec->plugin->decode(
self->decoder.codec,
(packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size,
&self->decoder.buffer, &self->decoder.buffer_size,
packet->header
self->decoder.codec,
(packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size,
&self->decoder.buffer, &self->decoder.buffer_size,
packet->header
);
// check
if(!out_size || !self->decoder.buffer){
@ -889,21 +889,21 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
// Create video converter if not already done
if(!self->conv.fromYUV420 || CONSUMER_DISPLAY_N_CONVERTER_MISMATCH){
TSK_OBJECT_SAFE_FREE(self->conv.fromYUV420);
// create converter
if(!(self->conv.fromYUV420 = tmedia_converter_video_create(TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.chroma, base->consumer->video.display.width, base->consumer->video.display.height,
base->consumer->video.display.chroma))){
TSK_DEBUG_ERROR("Failed to create video converter");
ret = -3;
goto bail;
TSK_DEBUG_ERROR("Failed to create video converter");
ret = -3;
goto bail;
}
}
}
// update consumer size using the codec decoded values
// must be done here to avoid fooling "CONSUMER_IN_N_DISPLAY_MISMATCH" unless "auto_resize" option is enabled
base->consumer->video.in.width = TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width;//decoded width
base->consumer->video.in.height = TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height;//decoded height
base->consumer->video.in.width = TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width;//decoded width
base->consumer->video.in.height = TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height;//decoded height
if(self->conv.fromYUV420){
// update one-shot parameters
@ -926,7 +926,7 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
// congetion control
// send RTCP-REMB if:
// - congestion control is enabled and
// - congestion control is enabled and
// - fps changed or
// - first frame or
// - approximately every 5 minutes (300 = 60 * 5)
@ -935,12 +935,12 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
int32_t bandwidth_max_download_kbps = base->bandwidth_max_download_kbps;
// bandwidth already computed in start() but the decoded video size was not correct and based on the SDP negotiation
bandwidth_max_download_kbps = TSK_MIN(
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.fps),
bandwidth_max_download_kbps);
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.fps),
bandwidth_max_download_kbps);
if(self->encoder.codec){
bandwidth_max_upload_kbps = TSK_MIN(
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.width, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.height, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.fps),
bandwidth_max_upload_kbps);
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.width, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.height, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.fps),
bandwidth_max_upload_kbps);
}
self->fps_changed = tsk_false; // reset
TSK_DEBUG_INFO("video with congestion control enabled: max_bw_up=%d kpbs, max_bw_down=%d kpbs", bandwidth_max_upload_kbps, bandwidth_max_download_kbps);
@ -1045,7 +1045,7 @@ static int tdav_session_video_get(tmedia_session_t* self, tmedia_param_t* param)
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
// try with the base class to see if this option is supported or not
if (tdav_session_av_get(TDAV_SESSION_AV(self), param) == tsk_true) {
return 0;
@ -1068,7 +1068,7 @@ static int tdav_session_video_get(tmedia_session_t* self, tmedia_param_t* param)
static int tdav_session_video_prepare(tmedia_session_t* self)
{
tdav_session_av_t* base = (tdav_session_av_t*)(self);
tdav_session_video_t* video = (tdav_session_video_t*)self;
tdav_session_video_t* video = (tdav_session_video_t*)self;
int ret;
if((ret = tdav_session_av_prepare(base))){
@ -1112,6 +1112,7 @@ static int tdav_session_video_start(tmedia_session_t* self)
tsk_mutex_lock(video->encoder.h_mutex);
TSK_OBJECT_SAFE_FREE(video->encoder.codec);
video->encoder.codec = tsk_object_ref((tsk_object_t*)codec);
// initialize the encoder using user-defined values
if ((ret = tdav_session_av_init_encoder(base, video->encoder.codec))) {
TSK_DEBUG_ERROR("Failed to initialize the encoder [%s] codec", video->encoder.codec->plugin->desc);
@ -1157,7 +1158,7 @@ static int tdav_session_video_stop(tmedia_session_t* self)
video->started = tsk_false;
tsk_mutex_unlock(video->encoder.h_mutex);
// at this step we're sure that encode() will no longer be called which means we can safely close the codec
if (video->jb) {
ret = tdav_video_jb_stop(video->jb);
}
@ -1175,10 +1176,10 @@ static int tdav_session_video_stop(tmedia_session_t* self)
TSK_OBJECT_SAFE_FREE(video->encoder.codec);
tsk_mutex_unlock(video->encoder.h_mutex);
TSK_OBJECT_SAFE_FREE(video->decoder.codec);
// reset default values to make sure next start will be called with right defaults
// do not call this function in start to avoid overriding values defined between prepare() and start()
_tdav_session_video_set_defaults(video);
// reset default values to make sure next start will be called with right defaults
// do not call this function in start to avoid overriding values defined between prepare() and start()
_tdav_session_video_set_defaults(video);
return ret;
}
@ -1203,7 +1204,7 @@ static const tsdp_header_M_t* tdav_session_video_get_lo(tmedia_session_t* self)
// set callbacks
_tdav_session_video_set_callbacks(self);
}
return ret;
}
@ -1218,36 +1219,6 @@ static int tdav_session_video_set_ro(tmedia_session_t* self, const tsdp_header_M
return ret;
}
// Check if "RTCP-NACK" and "RTC-FIR" are supported
{
const tmedia_codec_t* codec;
base->is_fb_fir_neg = base->is_fb_nack_neg = base->is_fb_googremb_neg = tsk_false;
if ((codec = tdav_session_av_get_best_neg_codec(base))) {
// a=rtcp-fb:* ccm fir
// a=rtcp-fb:* nack
// a=rtcp-fb:* goog-remb
char attr_fir[256], attr_nack[256], attr_goog_remb[256];
int index = 0;
const tsdp_header_A_t* A;
sprintf(attr_fir, "%s ccm fir", codec->neg_format);
sprintf(attr_nack, "%s nack", codec->neg_format);
sprintf(attr_goog_remb, "%s goog-remb", codec->neg_format);
while ((A = tsdp_header_M_findA_at(m, "rtcp-fb", index++))) {
if (!base->is_fb_fir_neg) {
base->is_fb_fir_neg = (tsk_striequals(A->value, "* ccm fir") || tsk_striequals(A->value, attr_fir));
}
if (!base->is_fb_nack_neg) {
base->is_fb_nack_neg = (tsk_striequals(A->value, "* nack") || tsk_striequals(A->value, attr_nack));
}
if (!base->is_fb_googremb_neg) {
base->is_fb_googremb_neg = (tsk_striequals(A->value, "* goog-remb") || tsk_striequals(A->value, attr_goog_remb));
}
}
}
}
if (updated) {
// set callbacks
ret = _tdav_session_video_set_callbacks(self);
@ -1372,9 +1343,9 @@ static int _tdav_session_video_init(tdav_session_video_t *p_self, tmedia_type_t
TSK_DEBUG_ERROR("tdav_session_av_init(video) failed");
return ret;
}
/* init() self */
_tdav_session_video_set_defaults(p_self);
_tdav_session_video_set_defaults(p_self);
if (!p_self->encoder.h_mutex && !(p_self->encoder.h_mutex = tsk_mutex_create())) {
TSK_DEBUG_ERROR("Failed to create encode mutex");
return -4;
@ -1461,17 +1432,17 @@ static const tsk_object_def_t tdav_session_video_def_s =
static const tmedia_session_plugin_def_t tdav_session_video_plugin_def_s =
{
&tdav_session_video_def_s,
tmedia_video,
"video",
tdav_session_video_set,
tdav_session_video_get,
tdav_session_video_prepare,
tdav_session_video_start,
tdav_session_video_pause,
tdav_session_video_stop,
/* Audio part */
{ tsk_null },
@ -1484,8 +1455,8 @@ static const tmedia_session_plugin_def_t tdav_session_video_plugin_def_s =
/* Rtcp */
{
tdav_session_video_rtcp_set_onevent_cbfn,
tdav_session_video_rtcp_send_event,
tdav_session_video_rtcp_recv_event
tdav_session_video_rtcp_send_event,
tdav_session_video_rtcp_recv_event
}
};
const tmedia_session_plugin_def_t *tdav_session_video_plugin_def_t = &tdav_session_video_plugin_def_s;
@ -1515,17 +1486,17 @@ static const tsk_object_def_t tdav_session_bfcpvideo_def_s =
static const tmedia_session_plugin_def_t tdav_session_bfcpvideo_plugin_def_s =
{
&tdav_session_bfcpvideo_def_s,
tmedia_bfcp_video,
"video",
tdav_session_video_set,
tdav_session_video_get,
tdav_session_video_prepare,
tdav_session_video_start,
tdav_session_video_pause,
tdav_session_video_stop,
/* Audio part */
{ tsk_null },
@ -1538,8 +1509,8 @@ static const tmedia_session_plugin_def_t tdav_session_bfcpvideo_plugin_def_s =
/* Rtcp */
{
tdav_session_video_rtcp_set_onevent_cbfn,
tdav_session_video_rtcp_send_event,
tdav_session_video_rtcp_recv_event
tdav_session_video_rtcp_send_event,
tdav_session_video_rtcp_recv_event
}
};
const tmedia_session_plugin_def_t *tdav_session_bfcpvideo_plugin_def_t = &tdav_session_bfcpvideo_plugin_def_s;

View File

@ -54,6 +54,7 @@ typedef struct tsip_dialog_invite
tsk_bool_t is_cancelling; // whether we're cancelling the outgoing INVITE
uint32_t rseq;
uint32_t cseq_out_media_update; // CSeq for the last media update request (INVITE or UPDATE).
uint64_t last_out_fastupdate_time;
tsip_timer_t timershutdown;
tsip_timer_t timer100rel;

View File

@ -53,6 +53,12 @@
#include "tsk_debug.h"
#if METROPOLIS
# define TSIP_INFO_FASTUPDATE_OUT_INTERVAL_MIN 0 // millis
#else
# define TSIP_INFO_FASTUPDATE_OUT_INTERVAL_MIN 1500 // millis
#endif
#if HAVE_LIBXML2
#include <libxml/tree.h>
#include <libxml/parser.h>
@ -1799,22 +1805,30 @@ static int tsip_dialog_invite_msession_rfc5168_cb(const void* usrdata, const str
if (self) {
if (command == tmedia_session_rfc5168_cmd_picture_fast_update) {
char* content_ptr = tsk_null;
static const char* __content_type = "application/media_control+xml";
static const void* __content_format =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
" <media_control>\r\n"
" <vc_primitive>\r\n"
" <to_encoder>\r\n"
" <picture_fast_update>\r\n"
" </picture_fast_update>\r\n"
" </to_encoder>\r\n"
" <stream_id>%llu</stream_id>\r\n"
" </vc_primitive>\r\n"
" </media_control>\r\n";
TSK_DEBUG_INFO("Media session is asking the sigaling layer to send SIP INFO('picture_fast_update')");
tsk_sprintf(&content_ptr, __content_format, session->id);
return send_INFO(self, __content_type, content_ptr, tsk_strlen(content_ptr));
uint64_t now = tsk_time_now();
if ((now - self->last_out_fastupdate_time) > TSIP_INFO_FASTUPDATE_OUT_INTERVAL_MIN) {
char* content_ptr = tsk_null;
static const char* __content_type = "application/media_control+xml";
static const void* __content_format =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
" <media_control>\r\n"
" <vc_primitive>\r\n"
" <to_encoder>\r\n"
" <picture_fast_update>\r\n"
" </picture_fast_update>\r\n"
" </to_encoder>\r\n"
" <stream_id>%llu</stream_id>\r\n"
" </vc_primitive>\r\n"
" </media_control>\r\n";
TSK_DEBUG_INFO("Media session is asking the sigaling layer to send SIP INFO('picture_fast_update')");
tsk_sprintf(&content_ptr, __content_format, session->id);
self->last_out_fastupdate_time = now;
return send_INFO(self, __content_type, content_ptr, tsk_strlen(content_ptr));
}
else {
/* if too close don't update "last_fir_time" to "now" to be sure interval will increase */
TSK_DEBUG_INFO("Outgoing SIP INFO ('picture_fast_update') requested but delay too close");
}
}
}
return 0;