Bug 1359775 - Part 1 - add RTCRtpContributingSourceStats;r=jib,smaug

Still left TODO:
  * add an aboutWebrtc.js section
  * write tests

MozReview-Commit-ID: DwFxq19KWeu

--HG--
extra : rebase_source : fad3018d851316af83df48c62db16028a1a84b5c
This commit is contained in:
Nico Grunbaum 2017-04-26 04:27:13 -07:00
Родитель d2076c357d
Коммит e45ddffb1e
7 изменённых файлов: 191 добавлений и 18 удалений

Просмотреть файл

@ -15,6 +15,7 @@ function convertToRTCStatsReport(dict) {
let report = {};
appendStats(dict.inboundRTPStreamStats, report);
appendStats(dict.outboundRTPStreamStats, report);
appendStats(dict.rtpContributingSourceStats, report);
appendStats(dict.mediaStreamTrackStats, report);
appendStats(dict.mediaStreamStats, report);
appendStats(dict.transportStats, report);

Просмотреть файл

@ -35,6 +35,7 @@ var statsExpectedByType = {
"sliCount", "qpSum", "targetBitrate",],
deprecated: [],
},
"csrc": { skip: true },
"codec": { skip: true },
"peer-connection": { skip: true },
"data-channel": { skip: true },

Просмотреть файл

@ -115,6 +115,7 @@ struct ParamTraits<mozilla::dom::RTCStatsReportInternal>
WriteParam(aMsg, aParam.mIceRestarts);
WriteParam(aMsg, aParam.mIceRollbacks);
WriteParam(aMsg, aParam.mTransportStats);
WriteParam(aMsg, aParam.mRtpContributingSourceStats);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@ -134,7 +135,8 @@ struct ParamTraits<mozilla::dom::RTCStatsReportInternal>
!ReadParam(aMsg, aIter, &(aResult->mTimestamp)) ||
!ReadParam(aMsg, aIter, &(aResult->mIceRestarts)) ||
!ReadParam(aMsg, aIter, &(aResult->mIceRollbacks)) ||
!ReadParam(aMsg, aIter, &(aResult->mTransportStats))) {
!ReadParam(aMsg, aIter, &(aResult->mTransportStats)) ||
!ReadParam(aMsg, aIter, &(aResult->mRtpContributingSourceStats))) {
return false;
}
@ -504,6 +506,29 @@ struct ParamTraits<mozilla::dom::RTCMediaStreamTrackStats>
}
};
template<>
struct ParamTraits<mozilla::dom::RTCRTPContributingSourceStats>
{
typedef mozilla::dom::RTCRTPContributingSourceStats paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mContributorSsrc);
WriteParam(aMsg, aParam.mInboundRtpStreamId);
WriteRTCStats(aMsg, aParam);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
if (!ReadParam(aMsg, aIter, &(aResult->mContributorSsrc)) ||
!ReadParam(aMsg, aIter, &(aResult->mInboundRtpStreamId)) ||
!ReadRTCStats(aMsg, aIter, aResult)) {
return false;
}
return true;
}
};
} // namespace ipc
#endif // _WEBRTC_GLOBAL_H_

Просмотреть файл

@ -11,6 +11,7 @@
enum RTCStatsType {
"inbound-rtp",
"outbound-rtp",
"csrc",
"session",
"track",
"transport",
@ -95,6 +96,11 @@ dictionary RTCMediaStreamStats : RTCStats {
sequence<DOMString> trackIds; // Note: stats object ids, not track.id
};
dictionary RTCRTPContributingSourceStats : RTCStats {
unsigned long contributorSsrc;
DOMString inboundRtpStreamId;
};
dictionary RTCTransportStats: RTCStats {
unsigned long bytesSent;
unsigned long bytesReceived;
@ -157,22 +163,23 @@ dictionary RTCCodecStats : RTCStats {
// to be received from c++
dictionary RTCStatsReportInternal {
DOMString pcid = "";
sequence<RTCInboundRTPStreamStats> inboundRTPStreamStats;
sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;
sequence<RTCMediaStreamTrackStats> mediaStreamTrackStats;
sequence<RTCMediaStreamStats> mediaStreamStats;
sequence<RTCTransportStats> transportStats;
sequence<RTCIceComponentStats> iceComponentStats;
sequence<RTCIceCandidatePairStats> iceCandidatePairStats;
sequence<RTCIceCandidateStats> iceCandidateStats;
sequence<RTCCodecStats> codecStats;
DOMString localSdp;
DOMString remoteSdp;
DOMHighResTimeStamp timestamp;
unsigned long iceRestarts;
unsigned long iceRollbacks;
boolean closed; // Is the PC now closed
DOMString pcid = "";
sequence<RTCInboundRTPStreamStats> inboundRTPStreamStats;
sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;
sequence<RTCRTPContributingSourceStats> rtpContributingSourceStats;
sequence<RTCMediaStreamTrackStats> mediaStreamTrackStats;
sequence<RTCMediaStreamStats> mediaStreamStats;
sequence<RTCTransportStats> transportStats;
sequence<RTCIceComponentStats> iceComponentStats;
sequence<RTCIceCandidatePairStats> iceCandidatePairStats;
sequence<RTCIceCandidateStats> iceCandidateStats;
sequence<RTCCodecStats> codecStats;
DOMString localSdp;
DOMString remoteSdp;
DOMHighResTimeStamp timestamp;
unsigned long iceRestarts;
unsigned long iceRollbacks;
boolean closed; // Is the PC now closed
};
[Pref="media.peerconnection.enabled",

Просмотреть файл

@ -42,6 +42,7 @@
#include "transportlayerice.h"
#include "runnable_utils.h"
#include "libyuv/convert.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/PeerIdentity.h"
#include "mozilla/Preferences.h"
@ -56,6 +57,8 @@
#include "webrtc/common_types.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "nsThreadUtils.h"
#include "logging.h"
// Max size given stereo is 480*2*2 = 1920 (10ms of 16-bits stereo audio at
@ -609,7 +612,7 @@ MediaPipeline::MediaPipeline(const std::string& pc,
pc_(pc),
description_(),
filter_(filter),
rtp_parser_(webrtc::RtpHeaderParser::Create()) {
rtp_parser_(webrtc::RtpHeaderParser::Create()){
// To indicate rtcp-mux rtcp_transport should be nullptr.
// Therefore it's an error to send in the same flow for
// both rtp and rtcp.
@ -769,6 +772,22 @@ MediaPipeline::AddRIDFilter_s(const std::string& rid)
filter_->AddRemoteRtpStreamId(rid);
}
void
MediaPipeline::GetContributingSourceStats(
const nsString& aInboundRtpStreamId,
FallibleTArray<dom::RTCRTPContributingSourceStats>& aArr) const
{
// Get the expiry from now
DOMHighResTimeStamp expiry = RtpCSRCStats::GetExpiryFromTime(GetNow());
for (auto info : csrc_stats_) {
if (!info.second.Expired(expiry)) {
RTCRTPContributingSourceStats stats;
info.second.GetWebidlInstance(stats, aInboundRtpStreamId);
aArr.AppendElement(stats, fallible);
}
}
}
void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) {
TransportInfo* info = GetTransportInfo_s(flow);
MOZ_ASSERT(info);
@ -1063,6 +1082,44 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
return;
}
// Make sure to only get the time once, and only if we need it by
// using getTimestamp() for access
DOMHighResTimeStamp now = 0.0;
bool hasTime = false;
// Remove expired RtpCSRCStats
if (!csrc_stats_.empty()) {
if (!hasTime) {
now = GetNow();
hasTime = true;
}
auto expiry = RtpCSRCStats::GetExpiryFromTime(now);
for (auto p = csrc_stats_.begin(); p != csrc_stats_.end();) {
if (p->second.Expired(expiry)) {
p = csrc_stats_.erase(p);
continue;
}
p++;
}
}
// Add new RtpCSRCStats
if (header.numCSRCs) {
for (auto i = 0; i < header.numCSRCs; i++) {
if (!hasTime) {
now = GetNow();
hasTime = true;
}
auto csrcInfo = csrc_stats_.find(header.arrOfCSRCs[i]);
if (csrcInfo == csrc_stats_.end()) {
csrc_stats_.insert(std::make_pair(header.arrOfCSRCs[i],
RtpCSRCStats(header.arrOfCSRCs[i],now)));
} else {
csrcInfo->second.SetTimestamp(now);
}
}
}
// Make a copy rather than cast away constness
auto inner_data = MakeUnique<unsigned char[]>(len);
memcpy(inner_data.get(), data, len);
@ -2322,4 +2379,35 @@ void MediaPipelineReceiveVideo::SetPrincipalHandle_m(const PrincipalHandle& prin
listener_->SetPrincipalHandle_m(principal_handle);
}
DOMHighResTimeStamp MediaPipeline::GetNow() {
return webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
}
DOMHighResTimeStamp
MediaPipeline::RtpCSRCStats::GetExpiryFromTime(
const DOMHighResTimeStamp aTime) {
// DOMHighResTimeStamp is a unit measured in ms
return aTime - EXPIRY_TIME_MILLISECONDS;
}
MediaPipeline::RtpCSRCStats::RtpCSRCStats(const uint32_t aCsrc,
const DOMHighResTimeStamp aTime)
: mCsrc(aCsrc)
, mTimestamp(aTime) {}
void
MediaPipeline::RtpCSRCStats::GetWebidlInstance(
dom::RTCRTPContributingSourceStats& aWebidlObj,
const nsString &aInboundRtpStreamId) const
{
nsString statId = NS_LITERAL_STRING("csrc_") + aInboundRtpStreamId;
statId.AppendLiteral("_");
statId.AppendInt(mCsrc);
aWebidlObj.mId.Construct(statId);
aWebidlObj.mType.Construct(RTCStatsType::Csrc);
aWebidlObj.mTimestamp.Construct(mTimestamp);
aWebidlObj.mContributorSsrc.Construct(mCsrc);
aWebidlObj.mInboundRtpStreamId.Construct(aInboundRtpStreamId);
}
} // end namespace

Просмотреть файл

@ -8,6 +8,8 @@
#ifndef mediapipeline_h__
#define mediapipeline_h__
#include <map>
#include "sigslot.h"
#include "MediaConduitInterface.h"
@ -36,6 +38,7 @@ class VideoFrameConverter;
namespace dom {
class MediaStreamTrack;
struct RTCRTPContributingSourceStats;
} // namespace dom
class SourceMediaStream;
@ -132,6 +135,45 @@ class MediaPipeline : public sigslot::has_slots<> {
return (rtp_.type_ == MUX);
}
class RtpCSRCStats {
public:
// Gets an expiration time for CRC info given a reference time,
// this reference time would normally be the time of calling.
// This value can then be used to check if a RtpCSRCStats
// has expired via Expired(...)
static DOMHighResTimeStamp
GetExpiryFromTime(const DOMHighResTimeStamp aTime);
RtpCSRCStats(const uint32_t aCsrc,
const DOMHighResTimeStamp aTime);
~RtpCSRCStats() {};
// Initialize a webidl representation suitable for adding to a report.
// This assumes that the webidl object is empty.
// @param aWebidlObj the webidl binding object to popluate
// @param aRtpInboundStreamId the associated RTCInboundRTPStreamStats.id
void
GetWebidlInstance(dom::RTCRTPContributingSourceStats& aWebidlObj,
const nsString &aInboundRtpStreamId) const;
void SetTimestamp(const DOMHighResTimeStamp aTime) { mTimestamp = aTime; }
// Check if the RtpCSRCStats has expired, checks against a
// given expiration time.
bool Expired(const DOMHighResTimeStamp aExpiry) const {
return mTimestamp < aExpiry;
}
private:
static const double constexpr EXPIRY_TIME_MILLISECONDS = 10 * 1000;
uint32_t mCsrc;
DOMHighResTimeStamp mTimestamp;
};
// Gets the gathered contributing source stats for the last expiration period.
// @param aId the stream id to use for populating inboundRtpStreamId field
// @param aArr the array to append the stats objects to
void
GetContributingSourceStats(
const nsString& aInboundStreamId,
FallibleTArray<dom::RTCRTPContributingSourceStats>& aArr) const;
int32_t rtp_packets_sent() const { return rtp_packets_sent_; }
int64_t rtp_bytes_sent() const { return rtp_bytes_sent_; }
int32_t rtcp_packets_sent() const { return rtcp_packets_sent_; }
@ -269,6 +311,9 @@ class MediaPipeline : public sigslot::has_slots<> {
int64_t rtp_bytes_sent_;
int64_t rtp_bytes_received_;
// Only safe to access from STS thread.
std::map<uint32_t, RtpCSRCStats> csrc_stats_;
// Written on Init. Read on STS thread.
std::string pc_;
std::string description_;
@ -278,6 +323,8 @@ class MediaPipeline : public sigslot::has_slots<> {
nsAutoPtr<webrtc::RtpHeaderParser> rtp_parser_;
private:
// Gets the current time as a DOMHighResTimeStamp
static DOMHighResTimeStamp GetNow();
nsresult Init_s();
bool IsRtp(const unsigned char *data, size_t len);

Просмотреть файл

@ -2090,6 +2090,7 @@ class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
public:
RTCStatsReportInternalConstruct(const nsString &pcid, DOMHighResTimeStamp now) {
mPcid = pcid;
mRtpContributingSourceStats.Construct();
mInboundRTPStreamStats.Construct();
mOutboundRTPStreamStats.Construct();
mMediaStreamTrackStats.Construct();
@ -3818,6 +3819,9 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
}
query->report->mInboundRTPStreamStats.Value().AppendElement(s,
fallible);
// Fill in Contributing Source statistics
mp.GetContributingSourceStats(localId,
query->report->mRtpContributingSourceStats.Value());
break;
}
}