Add callbacks for send channel rtcp statistics
BUG=2235
R=mflodman@webrtc.org, pbos@webrtc.org, stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/4429004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5220 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index a45cf06..28099df 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -240,14 +240,12 @@
: fraction_lost(0),
cumulative_lost(0),
extended_max_sequence_number(0),
- jitter(0),
- max_jitter(0) {}
+ jitter(0) {}
uint8_t fraction_lost;
uint32_t cumulative_lost;
uint32_t extended_max_sequence_number;
uint32_t jitter;
- uint32_t max_jitter;
};
// Callback, called whenever a new rtcp report block is transmitted.
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index 9fb8199..51471ba 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -590,6 +590,12 @@
// Returns true if the module is configured to store packets.
virtual bool StorePackets() const = 0;
+ // Called on receipt of RTCP report block from remote side.
+ virtual void RegisterSendChannelRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback) = 0;
+ virtual RtcpStatisticsCallback*
+ GetSendChannelRtcpStatisticsCallback() = 0;
+
/**************************************************************************
*
* Audio
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 93230da..9ca4897 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -201,6 +201,10 @@
MOCK_METHOD2(SetStorePacketsStatus,
int32_t(const bool enable, const uint16_t numberToStore));
MOCK_CONST_METHOD0(StorePackets, bool());
+ MOCK_METHOD1(RegisterSendChannelRtcpStatisticsCallback,
+ void(RtcpStatisticsCallback*));
+ MOCK_METHOD0(GetSendChannelRtcpStatisticsCallback,
+ RtcpStatisticsCallback*());
MOCK_METHOD1(RegisterAudioCallback,
int32_t(RtpAudioFeedback* messagesCallback));
MOCK_METHOD1(SetAudioPacketSize,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
index fb7adf6..a95fdde 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -54,7 +54,8 @@
_receivedInfoMap(),
_packetTimeOutMS(0),
_lastReceivedRrMs(0),
- _lastIncreasedSequenceNumberMs(0) {
+ _lastIncreasedSequenceNumberMs(0),
+ stats_callback_(NULL) {
memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
}
@@ -1359,6 +1360,19 @@
return 0;
}
+void RTCPReceiver::RegisterRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback) {
+ CriticalSectionScoped cs(_criticalSectionFeedbacks);
+ if (callback != NULL)
+ assert(stats_callback_ == NULL);
+ stats_callback_ = callback;
+}
+
+RtcpStatisticsCallback* RTCPReceiver::GetRtcpStatisticsCallback() {
+ CriticalSectionScoped cs(_criticalSectionFeedbacks);
+ return stats_callback_;
+}
+
// Holding no Critical section
void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
RTCPPacketInformation& rtcpPacketInformation) {
@@ -1453,6 +1467,24 @@
}
}
}
+
+ {
+ CriticalSectionScoped cs(_criticalSectionFeedbacks);
+ if (stats_callback_) {
+ for (ReportBlockList::const_iterator it =
+ rtcpPacketInformation.report_blocks.begin();
+ it != rtcpPacketInformation.report_blocks.end();
+ ++it) {
+ RtcpStatistics stats;
+ stats.cumulative_lost = it->cumulativeLost;
+ stats.extended_max_sequence_number = it->extendedHighSeqNum;
+ stats.fraction_lost = it->fractionLost;
+ stats.jitter = it->jitter;
+
+ stats_callback_->StatisticsUpdated(stats, local_ssrc);
+ }
+ }
+ }
}
int32_t RTCPReceiver::CNAME(const uint32_t remoteSSRC,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
index 5c6f732..637773d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -109,6 +109,9 @@
int32_t UpdateTMMBR();
+ void RegisterRtcpStatisticsCallback(RtcpStatisticsCallback* callback);
+ RtcpStatisticsCallback* GetRtcpStatisticsCallback();
+
protected:
RTCPHelp::RTCPReportBlockInformation* CreateReportBlockInformation(const uint32_t remoteSSRC);
RTCPHelp::RTCPReportBlockInformation* GetReportBlockInformation(const uint32_t remoteSSRC) const;
@@ -262,6 +265,7 @@
// delivered RTP packet to the remote side.
int64_t _lastIncreasedSequenceNumberMs;
+ RtcpStatisticsCallback* stats_callback_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index 25670f5..47befea 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -35,16 +35,18 @@
struct ReportBlock {
ReportBlock(uint32_t ssrc, uint32_t extended_max, uint8_t fraction_loss,
- uint32_t cumulative_loss)
+ uint32_t cumulative_loss, uint32_t jitter)
: ssrc(ssrc),
extended_max(extended_max),
fraction_loss(fraction_loss),
- cumulative_loss(cumulative_loss) {}
+ cumulative_loss(cumulative_loss),
+ jitter(jitter) {}
uint32_t ssrc;
uint32_t extended_max;
uint8_t fraction_loss;
uint32_t cumulative_loss;
+ uint32_t jitter;
};
PacketBuilder()
@@ -108,9 +110,9 @@
void AddRrPacket(uint32_t sender_ssrc, uint32_t rtp_ssrc,
uint32_t extended_max, uint8_t fraction_loss,
- uint32_t cumulative_loss) {
+ uint32_t cumulative_loss, uint32_t jitter) {
ReportBlock report_block(rtp_ssrc, extended_max, fraction_loss,
- cumulative_loss);
+ cumulative_loss, jitter);
std::list<ReportBlock> report_block_vector(&report_block,
&report_block + 1);
AddRrPacketMultipleReportBlocks(sender_ssrc, report_block_vector);
@@ -123,16 +125,17 @@
for (std::list<ReportBlock>::const_iterator it = report_blocks.begin();
it != report_blocks.end(); ++it) {
AddReportBlock(it->ssrc, it->extended_max, it->fraction_loss,
- it->cumulative_loss);
+ it->cumulative_loss, it->jitter);
}
}
void AddReportBlock(uint32_t rtp_ssrc, uint32_t extended_max,
- uint8_t fraction_loss, uint32_t cumulative_loss) {
+ uint8_t fraction_loss, uint32_t cumulative_loss,
+ uint32_t jitter) {
Add32(rtp_ssrc);
Add32((fraction_loss << 24) + cumulative_loss);
Add32(extended_max);
- Add32(0); // Jitter.
+ Add32(jitter);
Add32(0); // Last SR.
Add32(0); // Delay since last SR.
}
@@ -283,8 +286,9 @@
true); // Allow non-compound RTCP
RTCPHelp::RTCPPacketInformation rtcpPacketInformation;
- int result = rtcp_receiver_->IncomingRTCPPacket(rtcpPacketInformation,
- &rtcpParser);
+ EXPECT_EQ(0, rtcp_receiver_->IncomingRTCPPacket(rtcpPacketInformation,
+ &rtcpParser));
+ rtcp_receiver_->TriggerCallbacksFromRTCPPacket(rtcpPacketInformation);
// The NACK list is on purpose not copied below as it isn't needed by the
// test.
rtcp_packet_info_.rtcpPacketTypeFlags =
@@ -308,7 +312,7 @@
if (rtcpPacketInformation.VoIPMetric) {
rtcp_packet_info_.AddVoIPMetric(rtcpPacketInformation.VoIPMetric);
}
- return result;
+ return 0;
}
OverUseDetectorOptions over_use_detector_options_;
@@ -543,7 +547,7 @@
// Add a RR and advance the clock just enough to not trigger a timeout.
PacketBuilder p1;
- p1.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0);
+ p1.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0);
EXPECT_EQ(0, InjectRtcpPacket(p1.packet(), p1.length()));
system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs - 1);
EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs));
@@ -552,7 +556,7 @@
// Add a RR with the same extended max as the previous RR to trigger a
// sequence number timeout, but not a RR timeout.
PacketBuilder p2;
- p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0);
+ p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0);
EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length()));
system_clock_.AdvanceTimeMilliseconds(2);
EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs));
@@ -570,7 +574,7 @@
// Add a new RR with increase sequence number to reset timers.
PacketBuilder p3;
sequence_number++;
- p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0);
+ p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0);
EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length()));
EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs));
EXPECT_FALSE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs));
@@ -578,7 +582,7 @@
// Verify we can get a timeout again once we've received new RR.
system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs);
PacketBuilder p4;
- p4.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0);
+ p4.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0);
EXPECT_EQ(0, InjectRtcpPacket(p4.packet(), p4.length()));
system_clock_.AdvanceTimeMilliseconds(kRtcpIntervalMs + 1);
EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs));
@@ -604,9 +608,9 @@
PacketBuilder packet;
std::list<PacketBuilder::ReportBlock> report_blocks;
report_blocks.push_back(PacketBuilder::ReportBlock(
- kSourceSsrcs[0], sequence_numbers[0], 10, 5));
+ kSourceSsrcs[0], sequence_numbers[0], 10, 5, 0));
report_blocks.push_back(PacketBuilder::ReportBlock(
- kSourceSsrcs[1], sequence_numbers[1], 0, 0));
+ kSourceSsrcs[1], sequence_numbers[1], 0, 0, 0));
packet.AddRrPacketMultipleReportBlocks(kSenderSsrc, report_blocks);
EXPECT_EQ(0, InjectRtcpPacket(packet.packet(), packet.length()));
ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size());
@@ -616,9 +620,9 @@
PacketBuilder packet2;
report_blocks.clear();
report_blocks.push_back(PacketBuilder::ReportBlock(
- kSourceSsrcs[0], sequence_numbers[0], 0, 0));
+ kSourceSsrcs[0], sequence_numbers[0], 0, 0, 0));
report_blocks.push_back(PacketBuilder::ReportBlock(
- kSourceSsrcs[1], sequence_numbers[1], 20, 10));
+ kSourceSsrcs[1], sequence_numbers[1], 20, 10, 0));
packet2.AddRrPacketMultipleReportBlocks(kSenderSsrc, report_blocks);
EXPECT_EQ(0, InjectRtcpPacket(packet2.packet(), packet2.length()));
ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size());
@@ -736,6 +740,61 @@
EXPECT_EQ(kMediaRecipientSsrc + 2, candidate_set.Ssrc(0));
}
+TEST_F(RtcpReceiverTest, Callbacks) {
+ class RtcpCallbackImpl : public RtcpStatisticsCallback {
+ public:
+ RtcpCallbackImpl() : RtcpStatisticsCallback(), ssrc_(0) {}
+ virtual ~RtcpCallbackImpl() {}
+
+ virtual void StatisticsUpdated(const RtcpStatistics& statistics,
+ uint32_t ssrc) {
+ stats_ = statistics;
+ ssrc_ = ssrc;
+ }
+
+ bool Matches(uint32_t ssrc, uint32_t extended_max, uint8_t fraction_loss,
+ uint32_t cumulative_loss, uint32_t jitter) {
+ return ssrc_ == ssrc &&
+ stats_.fraction_lost == fraction_loss &&
+ stats_.cumulative_lost == cumulative_loss &&
+ stats_.extended_max_sequence_number == extended_max &&
+ stats_.jitter == jitter;
+ }
+
+ RtcpStatistics stats_;
+ uint32_t ssrc_;
+ } callback;
+
+ rtcp_receiver_->RegisterRtcpStatisticsCallback(&callback);
+
+ const uint32_t kSenderSsrc = 0x10203;
+ const uint32_t kSourceSsrc = 0x123456;
+ const uint8_t fraction_loss = 3;
+ const uint32_t cumulative_loss = 7;
+ const uint32_t jitter = 9;
+ uint32_t sequence_number = 1234;
+
+ std::set<uint32_t> ssrcs;
+ ssrcs.insert(kSourceSsrc);
+ rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+
+ // First packet, all numbers should just propagate
+ PacketBuilder p1;
+ p1.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number,
+ fraction_loss, cumulative_loss, jitter);
+ EXPECT_EQ(0, InjectRtcpPacket(p1.packet(), p1.length()));
+ EXPECT_TRUE(callback.Matches(kSourceSsrc, sequence_number, fraction_loss,
+ cumulative_loss, jitter));
+
+ rtcp_receiver_->RegisterRtcpStatisticsCallback(NULL);
+
+ // Add arbitrary numbers, callback should not be called (retain old values)
+ PacketBuilder p2;
+ p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number + 1, 42, 137, 4711);
+ EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length()));
+ EXPECT_TRUE(callback.Matches(kSourceSsrc, sequence_number, fraction_loss,
+ cumulative_loss, jitter));
+}
} // Anonymous namespace
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 027d17d..4af8cde 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -1189,6 +1189,16 @@
return rtp_sender_.StorePackets();
}
+void ModuleRtpRtcpImpl::RegisterSendChannelRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback) {
+ rtcp_receiver_.RegisterRtcpStatisticsCallback(callback);
+}
+
+RtcpStatisticsCallback* ModuleRtpRtcpImpl::
+ GetSendChannelRtcpStatisticsCallback() {
+ return rtcp_receiver_.GetRtcpStatisticsCallback();
+}
+
// Send a TelephoneEvent tone using RFC 2833 (4733).
int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband(
const uint8_t key,
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index c8ab063..0dd2549 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -246,6 +246,12 @@
virtual bool StorePackets() const OVERRIDE;
+ // Called on receipt of RTCP report block from remote side.
+ virtual void RegisterSendChannelRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback) OVERRIDE;
+ virtual RtcpStatisticsCallback*
+ GetSendChannelRtcpStatisticsCallback() OVERRIDE;
+
// (APP) Application specific data.
virtual int32_t SetRTCPApplicationSpecificData(
const uint8_t sub_type,
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 59c628e..0c595fc 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -357,6 +357,7 @@
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
rtp_rtcp->RegisterSendFrameCountObserver(NULL);
+ rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
@@ -413,6 +414,8 @@
rtp_rtcp->SetRtcpXrRrtrStatus(rtp_rtcp_->RtcpXrRrtrStatus());
rtp_rtcp->RegisterSendFrameCountObserver(
rtp_rtcp_->GetSendFrameCountObserver());
+ rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(
+ rtp_rtcp_->GetSendChannelRtcpStatisticsCallback());
}
// |RegisterSimulcastRtpRtcpModules| resets all old weak pointers and old
// modules can be deleted after this step.
@@ -424,6 +427,7 @@
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
rtp_rtcp->RegisterSendFrameCountObserver(NULL);
+ rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
@@ -1264,6 +1268,19 @@
return 0;
}
+void ViEChannel::RegisterSendChannelRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback) {
+ WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
+ __FUNCTION__);
+ rtp_rtcp_->RegisterSendChannelRtcpStatisticsCallback(callback);
+ CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+ for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
+ it != simulcast_rtp_rtcp_.end();
+ ++it) {
+ (*it)->RegisterSendChannelRtcpStatisticsCallback(callback);
+ }
+}
+
// TODO(holmer): This is a bad function name as it implies that it returns the
// received RTCP, while it actually returns the statistics which will be sent
// in the RTCP.
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index a16a65d..a17bb2b 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -174,6 +174,10 @@
uint32_t* jitter_samples,
int32_t* rtt_ms);
+ // Called on receipt of RTCP report block from remote side.
+ void RegisterSendChannelRtcpStatisticsCallback(
+ RtcpStatisticsCallback* callback);
+
// Returns our localy created statistics of the received RTP stream.
int32_t GetReceivedRtcpStatistics(uint16_t* fraction_lost,
uint32_t* cumulative_lost,
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index edad270..9822b9d 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -1119,15 +1119,39 @@
}
int ViERTP_RTCPImpl::RegisterSendChannelRtcpStatisticsCallback(
- int channel, RtcpStatisticsCallback* callback) {
- // TODO(sprang): Implement
- return -1;
+ int video_channel, RtcpStatisticsCallback* callback) {
+ WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s(channel: %d)", __FUNCTION__, video_channel);
+ ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+ ViEChannel* vie_channel = cs.Channel(video_channel);
+ if (!vie_channel) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+ shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+ return -1;
+ }
+ vie_channel->RegisterSendChannelRtcpStatisticsCallback(callback);
+ return 0;
}
int ViERTP_RTCPImpl::DeregisterSendChannelRtcpStatisticsCallback(
- int channel, RtcpStatisticsCallback* callback) {
- // TODO(sprang): Implement
- return -1;
+ int video_channel, RtcpStatisticsCallback* callback) {
+ WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s(channel: %d)", __FUNCTION__, video_channel);
+ ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+ ViEChannel* vie_channel = cs.Channel(video_channel);
+ if (!vie_channel) {
+ WEBRTC_TRACE(kTraceError, kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+ shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+ return -1;
+ }
+ vie_channel->RegisterSendChannelRtcpStatisticsCallback(NULL);
+ return 0;
}
int ViERTP_RTCPImpl::RegisterReceiveChannelRtcpStatisticsCallback(