diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 104adc339284..407696bc16f4 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1565,13 +1565,17 @@ PeerConnectionWrapper.prototype = { for (var key in stats) { if (stats.hasOwnProperty(key)) { var res = stats[key]; - counters[res.type] = toNum(counters[res.type]) + 1; + if (!res.isRemote) { + counters[res.type] = toNum(counters[res.type]) + 1; + } } } // Use MapClass way of enumerating stats var counters2 = {}; stats.forEach(function(res) { - counters2[res.type] = toNum(counters2[res.type]) + 1; + if (!res.isRemote) { + counters2[res.type] = toNum(counters2[res.type]) + 1; + } }); is(JSON.stringify(counters), JSON.stringify(counters2), "Spec and MapClass variant of RTCStatsReport enumeration agree"); diff --git a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp index a10c05eeddd4..b8ceb3bc9133 100644 --- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp @@ -23,6 +23,7 @@ #endif #include "webrtc/voice_engine/include/voe_errors.h" +#include "webrtc/system_wrappers/interface/clock.h" #ifdef MOZ_WIDGET_ANDROID #include "AndroidJNIWrapper.h" @@ -145,13 +146,63 @@ bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) { return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc); } -bool WebrtcAudioConduit::GetReceivedJitter(unsigned int* jitterMs) { +bool WebrtcAudioConduit::GetRTPJitter(unsigned int* jitterMs) { unsigned int maxJitterMs; unsigned int discardedPackets; return !mPtrRTP->GetRTPStatistics(mChannel, *jitterMs, maxJitterMs, discardedPackets); } +DOMHighResTimeStamp +NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow) { + return (uint32_t(ntpHigh - webrtc::kNtpJan1970) + + double(ntpLow) / webrtc::kMagicNtpFractionalUnit) * 1000; +} + +bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, + unsigned int* jitterMs, + unsigned int* packetsReceived, + uint64_t* bytesReceived) { + unsigned int ntpHigh, ntpLow; + unsigned int rtpTimestamp, playoutTimestamp; + unsigned int packetsSent; + unsigned int bytesSent32; + unsigned short fractionLost; + unsigned int cumulativeLost; + bool result = !mPtrRTP->GetRemoteRTCPData(mChannel, ntpHigh, ntpLow, + rtpTimestamp, playoutTimestamp, + packetsSent, bytesSent32, + jitterMs, + &fractionLost, &cumulativeLost); + if (result) { + *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow); + *packetsReceived = (packetsSent >= cumulativeLost) ? + (packetsSent - cumulativeLost) : 0; + *bytesReceived = (packetsSent ? + (bytesSent32 / packetsSent) : 0) * (*packetsReceived); + } + return result; +} + +bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, + unsigned int* packetsSent, + uint64_t* bytesSent) { + unsigned int ntpHigh, ntpLow; + unsigned int rtpTimestamp, playoutTimestamp; + unsigned int bytesSent32; + unsigned int jitterMs; + unsigned short fractionLost; + bool result = !mPtrRTP->GetRemoteRTCPData(mChannel, ntpHigh, ntpLow, + rtpTimestamp, playoutTimestamp, + *packetsSent, bytesSent32, + &jitterMs, &fractionLost); + if (result) { + *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow); + *bytesSent = bytesSent32; + } + return result; +} + /* * WebRTCAudioConduit Implementation */ diff --git a/media/webrtc/signaling/src/media-conduit/AudioConduit.h b/media/webrtc/signaling/src/media-conduit/AudioConduit.h index a5a192a914f4..eab3fb17d0b5 100755 --- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h +++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h @@ -38,6 +38,11 @@ namespace mozilla { +// Helper function + +DOMHighResTimeStamp +NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow); + /** * Concrete class for Audio session. Hooks up * - media-source and target to external transport @@ -172,7 +177,14 @@ public: webrtc::VoiceEngine* GetVoiceEngine() { return mVoiceEngine; } bool GetLocalSSRC(unsigned int* ssrc); bool GetRemoteSSRC(unsigned int* ssrc); - bool GetReceivedJitter(unsigned int* jitterMs); + bool GetRTPJitter(unsigned int* jitterMs); + bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, + unsigned int* jitterMs, + unsigned int* packetsReceived, + uint64_t* bytesReceived); + bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, + unsigned int* packetsSent, + uint64_t* bytesSent); private: WebrtcAudioConduit(const WebrtcAudioConduit& other) MOZ_DELETE; diff --git a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h index 304f33e4eea8..41bc9aac7a40 100755 --- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h +++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h @@ -7,6 +7,7 @@ #include "nsISupportsImpl.h" #include "nsXPCOM.h" +#include "nsDOMNavigationTiming.h" #include "mozilla/RefPtr.h" #include "CodecConfig.h" #include "VideoTypes.h" @@ -138,7 +139,18 @@ public: virtual bool GetLocalSSRC(unsigned int* ssrc) = 0; virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0; - virtual bool GetReceivedJitter(unsigned int* jitterMs) = 0; + + /** + * Functions returning stats needed by w3c stats model. + */ + virtual bool GetRTPJitter(unsigned int* jitterMs) = 0; + virtual bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, + unsigned int* jitterMs, + unsigned int* packetsReceived, + uint64_t* bytesReceived) = 0; + virtual bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, + unsigned int* packetsSent, + uint64_t* bytesSent) = 0; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSessionConduit) diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp index 664b41a9c3d9..cdf24d63aa4c 100644 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp @@ -145,12 +145,16 @@ bool WebrtcVideoConduit::GetRemoteSSRC(unsigned int* ssrc) { return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc); } -bool WebrtcVideoConduit::GetReceivedJitter(unsigned int* jitterMs) { +bool WebrtcVideoConduit::GetRTPJitter(unsigned int* jitterMs) { + unsigned int ntpHigh, ntpLow; + unsigned int packetsSent, bytesSent; unsigned short fractionLost; unsigned int cumulativeLost; unsigned extendedMax; int rttMs; - return !mPtrRTP->GetReceivedRTCPStatistics(mChannel, + // GetReceivedRTCPStatistics is a poorly named GetRTPStatistics variant + return !mPtrRTP->GetReceivedRTCPStatistics(mChannel, ntpHigh, ntpLow, + packetsSent, bytesSent, fractionLost, cumulativeLost, extendedMax, @@ -158,6 +162,57 @@ bool WebrtcVideoConduit::GetReceivedJitter(unsigned int* jitterMs) { rttMs); } +bool WebrtcVideoConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, + unsigned int* jitterMs, + unsigned int* packetsReceived, + uint64_t* bytesReceived) { + unsigned int ntpHigh, ntpLow; + unsigned int packetsSent; + unsigned int bytesSent32; + unsigned short fractionLost; + unsigned int cumulativeLost; + unsigned extendedMax; + int rttMs; + bool result = !mPtrRTP->GetSentRTCPStatistics(mChannel, ntpHigh, ntpLow, + bytesSent32, packetsSent, + fractionLost, + cumulativeLost, + extendedMax, + *jitterMs, + rttMs); + if (result) { + *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow); + *packetsReceived = (packetsSent >= cumulativeLost) ? + (packetsSent - cumulativeLost) : 0; + *bytesReceived = (packetsSent ? + (bytesSent32 / packetsSent) : 0) * (*packetsReceived); + } + return result; +} + +bool WebrtcVideoConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, + unsigned int* packetsSent, + uint64_t* bytesSent) { + unsigned int ntpHigh, ntpLow; + unsigned int bytesSent32; + unsigned int jitterMs; + unsigned short fractionLost; + unsigned int cumulativeLost; + unsigned extendedMax; + int rttMs; + bool result = !mPtrRTP->GetReceivedRTCPStatistics(mChannel, ntpHigh, ntpLow, + bytesSent32, *packetsSent, + fractionLost, + cumulativeLost, + jitterMs, extendedMax, + rttMs); + if (result) { + *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow); + *bytesSent = bytesSent32; + } + return result; +} + /** * Peforms intialization of the MANDATORY components of the Video Engine */ diff --git a/media/webrtc/signaling/src/media-conduit/VideoConduit.h b/media/webrtc/signaling/src/media-conduit/VideoConduit.h index 42bcb7132f68..1ab2fc858748 100755 --- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h +++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h @@ -210,7 +210,14 @@ public: webrtc::VideoEngine* GetVideoEngine() { return mVideoEngine; } bool GetLocalSSRC(unsigned int* ssrc); bool GetRemoteSSRC(unsigned int* ssrc); - bool GetReceivedJitter(unsigned int* jitterMs); + bool GetRTPJitter(unsigned int* jitterMs); + bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp, + unsigned int* jitterMs, + unsigned int* packetsReceived, + uint64_t* bytesReceived); + bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp, + unsigned int* packetsSent, + uint64_t* bytesSent); private: diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 6b813047b6cc..61665fa70d78 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -1325,7 +1325,7 @@ PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector, bool internalStats) { } else { CSFLogError(logTag, "Failed to get NrIceMediaStream for level %u " "in %s: %s", - level, __FUNCTION__, mHandle.c_str()); + uint32_t(level), __FUNCTION__, mHandle.c_str()); MOZ_CRASH(); } } @@ -1978,36 +1978,103 @@ PeerConnectionImpl::GetStatsImpl_s( switch (mp.direction()) { case MediaPipeline::TRANSMIT: { - RTCOutboundRTPStreamStats s; - s.mTimestamp.Construct(now); - s.mId.Construct(NS_LITERAL_STRING("outbound_rtp_") + idstr); - s.mType.Construct(RTCStatsType::Outboundrtp); - unsigned int ssrc; - if (mp.Conduit()->GetLocalSSRC(&ssrc)) { - nsString str; - str.AppendInt(ssrc); - s.mSsrc.Construct(str); + nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr; + nsString remoteId; + nsString ssrc; + unsigned int ssrcval; + if (mp.Conduit()->GetLocalSSRC(&ssrcval)) { + ssrc.AppendInt(ssrcval); + } + { + // First, fill in remote stat with rtcp receiver data, if present. + // ReceiverReports have less information than SenderReports, + // so fill in what we can. + DOMHighResTimeStamp timestamp; + uint32_t jitterMs; + uint32_t packetsReceived; + uint64_t bytesReceived; + if (mp.Conduit()->GetRTCPReceiverReport(×tamp, &jitterMs, + &packetsReceived, + &bytesReceived)) { + remoteId = NS_LITERAL_STRING("outbound_rtcp_") + idstr; + RTCInboundRTPStreamStats s; + s.mTimestamp.Construct(timestamp); + s.mId.Construct(remoteId); + s.mType.Construct(RTCStatsType::Inboundrtp); + if (ssrc.Length()) { + s.mSsrc.Construct(ssrc); + } + s.mJitter.Construct(double(jitterMs)/1000); + s.mRemoteId.Construct(localId); + s.mIsRemote = true; + s.mPacketsReceived.Construct(packetsReceived); + s.mBytesReceived.Construct(bytesReceived); + report->mInboundRTPStreamStats.Value().AppendElement(s); + } + } + // Then, fill in local side (with cross-link to remote only if present) + { + RTCOutboundRTPStreamStats s; + s.mTimestamp.Construct(now); + s.mId.Construct(localId); + s.mType.Construct(RTCStatsType::Outboundrtp); + if (ssrc.Length()) { + s.mSsrc.Construct(ssrc); + } + s.mRemoteId.Construct(remoteId); + s.mIsRemote = false; + s.mPacketsSent.Construct(mp.rtp_packets_sent()); + s.mBytesSent.Construct(mp.rtp_bytes_sent()); + report->mOutboundRTPStreamStats.Value().AppendElement(s); } - s.mPacketsSent.Construct(mp.rtp_packets_sent()); - s.mBytesSent.Construct(mp.rtp_bytes_sent()); - report->mOutboundRTPStreamStats.Value().AppendElement(s); break; } case MediaPipeline::RECEIVE: { + nsString localId = NS_LITERAL_STRING("inbound_rtp_") + idstr; + nsString remoteId; + nsString ssrc; + unsigned int ssrcval; + if (mp.Conduit()->GetRemoteSSRC(&ssrcval)) { + ssrc.AppendInt(ssrcval); + } + { + // First, fill in remote stat with rtcp sender data, if present. + DOMHighResTimeStamp timestamp; + uint32_t packetsSent; + uint64_t bytesSent; + if (mp.Conduit()->GetRTCPSenderReport(×tamp, + &packetsSent, &bytesSent)) { + remoteId = NS_LITERAL_STRING("inbound_rtcp_") + idstr; + RTCOutboundRTPStreamStats s; + s.mTimestamp.Construct(timestamp); + s.mId.Construct(remoteId); + s.mType.Construct(RTCStatsType::Outboundrtp); + if (ssrc.Length()) { + s.mSsrc.Construct(ssrc); + } + s.mRemoteId.Construct(localId); + s.mIsRemote = true; + s.mPacketsSent.Construct(packetsSent); + s.mBytesSent.Construct(bytesSent); + report->mOutboundRTPStreamStats.Value().AppendElement(s); + } + } + // Then, fill in local side (with cross-link to remote only if present) RTCInboundRTPStreamStats s; s.mTimestamp.Construct(now); - s.mId.Construct(NS_LITERAL_STRING("inbound_rtp_") + idstr); + s.mId.Construct(localId); s.mType.Construct(RTCStatsType::Inboundrtp); - unsigned int ssrc; - if (mp.Conduit()->GetRemoteSSRC(&ssrc)) { - nsString str; - str.AppendInt(ssrc); - s.mSsrc.Construct(str); + if (ssrc.Length()) { + s.mSsrc.Construct(ssrc); } unsigned int jitterMs; - if (mp.Conduit()->GetReceivedJitter(&jitterMs)) { + if (mp.Conduit()->GetRTPJitter(&jitterMs)) { s.mJitter.Construct(double(jitterMs)/1000); } + if (remoteId.Length()) { + s.mRemoteId.Construct(remoteId); + } + s.mIsRemote = false; s.mPacketsReceived.Construct(mp.rtp_packets_received()); s.mBytesReceived.Construct(mp.rtp_bytes_received()); report->mInboundRTPStreamStats.Value().AppendElement(s); diff --git a/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h b/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h index 135f7f834a85..c28a804b85ee 100644 --- a/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -264,6 +264,10 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { // stream. virtual int GetReceivedRTCPStatistics( const int video_channel, + unsigned int& ntpHigh, + unsigned int& ntpLow, + unsigned int& bytes_sent, + unsigned int& packets_sent, unsigned short& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, @@ -273,6 +277,10 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { // This function returns statistics reported by the remote client in a RTCP // packet. virtual int GetSentRTCPStatistics(const int video_channel, + unsigned int& ntpHigh, + unsigned int& ntpLow, + unsigned int& bytes_sent, + unsigned int& packets_sent, unsigned short& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc b/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc index 1a6bd58a6023..0574eda004b9 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc @@ -1177,7 +1177,11 @@ int32_t ViEChannel::SendApplicationDefinedRTCPPacket( return 0; } -int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost, +int32_t ViEChannel::GetSendRtcpStatistics(uint32_t* ntp_high, + uint32_t* ntp_low, + uint32_t* bytes_sent, + uint32_t* packets_sent, + uint16_t* fraction_lost, uint32_t* cumulative_lost, uint32_t* extended_max, uint32_t* jitter_samples, @@ -1196,6 +1200,20 @@ int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost, // } uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc(); + // --- Information from sender info in received RTCP Sender Reports + + RTCPSenderInfo sender_info; + if (rtp_rtcp_->RemoteRTCPStat(&sender_info) != 0) { + WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), + "%s: Could not get sender info for remote side", __FUNCTION__); + return -1; + } + + *ntp_high = sender_info.NTPseconds; + *ntp_low = sender_info.NTPfraction; + *bytes_sent = sender_info.sendOctetCount; + *packets_sent = sender_info.sendPacketCount; + // Get all RTCP receiver report blocks that have been received on this // channel. If we receive RTP packets from a remote source we know the // remote SSRC and use the report block from him. @@ -1240,7 +1258,11 @@ int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost, // 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. -int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost, +int32_t ViEChannel::GetReceivedRtcpStatistics(uint32_t* ntp_high, + uint32_t* ntp_low, + uint32_t* bytes_sent, + uint32_t* packets_sent, + uint16_t* fraction_lost, uint32_t* cumulative_lost, uint32_t* extended_max, uint32_t* jitter_samples, @@ -1248,6 +1270,22 @@ int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost, WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s", __FUNCTION__); + // --- Information from sender info in received RTCP Sender Reports + + RTCPSenderInfo sender_info; + if (rtp_rtcp_->RemoteRTCPStat(&sender_info) != 0) { + WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_), + "%s: Could not get sender info for remote side", __FUNCTION__); + return -1; + } + + *ntp_high = sender_info.NTPseconds; + *ntp_low = sender_info.NTPfraction; + *bytes_sent = sender_info.sendOctetCount; + *packets_sent = sender_info.sendPacketCount; + + // --- Locally derived information + uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc(); uint8_t frac_lost = 0; StreamStatistician* statistician = diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_channel.h b/media/webrtc/trunk/webrtc/video_engine/vie_channel.h index 9791e102d751..e806b13349dc 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.h +++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.h @@ -164,14 +164,22 @@ class ViEChannel uint16_t data_length_in_bytes); // Returns statistics reported by the remote client in an RTCP packet. - int32_t GetSendRtcpStatistics(uint16_t* fraction_lost, + int32_t GetSendRtcpStatistics(uint32_t* ntp_high, + uint32_t* ntp_low, + uint32_t* bytes_sent, + uint32_t* packets_sent, + uint16_t* fraction_lost, uint32_t* cumulative_lost, uint32_t* extended_max, uint32_t* jitter_samples, int32_t* rtt_ms); - // Returns our localy created statistics of the received RTP stream. - int32_t GetReceivedRtcpStatistics(uint16_t* fraction_lost, + // Returns RTCP sender report + locally created stats of received RTP stream + int32_t GetReceivedRtcpStatistics(uint32_t* ntp_high, + uint32_t* ntp_low, + uint32_t* bytes_sent, + uint32_t* packets_sent, + uint16_t* fraction_lost, uint32_t* cumulative_lost, uint32_t* extended_max, uint32_t* jitter_samples, diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc index ecfa1b669f5a..25a3fef51ec4 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -824,6 +824,10 @@ int ViERTP_RTCPImpl::SetTransmissionSmoothingStatus(int video_channel, } int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel, + unsigned int& ntp_high, + unsigned int& ntp_low, + unsigned int& bytes_sent, + unsigned int& packets_sent, uint16_t& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, @@ -841,7 +845,11 @@ int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel, shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); return -1; } - if (vie_channel->GetReceivedRtcpStatistics(&fraction_lost, + if (vie_channel->GetReceivedRtcpStatistics(&ntp_high, + &ntp_low, + &bytes_sent, + &packets_sent, + &fraction_lost, &cumulative_lost, &extended_max, &jitter, @@ -853,6 +861,10 @@ int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel, } int ViERTP_RTCPImpl::GetSentRTCPStatistics(const int video_channel, + unsigned int& ntp_high, + unsigned int& ntp_low, + unsigned int& bytes_sent, + unsigned int& packets_sent, uint16_t& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, @@ -871,7 +883,9 @@ int ViERTP_RTCPImpl::GetSentRTCPStatistics(const int video_channel, return -1; } - if (vie_channel->GetSendRtcpStatistics(&fraction_lost, &cumulative_lost, + if (vie_channel->GetSendRtcpStatistics(&ntp_high, &ntp_low, + &bytes_sent, &packets_sent, + &fraction_lost, &cumulative_lost, &extended_max, &jitter, &rtt_ms) != 0) { shared_data_->SetLastError(kViERtpRtcpUnknownError); diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h index 9af4b0c2b2ef..bd2926984aba 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h +++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h @@ -90,12 +90,20 @@ class ViERTP_RTCPImpl int id); virtual int SetTransmissionSmoothingStatus(int video_channel, bool enable); virtual int GetReceivedRTCPStatistics(const int video_channel, + unsigned int& ntpHigh, + unsigned int& ntpLow, + unsigned int& bytes_sent, + unsigned int& packets_sent, uint16_t& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, unsigned int& jitter, int& rtt_ms) const; virtual int GetSentRTCPStatistics(const int video_channel, + unsigned int& ntpHigh, + unsigned int& ntpLow, + unsigned int& bytes_sent, + unsigned int& packets_sent, uint16_t& fraction_lost, unsigned int& cumulative_lost, unsigned int& extended_max, diff --git a/media/webrtc/trunk/webrtc/voice_engine/channel.cc b/media/webrtc/trunk/webrtc/voice_engine/channel.cc index 0702d85bddf9..e0afefa4c9ef 100644 --- a/media/webrtc/trunk/webrtc/voice_engine/channel.cc +++ b/media/webrtc/trunk/webrtc/voice_engine/channel.cc @@ -3799,8 +3799,11 @@ Channel::GetRemoteRTCPData( unsigned int& NTPLow, unsigned int& timestamp, unsigned int& playoutTimestamp, + unsigned int& sendPacketCount, + unsigned int& sendOctetCount, unsigned int* jitter, - unsigned short* fractionLost) + unsigned short* fractionLost, + unsigned int* cumulativeLost) { // --- Information from sender info in received Sender Reports @@ -3814,11 +3817,11 @@ Channel::GetRemoteRTCPData( return -1; } - // We only utilize 12 out of 20 bytes in the sender info (ignores packet - // and octet count) NTPHigh = senderInfo.NTPseconds; NTPLow = senderInfo.NTPfraction; timestamp = senderInfo.RTPtimeStamp; + sendPacketCount = senderInfo.sendPacketCount; + sendOctetCount = senderInfo.sendOctetCount; WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId), @@ -3837,7 +3840,7 @@ Channel::GetRemoteRTCPData( "GetRemoteRTCPData() => playoutTimestamp=%lu", playout_timestamp_rtcp_); - if (NULL != jitter || NULL != fractionLost) + if (NULL != jitter || NULL != fractionLost || NULL != cumulativeLost) { // Get all RTCP receiver report blocks that have been received on this // channel. If we receive RTP packets from a remote source we know the @@ -3882,6 +3885,14 @@ Channel::GetRemoteRTCPData( "GetRemoteRTCPData() => fractionLost = %lu", *fractionLost); } + + if (cumulativeLost) { + *cumulativeLost = it->cumulativeLost; + WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, + VoEId(_instanceId, _channelId), + "GetRemoteRTCPData() => cumulativeLost = %lu", + *cumulativeLost); + } } return 0; } diff --git a/media/webrtc/trunk/webrtc/voice_engine/channel.h b/media/webrtc/trunk/webrtc/voice_engine/channel.h index 2e5ac5317b45..89cb0e533abd 100644 --- a/media/webrtc/trunk/webrtc/voice_engine/channel.h +++ b/media/webrtc/trunk/webrtc/voice_engine/channel.h @@ -264,8 +264,12 @@ public: int GetRemoteRTCP_CNAME(char cName[256]); int GetRemoteRTCPData(unsigned int& NTPHigh, unsigned int& NTPLow, unsigned int& timestamp, - unsigned int& playoutTimestamp, unsigned int* jitter, - unsigned short* fractionLost); + unsigned int& playoutTimestamp, + unsigned int& sendPacketCount, + unsigned int& sendOctetCount, + unsigned int* jitter, + unsigned short* fractionLost, + unsigned int* cumulativeLost); int SendApplicationDefinedRTCPPacket(unsigned char subType, unsigned int name, const char* data, unsigned short dataLengthInBytes); diff --git a/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h b/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h index 30d8add8c6df..51e6abb3b90a 100644 --- a/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h +++ b/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h @@ -185,7 +185,9 @@ public: virtual int GetRemoteRTCPData( int channel, unsigned int& NTPHigh, unsigned int& NTPLow, unsigned int& timestamp, unsigned int& playoutTimestamp, - unsigned int* jitter = NULL, unsigned short* fractionLost = NULL) = 0; + unsigned int& sendPacketCount, unsigned int& sendOctetCount, + unsigned int* jitter = NULL, unsigned short* fractionLost = NULL, + unsigned int* cumulativeLost = NULL) = 0; // Gets RTP statistics for a specific |channel|. virtual int GetRTPStatistics( diff --git a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc index 945c5384b367..f3c9a83280cb 100644 --- a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc +++ b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc @@ -375,8 +375,11 @@ int VoERTP_RTCPImpl::GetRemoteRTCPData( unsigned int& NTPLow, // from sender info in SR unsigned int& timestamp, // from sender info in SR unsigned int& playoutTimestamp, // derived locally + unsigned int& sendPacketCount, // from sender info in SR + unsigned int& sendOctetCount, // from sender info in SR unsigned int* jitter, // from report block 1 in SR/RR - unsigned short* fractionLost) // from report block 1 in SR/RR + unsigned short* fractionLost, // from report block 1 in SR/RR + unsigned int* cumulativeLost) // from report block 1 in SR/RR { WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), "GetRemoteRTCPData(channel=%d,...)", channel); @@ -397,8 +400,11 @@ int VoERTP_RTCPImpl::GetRemoteRTCPData( NTPLow, timestamp, playoutTimestamp, + sendPacketCount, + sendOctetCount, jitter, - fractionLost); + fractionLost, + cumulativeLost); } int VoERTP_RTCPImpl::SendApplicationDefinedRTCPPacket( diff --git a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h index 0f8d08481c8b..b02fed0a1663 100644 --- a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h +++ b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h @@ -45,8 +45,11 @@ public: unsigned int& NTPLow, unsigned int& timestamp, unsigned int& playoutTimestamp, + unsigned int& sendPacketCount, + unsigned int& sendOctetCount, unsigned int* jitter = NULL, - unsigned short* fractionLost = NULL); + unsigned short* fractionLost = NULL, + unsigned int* cumulativeLost = NULL); virtual int SendApplicationDefinedRTCPPacket( int channel, diff --git a/toolkit/content/aboutWebrtc.xhtml b/toolkit/content/aboutWebrtc.xhtml index 28c44f1c502d..25a39762e139 100644 --- a/toolkit/content/aboutWebrtc.xhtml +++ b/toolkit/content/aboutWebrtc.xhtml @@ -148,6 +148,26 @@ function round00(num) { return Math.round(num * 100) / 100; } +function dumpStat(stat, label) { + var div = document.createElement('div'); + var statsString = " " + label + new Date(stat.timestamp).toTimeString() + + " " + stat.type + " SSRC: " + stat.ssrc; + if (stat.packetsReceived !== undefined) { + statsString += " Received: " + stat.packetsReceived + " packets"; + if (stat.bytesReceived !== undefined) { + statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)"; + } + statsString += " Jitter: " + stat.jitter; + } else if (stat.packetsSent !== undefined) { + statsString += " Sent: " + stat.packetsSent + " packets"; + if (stat.bytesSent !== undefined) { + statsString += " (" + round00(stat.bytesSent/1024) + " Kb)"; + } + } + div.appendChild(document.createTextNode(statsString)); + return div; +} + function buildPcDiv(stats, pcDivId) { var newPcDiv = document.createElement('div'); @@ -159,26 +179,16 @@ function buildPcDiv(stats, pcDivId) { stats.forEach(function(stat) { if (!stat.componentId) { - var statDiv = document.createElement('div'); - statDiv.appendChild(document.createElement('strong')) - .appendChild(document.createTextNode(stat.id)); - - var statsString = " " + new Date(stat.timestamp).toTimeString() + - " " + stat.type + " SSRC: " + stat.ssrc; - if (stat.packetsReceived !== undefined) { - statsString += " Received: " + stat.packetsReceived + " packets"; - if (stat.bytesReceived !== undefined) { - statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)"; - } - statsString += " Jitter: " + stat.jitter; - } else if (stat.packetsSent !== undefined) { - statsString += " Sent: " + stat.packetsSent + " packets"; - if (stat.bytesSent !== undefined) { - statsString += " (" + round00(stat.bytesSent/1024) + " Kb)"; + if (!stat.isRemote) { + newPcDiv.appendChild(document.createElement('h4')) + .appendChild(document.createTextNode(stat.id)); + if (stat.remoteId) { + newPcDiv.appendChild(dumpStat(stat, "Local: ")); + newPcDiv.appendChild(dumpStat(stats.get(stat.remoteId), "Remote: ")); + } else { + newPcDiv.appendChild(dumpStat(stat, "")); } } - statDiv.appendChild(document.createTextNode(statsString)); - newPcDiv.appendChild(statDiv); return; }