Bug 906990 - Part 12: Report statistics from all components when the MediaStreamTrack is not specified. r=ekr

This commit is contained in:
Byron Campen [:bwc] 2014-01-07 09:20:28 -08:00
parent d3401e83a9
commit f0d2b96210
8 changed files with 293 additions and 161 deletions

View File

@ -119,13 +119,17 @@ GlobalPCList.prototype = {
}, },
getStatsForEachPC: function(callback, errorCallback) { getStatsForEachPC: function(callback, errorCallback) {
function getStatsFromPC(pcref) {
if (pcref.get()) {
pcref.get().getStatsInternal(null, callback, errorCallback);
}
}
for (let winId in this._list) { for (let winId in this._list) {
if (this._list.hasOwnProperty(winId)) { if (this._list.hasOwnProperty(winId)) {
this.removeNullRefs(winId); this.removeNullRefs(winId);
if (this._list[winId]) { if (this._list[winId]) {
this._list[winId].forEach(function(pcref) { this._list[winId].forEach(getStatsFromPC);
pcref.get().getStatsInternal(null, callback, errorCallback);
});
} }
} }
} }

View File

@ -104,6 +104,7 @@ enum RTCStatsIceCandidateType {
}; };
dictionary RTCIceCandidateStats : RTCStats { dictionary RTCIceCandidateStats : RTCStats {
DOMString componentId;
DOMString candidateId; DOMString candidateId;
DOMString ipAddress; DOMString ipAddress;
long portNumber; long portNumber;

View File

@ -1589,6 +1589,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
pc.impl()->GetSTSThread(), pc.impl()->GetSTSThread(),
stream->GetMediaStream()->GetStream(), stream->GetMediaStream()->GetStream(),
pc_track_id, pc_track_id,
level,
conduit, rtp_flow, rtcp_flow); conduit, rtp_flow, rtcp_flow);
nsresult res = pipeline->Init(); nsresult res = pipeline->Init();
@ -1640,6 +1641,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
pc.impl()->GetSTSThread(), pc.impl()->GetSTSThread(),
stream->GetMediaStream()->GetStream(), stream->GetMediaStream()->GetStream(),
pc_track_id, pc_track_id,
level,
conduit, rtp_flow, rtcp_flow); conduit, rtp_flow, rtcp_flow);
nsresult res = pipeline->Init(); nsresult res = pipeline->Init();
@ -2241,6 +2243,7 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id,
pc.impl()->GetSTSThread(), pc.impl()->GetSTSThread(),
stream->GetMediaStream(), stream->GetMediaStream(),
pc_track_id, pc_track_id,
level,
conduit, rtp_flow, rtcp_flow); conduit, rtp_flow, rtcp_flow);
nsresult res = pipeline->Init(); nsresult res = pipeline->Init();
@ -2291,6 +2294,7 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id,
pc.impl()->GetSTSThread(), pc.impl()->GetSTSThread(),
stream->GetMediaStream(), stream->GetMediaStream(),
pc_track_id, pc_track_id,
level,
conduit, rtp_flow, rtcp_flow); conduit, rtp_flow, rtcp_flow);
nsresult res = pipeline->Init(); nsresult res = pipeline->Init();

View File

@ -71,12 +71,14 @@ class MediaPipeline : public sigslot::has_slots<> {
nsCOMPtr<nsIEventTarget> sts_thread, nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream, MediaStream *stream,
TrackID track_id, TrackID track_id,
int level,
RefPtr<MediaSessionConduit> conduit, RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport, RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport) RefPtr<TransportFlow> rtcp_transport)
: direction_(direction), : direction_(direction),
stream_(stream), stream_(stream),
track_id_(track_id), track_id_(track_id),
level_(level),
conduit_(conduit), conduit_(conduit),
rtp_transport_(rtp_transport), rtp_transport_(rtp_transport),
rtp_state_(MP_CONNECTING), rtp_state_(MP_CONNECTING),
@ -126,6 +128,7 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual Direction direction() const { return direction_; } virtual Direction direction() const { return direction_; }
virtual TrackID trackid() const { return track_id_; } virtual TrackID trackid() const { return track_id_; }
virtual int level() const { return level_; }
bool IsDoingRtcpMux() const { bool IsDoingRtcpMux() const {
return (rtp_transport_ == rtcp_transport_); return (rtp_transport_ == rtcp_transport_);
@ -194,6 +197,7 @@ class MediaPipeline : public sigslot::has_slots<> {
// Used on STS and MediaStreamGraph threads. // Used on STS and MediaStreamGraph threads.
TrackID track_id_; // The track on the stream. TrackID track_id_; // The track on the stream.
// Written and used as the stream_; // Written and used as the stream_;
int level_; // The m-line index (starting at 1, to match convention)
RefPtr<MediaSessionConduit> conduit_; // Our conduit. Written on the main RefPtr<MediaSessionConduit> conduit_; // Our conduit. Written on the main
// thread. Read on STS thread. // thread. Read on STS thread.
@ -315,12 +319,13 @@ class MediaPipelineTransmit : public MediaPipeline {
nsCOMPtr<nsIEventTarget> sts_thread, nsCOMPtr<nsIEventTarget> sts_thread,
DOMMediaStream *domstream, DOMMediaStream *domstream,
TrackID track_id, TrackID track_id,
int level,
RefPtr<MediaSessionConduit> conduit, RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport, RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport) : RefPtr<TransportFlow> rtcp_transport) :
MediaPipeline(pc, TRANSMIT, main_thread, sts_thread, MediaPipeline(pc, TRANSMIT, main_thread, sts_thread,
domstream->GetStream(), track_id, conduit, rtp_transport, domstream->GetStream(), track_id, level,
rtcp_transport), conduit, rtp_transport, rtcp_transport),
listener_(new PipelineListener(conduit)), listener_(new PipelineListener(conduit)),
domstream_(domstream) domstream_(domstream)
{} {}
@ -437,11 +442,12 @@ class MediaPipelineReceive : public MediaPipeline {
nsCOMPtr<nsIEventTarget> sts_thread, nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream, MediaStream *stream,
TrackID track_id, TrackID track_id,
int level,
RefPtr<MediaSessionConduit> conduit, RefPtr<MediaSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport, RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport) : RefPtr<TransportFlow> rtcp_transport) :
MediaPipeline(pc, RECEIVE, main_thread, sts_thread, MediaPipeline(pc, RECEIVE, main_thread, sts_thread,
stream, track_id, conduit, rtp_transport, stream, track_id, level, conduit, rtp_transport,
rtcp_transport), rtcp_transport),
segments_added_(0) { segments_added_(0) {
} }
@ -464,11 +470,12 @@ class MediaPipelineReceiveAudio : public MediaPipelineReceive {
nsCOMPtr<nsIEventTarget> sts_thread, nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream, MediaStream *stream,
TrackID track_id, TrackID track_id,
int level,
RefPtr<AudioSessionConduit> conduit, RefPtr<AudioSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport, RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport) : RefPtr<TransportFlow> rtcp_transport) :
MediaPipelineReceive(pc, main_thread, sts_thread, MediaPipelineReceive(pc, main_thread, sts_thread,
stream, track_id, conduit, rtp_transport, stream, track_id, level, conduit, rtp_transport,
rtcp_transport), rtcp_transport),
listener_(new PipelineListener(stream->AsSourceStream(), listener_(new PipelineListener(stream->AsSourceStream(),
track_id, conduit)) { track_id, conduit)) {
@ -526,11 +533,12 @@ class MediaPipelineReceiveVideo : public MediaPipelineReceive {
nsCOMPtr<nsIEventTarget> sts_thread, nsCOMPtr<nsIEventTarget> sts_thread,
MediaStream *stream, MediaStream *stream,
TrackID track_id, TrackID track_id,
int level,
RefPtr<VideoSessionConduit> conduit, RefPtr<VideoSessionConduit> conduit,
RefPtr<TransportFlow> rtp_transport, RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport) : RefPtr<TransportFlow> rtcp_transport) :
MediaPipelineReceive(pc, main_thread, sts_thread, MediaPipelineReceive(pc, main_thread, sts_thread,
stream, track_id, conduit, rtp_transport, stream, track_id, level, conduit, rtp_transport,
rtcp_transport), rtcp_transport),
renderer_(new PipelineRenderer(MOZ_THIS_IN_INITIALIZER_LIST())), renderer_(new PipelineRenderer(MOZ_THIS_IN_INITIALIZER_LIST())),
listener_(new PipelineListener(stream->AsSourceStream(), track_id)) { listener_(new PipelineListener(stream->AsSourceStream(), track_id)) {

View File

@ -5,6 +5,7 @@
#include <cstdlib> #include <cstdlib>
#include <cerrno> #include <cerrno>
#include <deque> #include <deque>
#include <sstream>
#include "base/histogram.h" #include "base/histogram.h"
#include "vcm.h" #include "vcm.h"
@ -32,6 +33,7 @@
#include "nsIConsoleService.h" #include "nsIConsoleService.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsProxyRelease.h" #include "nsProxyRelease.h"
#include "prtime.h"
#include "runnable_utils.h" #include "runnable_utils.h"
#include "PeerConnectionCtx.h" #include "PeerConnectionCtx.h"
@ -56,6 +58,7 @@
#include "nsURLHelper.h" #include "nsURLHelper.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsIDOMDataChannel.h" #include "nsIDOMDataChannel.h"
#include "nsIDOMLocation.h"
#include "mozilla/dom/RTCConfigurationBinding.h" #include "mozilla/dom/RTCConfigurationBinding.h"
#include "mozilla/dom/RTCStatsReportBinding.h" #include "mozilla/dom/RTCStatsReportBinding.h"
#include "mozilla/dom/RTCPeerConnectionBinding.h" #include "mozilla/dom/RTCPeerConnectionBinding.h"
@ -709,8 +712,34 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow);
mWindow = aWindow; mWindow = aWindow;
NS_ENSURE_STATE(mWindow); NS_ENSURE_STATE(mWindow);
#endif // MOZILLA_INTERNAL_API #endif // MOZILLA_INTERNAL_API
PRTime timestamp = PR_Now();
// Ok if we truncate this.
char temp[128];
#ifdef MOZILLA_INTERNAL_API
nsIDOMLocation* location = nullptr;
mWindow->GetLocation(&location);
MOZ_ASSERT(location);
nsString locationAStr;
location->ToString(locationAStr);
nsCString locationCStr;
CopyUTF16toUTF8(locationAStr, locationCStr);
PR_snprintf(temp,
sizeof(temp),
"%ull (id=%u url=%s)",
timestamp,
mWindow->WindowID(),
locationCStr.get());
#else
PR_snprintf(temp, sizeof(temp), "%ull", timestamp);
#endif // MOZILLA_INTERNAL_API
mName = temp;
// Generate a random handle // Generate a random handle
unsigned char handle_bin[8]; unsigned char handle_bin[8];
SECStatus rv; SECStatus rv;
@ -1259,29 +1288,49 @@ PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector, bool internalStats) {
// Gather up pipelines from mMedia and dispatch them to STS for inspection // Gather up pipelines from mMedia and dispatch them to STS for inspection
nsAutoPtr<std::vector<RefPtr<MediaPipeline>>> pipelines( std::vector<RefPtr<MediaPipeline>> pipelines;
new std::vector<RefPtr<MediaPipeline>>());
TrackID trackId = aSelector ? aSelector->GetTrackID() : 0; TrackID trackId = aSelector ? aSelector->GetTrackID() : 0;
for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) { for (int i = 0, len = mMedia->LocalStreamsLength(); i < len; i++) {
PushBackSelect(*pipelines, mMedia->GetLocalStream(i)->GetPipelines(), trackId); PushBackSelect(pipelines, mMedia->GetLocalStream(i)->GetPipelines(), trackId);
} }
for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) { for (int i = 0, len = mMedia->RemoteStreamsLength(); i < len; i++) {
PushBackSelect(*pipelines, mMedia->GetRemoteStream(i)->GetPipelines(), trackId); PushBackSelect(pipelines, mMedia->GetRemoteStream(i)->GetPipelines(), trackId);
}
// From the list of MediaPipelines, determine the set of NrIceMediaStreams
// we are interested in.
std::vector<RefPtr<NrIceMediaStream> > streams;
RefPtr<NrIceCtx> iceCtx(mMedia->ice_ctx());
for (auto p = pipelines.begin(); p != pipelines.end(); ++p) {
size_t level = p->get()->level();
// TODO(bcampen@mozilla.com): I may need to revisit this for bundle.
// (Bug 786234)
RefPtr<NrIceMediaStream> temp(mMedia->ice_media_stream(level-1));
if (temp.get()) {
streams.push_back(temp);
} else {
CSFLogError(logTag, "Failed to get NrIceMediaStream for level %u "
"in %s: %s",
level, __FUNCTION__, mHandle.c_str());
MOZ_CRASH();
}
} }
DOMHighResTimeStamp now; DOMHighResTimeStamp now;
nsresult rv = GetTimeSinceEpoch(&now); nsresult rv = GetTimeSinceEpoch(&now);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mSTSThread, RUN_ON_THREAD(mSTSThread,
WrapRunnable(pc, WrapRunnableNM(&PeerConnectionImpl::GetStats_s,
&PeerConnectionImpl::GetStats_s, mHandle,
trackId, mName,
internalStats, mThread,
pipelines, internalStats,
now), pipelines,
iceCtx,
streams,
now),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
#endif #endif
return NS_OK; return NS_OK;
@ -1293,11 +1342,11 @@ PeerConnectionImpl::GetLogging(const nsAString& aPattern) {
#ifdef MOZILLA_INTERNAL_API #ifdef MOZILLA_INTERNAL_API
std::string pattern(NS_ConvertUTF16toUTF8(aPattern).get()); std::string pattern(NS_ConvertUTF16toUTF8(aPattern).get());
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mSTSThread, RUN_ON_THREAD(mSTSThread,
WrapRunnable(pc, WrapRunnableNM(&PeerConnectionImpl::GetLogging_s,
&PeerConnectionImpl::GetLogging_s, mHandle,
pattern), mThread,
pattern),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
#endif #endif
@ -1737,6 +1786,13 @@ PeerConnectionImpl::GetHandle()
return mHandle; return mHandle;
} }
const std::string&
PeerConnectionImpl::GetName()
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
return mName;
}
static mozilla::dom::PCImplIceConnectionState static mozilla::dom::PCImplIceConnectionState
toDomIceConnectionState(NrIceCtx::ConnectionState state) { toDomIceConnectionState(NrIceCtx::ConnectionState state) {
switch (state) { switch (state) {
@ -1884,15 +1940,16 @@ PeerConnectionImpl::IceGatheringStateChange_m(PCImplIceGatheringState aState)
#ifdef MOZILLA_INTERNAL_API #ifdef MOZILLA_INTERNAL_API
nsresult nsresult
PeerConnectionImpl::GetStatsImpl_s( PeerConnectionImpl::GetStatsImpl_s(
TrackID trackId,
bool internalStats, bool internalStats,
nsAutoPtr<std::vector<RefPtr<MediaPipeline>>> pipelines, const std::vector<RefPtr<MediaPipeline>>& pipelines,
const RefPtr<NrIceCtx>& iceCtx,
const std::vector<RefPtr<NrIceMediaStream>>& streams,
DOMHighResTimeStamp now, DOMHighResTimeStamp now,
RTCStatsReportInternal *report) { RTCStatsReportInternal* report) {
// Gather stats from pipelines provided (can't touch mMedia + stream on STS) // Gather stats from pipelines provided (can't touch mMedia + stream on STS)
for (auto it = pipelines->begin(); it != pipelines->end(); ++it) { for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
const MediaPipeline& mp = **it; const MediaPipeline& mp = **it;
nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ? nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ?
NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_"); NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
@ -1926,152 +1983,184 @@ PeerConnectionImpl::GetStatsImpl_s(
} }
} }
if (mMedia) { // Gather stats from ICE
for (auto s = streams.begin(); s != streams.end(); ++s) {
// Gather stats from ICE FillStatsReport_s(**s, internalStats, now, report);
RefPtr<NrIceMediaStream> mediaStream(mMedia->ice_media_stream(trackId));
if (mediaStream) {
std::vector<NrIceCandidatePair> candPairs;
mediaStream->GetCandidatePairs(&candPairs);
NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
// Only expose candidate-pair statistics to chrome, until we've thought
// through the implications of exposing it to content.
if (internalStats) {
RTCIceCandidatePairStats s;
s.mId.Construct(codeword);
s.mComponentId.Construct(componentId);
s.mTimestamp.Construct(now);
s.mType.Construct(RTCStatsType::Candidatepair);
// Not quite right; we end up with duplicate candidates. Will fix.
s.mLocalCandidateId.Construct(localCodeword);
s.mRemoteCandidateId.Construct(remoteCodeword);
s.mNominated.Construct(p->nominated);
s.mMozPriority.Construct(p->priority);
s.mSelected.Construct(p->selected);
s.mState.Construct(RTCStatsIceCandidatePairState(p->state));
report->mIceCandidatePairStats.Value().AppendElement(s);
}
{
RTCIceCandidateStats local;
local.mId.Construct(localCodeword);
local.mTimestamp.Construct(now);
local.mType.Construct(RTCStatsType::Localcandidate);
local.mCandidateType.Construct(
RTCStatsIceCandidateType(p->local.type));
local.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->local.cand_addr.host.c_str()));
local.mPortNumber.Construct(p->local.cand_addr.port);
report->mIceCandidateStats.Value().AppendElement(local);
}
{
RTCIceCandidateStats remote;
remote.mId.Construct(remoteCodeword);
remote.mTimestamp.Construct(now);
remote.mType.Construct(RTCStatsType::Remotecandidate);
remote.mCandidateType.Construct(
RTCStatsIceCandidateType(p->remote.type));
remote.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->remote.cand_addr.host.c_str()));
remote.mPortNumber.Construct(p->remote.cand_addr.port);
report->mIceCandidateStats.Value().AppendElement(remote);
}
}
}
} }
return NS_OK; return NS_OK;
} }
void PeerConnectionImpl::GetStats_s( void PeerConnectionImpl::FillStatsReport_s(
TrackID trackId, NrIceMediaStream& mediaStream,
bool internalStats, bool internalStats,
nsAutoPtr<std::vector<RefPtr<MediaPipeline>>> pipelines, DOMHighResTimeStamp now,
RTCStatsReportInternal* report) {
std::vector<NrIceCandidatePair> candPairs;
nsresult res = mediaStream.GetCandidatePairs(&candPairs);
if (NS_FAILED(res)) {
CSFLogError(logTag, "%s: Error getting candidate pairs", __FUNCTION__);
return;
}
NS_ConvertASCIItoUTF16 componentId(mediaStream.name().c_str());
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
// Only expose candidate-pair statistics to chrome, until we've thought
// through the implications of exposing it to content.
if (internalStats) {
RTCIceCandidatePairStats s;
s.mId.Construct(codeword);
s.mComponentId.Construct(componentId);
s.mTimestamp.Construct(now);
s.mType.Construct(RTCStatsType::Candidatepair);
s.mLocalCandidateId.Construct(localCodeword);
s.mRemoteCandidateId.Construct(remoteCodeword);
s.mNominated.Construct(p->nominated);
s.mMozPriority.Construct(p->priority);
s.mSelected.Construct(p->selected);
s.mState.Construct(RTCStatsIceCandidatePairState(p->state));
report->mIceCandidatePairStats.Value().AppendElement(s);
}
{
RTCIceCandidateStats local;
local.mComponentId.Construct(componentId);
local.mId.Construct(localCodeword);
local.mTimestamp.Construct(now);
local.mType.Construct(RTCStatsType::Localcandidate);
local.mCandidateType.Construct(
RTCStatsIceCandidateType(p->local.type));
local.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->local.cand_addr.host.c_str()));
local.mPortNumber.Construct(p->local.cand_addr.port);
report->mIceCandidateStats.Value().AppendElement(local);
}
{
RTCIceCandidateStats remote;
remote.mComponentId.Construct(componentId);
remote.mId.Construct(remoteCodeword);
remote.mTimestamp.Construct(now);
remote.mType.Construct(RTCStatsType::Remotecandidate);
remote.mCandidateType.Construct(
RTCStatsIceCandidateType(p->remote.type));
remote.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->remote.cand_addr.host.c_str()));
remote.mPortNumber.Construct(p->remote.cand_addr.port);
report->mIceCandidateStats.Value().AppendElement(remote);
}
}
}
void PeerConnectionImpl::GetStats_s(
const std::string& pcHandle, // The Runnable holds the memory
const std::string& pcName, // The Runnable holds the memory
nsCOMPtr<nsIThread> callbackThread,
bool internalStats,
const std::vector<RefPtr<MediaPipeline>>& pipelines,
const RefPtr<NrIceCtx>& iceCtx,
const std::vector<RefPtr<NrIceMediaStream>>& streams,
DOMHighResTimeStamp now) { DOMHighResTimeStamp now) {
nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternalConstruct( // We do not use the pcHandle here, since that's risky to expose to content.
NS_ConvertASCIItoUTF16(mHandle.c_str()), now)); nsAutoPtr<RTCStatsReportInternal> report(
new RTCStatsReportInternalConstruct(
NS_ConvertASCIItoUTF16(pcName.c_str()),
now));
nsresult rv = report ? GetStatsImpl_s(trackId, internalStats, pipelines, now, nsresult rv = GetStatsImpl_s(internalStats,
report) pipelines,
: NS_ERROR_UNEXPECTED; iceCtx,
streams,
now,
report);
nsRefPtr<PeerConnectionImpl> pc(this); RUN_ON_THREAD(callbackThread,
RUN_ON_THREAD(mThread, WrapRunnableNM(&PeerConnectionImpl::OnStatsReport_m,
WrapRunnable(pc, pcHandle,
&PeerConnectionImpl::OnStatsReport_m, rv,
rv, pipelines, // return for release on main thread
pipelines, // return for release on main thread report),
report),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
void PeerConnectionImpl::OnStatsReport_m( void PeerConnectionImpl::OnStatsReport_m(
const std::string& pcHandle,
nsresult result, nsresult result,
nsAutoPtr<std::vector<RefPtr<MediaPipeline>>> pipelines, //returned for release const std::vector<RefPtr<MediaPipeline>>& pipelines, //returned for release
nsAutoPtr<RTCStatsReportInternal> report) { nsAutoPtr<RTCStatsReportInternal> report) {
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (pco) {
JSErrorResult rv;
if (NS_SUCCEEDED(result)) {
pco->OnGetStatsSuccess(*report, rv);
} else {
pco->OnGetStatsError(kInternalError,
ObString("Failed to fetch statistics"),
rv);
}
if (rv.Failed()) { // Is the PeerConnectionImpl still around?
CSFLogError(logTag, "Error firing stats observer callback"); PeerConnectionWrapper pcw(pcHandle);
if (pcw.impl()) {
nsRefPtr<PeerConnectionObserver> pco =
do_QueryObjectReferent(pcw.impl()->mPCObserver);
if (pco) {
JSErrorResult rv;
if (NS_SUCCEEDED(result)) {
pco->OnGetStatsSuccess(*report, rv);
} else {
pco->OnGetStatsError(kInternalError,
ObString("Failed to fetch statistics"),
rv);
}
if (rv.Failed()) {
CSFLogError(logTag, "Error firing stats observer callback");
}
} }
} }
} }
void PeerConnectionImpl::GetLogging_s(const std::string& pattern) { void PeerConnectionImpl::GetLogging_s(const std::string& pcHandle,
nsCOMPtr<nsIThread> callbackThread,
const std::string& pattern) {
RLogRingBuffer* logs = RLogRingBuffer::GetInstance(); RLogRingBuffer* logs = RLogRingBuffer::GetInstance();
std::deque<std::string> result; nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
logs->Filter(pattern, 0, &result); logs->Filter(pattern, 0, result);
nsRefPtr<PeerConnectionImpl> pc(this); RUN_ON_THREAD(callbackThread,
RUN_ON_THREAD(mThread, WrapRunnableNM(&PeerConnectionImpl::OnGetLogging_m,
WrapRunnable(pc, pcHandle,
&PeerConnectionImpl::OnGetLogging_m, pattern,
pattern, result),
result),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
void PeerConnectionImpl::OnGetLogging_m(const std::string& pattern, void PeerConnectionImpl::OnGetLogging_m(
const std::deque<std::string>& logging) { const std::string& pcHandle,
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver); const std::string& pattern,
if (!pco) { nsAutoPtr<std::deque<std::string>> logging) {
return;
}
JSErrorResult rv; // Is the PeerConnectionImpl still around?
if (!logging.empty()) { PeerConnectionWrapper pcw(pcHandle);
Sequence<nsString> nsLogs; if (pcw.impl()) {
for (auto l = logging.begin(); l != logging.end(); ++l) { nsRefPtr<PeerConnectionObserver> pco =
nsLogs.AppendElement(ObString(l->c_str())); do_QueryObjectReferent(pcw.impl()->mPCObserver);
if (pco) {
JSErrorResult rv;
if (!logging->empty()) {
Sequence<nsString> nsLogs;
for (auto l = logging->begin(); l != logging->end(); ++l) {
nsLogs.AppendElement(ObString(l->c_str()));
}
pco->OnGetLoggingSuccess(nsLogs, rv);
} else {
pco->OnGetLoggingError(kInternalError,
ObString(("No logging matching pattern " + pattern).c_str()), rv);
}
if (rv.Failed()) {
CSFLogError(logTag, "Error firing stats observer callback");
}
} }
pco->OnGetLoggingSuccess(nsLogs, rv);
} else {
pco->OnGetLoggingError(kInternalError,
ObString(("No logging matching pattern " + pattern).c_str()), rv);
}
if (rv.Failed()) {
CSFLogError(logTag, "Error firing stats observer callback");
} }
} }
#endif #endif
void void

View File

@ -223,6 +223,9 @@ public:
// Handle system to allow weak references to be passed through C code // Handle system to allow weak references to be passed through C code
virtual const std::string& GetHandle(); virtual const std::string& GetHandle();
// Name suitable for exposing to content
virtual const std::string& GetName();
// ICE events // ICE events
void IceConnectionStateChange(NrIceCtx* ctx, void IceConnectionStateChange(NrIceCtx* ctx,
NrIceCtx::ConnectionState state); NrIceCtx::ConnectionState state);
@ -540,32 +543,51 @@ private:
#ifdef MOZILLA_INTERNAL_API #ifdef MOZILLA_INTERNAL_API
// TODO(bcampen@mozilla.com): Once the dust settles on this stuff, it
// probably makes sense to make these static in PeerConnectionImpl.cpp
// (ie; stop exporting them)
// Fills in an RTCStatsReportInternal. Must be run on STS. // Fills in an RTCStatsReportInternal. Must be run on STS.
void GetStats_s( static void GetStats_s(
mozilla::TrackID trackId, const std::string& pcHandle,
const std::string& pcName,
nsCOMPtr<nsIThread> callbackThread,
bool internalStats, bool internalStats,
nsAutoPtr<std::vector<mozilla::RefPtr<mozilla::MediaPipeline>>> pipelines, const std::vector<mozilla::RefPtr<mozilla::MediaPipeline>> &pipelines,
const mozilla::RefPtr<NrIceCtx> &iceCtx,
const std::vector<mozilla::RefPtr<NrIceMediaStream>> &streams,
DOMHighResTimeStamp now); DOMHighResTimeStamp now);
nsresult GetStatsImpl_s( static nsresult GetStatsImpl_s(
mozilla::TrackID trackId,
bool internalStats, bool internalStats,
nsAutoPtr<std::vector<mozilla::RefPtr<mozilla::MediaPipeline>>> pipelines, const std::vector<mozilla::RefPtr<mozilla::MediaPipeline>> &pipelines,
const mozilla::RefPtr<NrIceCtx> &iceCtx,
const std::vector<mozilla::RefPtr<NrIceMediaStream>> &streams,
DOMHighResTimeStamp now, DOMHighResTimeStamp now,
mozilla::dom::RTCStatsReportInternal *report); mozilla::dom::RTCStatsReportInternal *report);
static void FillStatsReport_s(
NrIceMediaStream& stream,
bool internalStats,
DOMHighResTimeStamp now,
mozilla::dom::RTCStatsReportInternal* stats);
// Sends an RTCStatsReport to JS. Must run on main thread. // Sends an RTCStatsReport to JS. Must run on main thread.
void OnStatsReport_m( static void OnStatsReport_m(
const std::string& pcHandle,
nsresult result, nsresult result,
nsAutoPtr<std::vector<mozilla::RefPtr<mozilla::MediaPipeline>>> pipelines, const std::vector<mozilla::RefPtr<mozilla::MediaPipeline>> &pipelines,
nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report); nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report);
// Fetches logs matching pattern from RLogRingBuffer. Must be run on STS. // Fetches logs matching pattern from RLogRingBuffer. Must be run on STS.
void GetLogging_s(const std::string& pattern); static void GetLogging_s(const std::string& pcHandle,
nsCOMPtr<nsIThread> callbackThread,
const std::string& pattern);
// Sends logging to JS. Must run on main thread. // Sends logging to JS. Must run on main thread.
void OnGetLogging_m(const std::string& pattern, static void OnGetLogging_m(const std::string& pcHandle,
const std::deque<std::string>& logging); const std::string& pattern,
nsAutoPtr<std::deque<std::string>> logging);
#endif #endif
// Timecard used to measure processing time. This should be the first class // Timecard used to measure processing time. This should be the first class
@ -605,6 +627,9 @@ private:
// A handle to refer to this PC with // A handle to refer to this PC with
std::string mHandle; std::string mHandle;
// A name for this PC that we are willing to expose to content.
std::string mName;
// The target to run stuff on // The target to run stuff on
nsCOMPtr<nsIEventTarget> mSTSThread; nsCOMPtr<nsIEventTarget> mSTSThread;

View File

@ -148,7 +148,7 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
{ {
// TODO(ekr@rtfm.com): need some way to set not offerer later // TODO(ekr@rtfm.com): need some way to set not offerer later
// Looks like a bug in the NrIceCtx API. // Looks like a bug in the NrIceCtx API.
mIceCtx = NrIceCtx::Create("PC:" + mParent->GetHandle(), true); mIceCtx = NrIceCtx::Create("PC:" + mParent->GetName(), true);
if(!mIceCtx) { if(!mIceCtx) {
CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__); CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -191,11 +191,11 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
// One each for audio, video and DataChannel // One each for audio, video and DataChannel
// TODO: this will be re-visited // TODO: this will be re-visited
RefPtr<NrIceMediaStream> audioStream = RefPtr<NrIceMediaStream> audioStream =
mIceCtx->CreateStream((mParent->GetHandle()+"/stream1/audio").c_str(), 2); mIceCtx->CreateStream((mParent->GetName()+": stream1/audio").c_str(), 2);
RefPtr<NrIceMediaStream> videoStream = RefPtr<NrIceMediaStream> videoStream =
mIceCtx->CreateStream((mParent->GetHandle()+"/stream2/video").c_str(), 2); mIceCtx->CreateStream((mParent->GetName()+": stream2/video").c_str(), 2);
RefPtr<NrIceMediaStream> dcStream = RefPtr<NrIceMediaStream> dcStream =
mIceCtx->CreateStream((mParent->GetHandle()+"/stream3/data").c_str(), 2); mIceCtx->CreateStream((mParent->GetName()+": stream3/data").c_str(), 2);
if (!audioStream) { if (!audioStream) {
CSFLogError(logTag, "%s: audio stream is NULL", __FUNCTION__); CSFLogError(logTag, "%s: audio stream is NULL", __FUNCTION__);

View File

@ -197,6 +197,7 @@ class TestAgentSend : public TestAgent {
test_utils->sts_target(), test_utils->sts_target(),
audio_, audio_,
1, 1,
1,
audio_conduit_, audio_conduit_,
audio_rtp_transport_.flow_, audio_rtp_transport_.flow_,
audio_rtcp_transport_.flow_); audio_rtcp_transport_.flow_);
@ -246,7 +247,7 @@ class TestAgentReceive : public TestAgent {
test_pc, test_pc,
nullptr, nullptr,
test_utils->sts_target(), test_utils->sts_target(),
audio_->GetStream(), 1, audio_->GetStream(), 1, 1,
static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()), static_cast<mozilla::AudioSessionConduit *>(audio_conduit_.get()),
audio_rtp_transport_.flow_, audio_rtcp_transport_.flow_); audio_rtp_transport_.flow_, audio_rtcp_transport_.flow_);