Bug 1218356 - P2 - Implement the RTCDataChannel stats;r=dminor

Note that transportId is not implemented and is not a stat but a key back into
the stats report. It identifies the related transport stats object. We don't
have transport stats, so this can not be implemented at the moment.

Differential Revision: https://phabricator.services.mozilla.com/D57116
This commit is contained in:
Nico Grunbaum 2020-05-29 10:46:42 +00:00
Родитель ee658e6245
Коммит 46b83b6604
4 изменённых файлов: 138 добавлений и 7 удалений

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

@ -2567,6 +2567,29 @@ RefPtr<dom::RTCStatsPromise> PeerConnectionImpl::GetSenderStats(
});
}
static UniquePtr<dom::RTCStatsCollection> GetDataChannelStats_s(
const RefPtr<DataChannelConnection>& aDataConnection,
const DOMHighResTimeStamp aTimestamp) {
UniquePtr<dom::RTCStatsCollection> report(new dom::RTCStatsCollection);
if (aDataConnection) {
aDataConnection->AppendStatsToReport(report, aTimestamp);
}
return report;
}
RefPtr<dom::RTCStatsPromise> PeerConnectionImpl::GetDataChannelStats(
const RefPtr<DataChannelConnection>& aDataChannelConnection,
const DOMHighResTimeStamp aTimestamp) {
// Gather stats from DataChannels
return InvokeAsync(
GetMainThreadSerialEventTarget(), __func__,
[aDataChannelConnection, aTimestamp]() {
return dom::RTCStatsPromise::CreateAndResolve(
GetDataChannelStats_s(aDataChannelConnection, aTimestamp),
__func__);
});
}
void PeerConnectionImpl::RecordConduitTelemetry() {
if (!mMedia) {
return;
@ -2663,6 +2686,8 @@ RefPtr<dom::RTCStatsReportPromise> PeerConnectionImpl::GetStats(
} else {
promises.AppendElement(mTransportHandler->GetIceStats("", now));
}
promises.AppendElement(GetDataChannelStats(mDataConnection, now));
}
// This is what we're going to return; all the stuff in |promises| will be
@ -2760,6 +2785,8 @@ RefPtr<dom::RTCStatsReportPromise> PeerConnectionImpl::GetStats(
report->mRtpContributingSourceStats, idGen);
AssignWithOpaqueIds(stats->mTrickledIceCandidateStats,
report->mTrickledIceCandidateStats, idGen);
AssignWithOpaqueIds(stats->mDataChannelStats,
report->mDataChannelStats, idGen);
if (!report->mRawLocalCandidates.AppendElements(
stats->mRawLocalCandidates, fallible) ||
!report->mRawRemoteCandidates.AppendElements(

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

@ -450,6 +450,9 @@ class PeerConnectionImpl final
const RefPtr<MediaPipelineReceive>& aPipeline);
RefPtr<dom::RTCStatsPromise> GetSenderStats(
const RefPtr<MediaPipelineTransmit>& aPipeline);
RefPtr<dom::RTCStatsPromise> GetDataChannelStats(
const RefPtr<DataChannelConnection>& aDataChannelConnection,
const DOMHighResTimeStamp aTimestamp);
nsresult CalculateFingerprint(const std::string& algorithm,
std::vector<uint8_t>* fingerprint) const;
nsresult ConfigureJsepSessionCodecs();

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

@ -43,9 +43,12 @@
#include "nsThreadUtils.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "mozilla/RandomNum.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/RTCDataChannelBinding.h"
#include "mozilla/dom/RTCStatsReportBinding.h"
#ifdef MOZ_PEERCONNECTION
# include "mtransport/runnable_utils.h"
# include "signaling/src/peerconnection/MediaTransportHandler.h"
@ -648,6 +651,60 @@ void DataChannelConnection::SetMaxMessageSize(bool aMaxMessageSizeSet,
uint64_t DataChannelConnection::GetMaxMessageSize() { return mMaxMessageSize; }
void DataChannelConnection::AppendStatsToReport(
const UniquePtr<dom::RTCStatsCollection>& aReport,
const DOMHighResTimeStamp aTimestamp) const {
ASSERT_WEBRTC(NS_IsMainThread());
nsString temp;
for (const RefPtr<DataChannel>& chan : mChannels.GetAll()) {
// If channel is empty, ignore
if (!chan) {
continue;
}
mozilla::dom::RTCDataChannelStats stats;
nsString id = NS_LITERAL_STRING("dc");
id.AppendInt(chan->GetStream());
stats.mId.Construct(id);
chan->GetLabel(temp);
stats.mTimestamp.Construct(aTimestamp);
stats.mType.Construct(mozilla::dom::RTCStatsType::Data_channel);
stats.mLabel.Construct(temp);
chan->GetProtocol(temp);
stats.mProtocol.Construct(temp);
stats.mDataChannelIdentifier.Construct(chan->GetStream());
{
using State = mozilla::dom::RTCDataChannelState;
State state;
switch (chan->GetReadyState()) {
case CONNECTING:
state = State::Connecting;
break;
case OPEN:
state = State::Open;
break;
case CLOSING:
state = State::Closing;
break;
case CLOSED:
state = State::Closed;
break;
default:
MOZ_ASSERT(false, "Unknown DataChannel state");
continue;
};
stats.mState.Construct(state);
}
auto counters = chan->GetTrafficCounters();
stats.mMessagesSent.Construct(counters.mMessagesSent);
stats.mBytesSent.Construct(counters.mBytesSent);
stats.mMessagesReceived.Construct(counters.mMessagesReceived);
stats.mBytesReceived.Construct(counters.mBytesReceived);
if (!aReport->mDataChannelStats.AppendElement(stats, fallible)) {
mozalloc_handle_oom(0);
}
}
}
#ifdef MOZ_PEERCONNECTION
bool DataChannelConnection::ConnectToTransport(const std::string& aTransportId,
@ -1697,6 +1754,12 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
return;
}
channel->WithTrafficCounters(
[&data_length](DataChannel::TrafficCounters& counters) {
counters.mMessagesReceived++;
counters.mBytesReceived += data_length;
});
// Notify onmessage
DC_DEBUG(("%s: sending ON_DATA_%s%s for %p", __FUNCTION__,
(type == DataChannelOnMessageAvailable::ON_DATA_STRING) ? "STRING"
@ -2890,13 +2953,22 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream,
}
auto& channel = *channelPtr;
int err = 0;
if (isBinary) {
return SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_BINARY_PARTIAL,
DATA_CHANNEL_PPID_BINARY);
err = SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_BINARY_PARTIAL,
DATA_CHANNEL_PPID_BINARY);
} else {
err = SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_DOMSTRING_PARTIAL,
DATA_CHANNEL_PPID_DOMSTRING);
}
return SendDataMsg(channel, data, len, DATA_CHANNEL_PPID_DOMSTRING_PARTIAL,
DATA_CHANNEL_PPID_DOMSTRING);
if (!err) {
channel.WithTrafficCounters([&len](DataChannel::TrafficCounters& counters) {
counters.mMessagesSent++;
counters.mBytesSent += len;
});
}
return err;
}
void DataChannelConnection::Stop() {
@ -3266,6 +3338,11 @@ void DataChannel::SendOrQueue(DataChannelOnMessageAvailable* aMessage) {
mMainThreadEventTarget->Dispatch(runnable.forget());
}
DataChannel::TrafficCounters DataChannel::GetTrafficCounters() const {
MutexAutoLock lock(mStatsLock);
return mTrafficCounters;
}
bool DataChannel::EnsureValidStream(ErrorResult& aRv) {
MOZ_ASSERT(mConnection);
if (mConnection && mStream != INVALID_STREAM) {
@ -3275,4 +3352,10 @@ bool DataChannel::EnsureValidStream(ErrorResult& aRv) {
return false;
}
void DataChannel::WithTrafficCounters(
const std::function<void(TrafficCounters&)>& aFn) {
MutexAutoLock lock(mStatsLock);
aFn(mTrafficCounters);
}
} // namespace mozilla

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

@ -51,6 +51,9 @@ class DataChannel;
class DataChannelOnMessageAvailable;
class MediaPacket;
class MediaTransportHandler;
namespace dom {
struct RTCStatsCollection;
};
// For sending outgoing messages.
// This class only holds a reference to the data and the info structure but does
@ -153,6 +156,8 @@ class DataChannelConnection final : public net::NeckoTargetHolder
void SetMaxMessageSize(bool aMaxMessageSizeSet, uint64_t aMaxMessageSize);
uint64_t GetMaxMessageSize();
void AppendStatsToReport(const UniquePtr<dom::RTCStatsCollection>& aReport,
const DOMHighResTimeStamp aTimestamp) const;
#ifdef ALLOW_DIRECT_SCTP_LISTEN_CONNECT
// These block; they require something to decide on listener/connector
// (though you can do simultaneous Connect()). Do not call these from
@ -305,7 +310,7 @@ class DataChannelConnection final : public net::NeckoTargetHolder
void HandleNotification(const union sctp_notification* notif, size_t n);
#ifdef SCTP_DTLS_SUPPORTED
bool IsSTSThread() {
bool IsSTSThread() const {
bool on = false;
if (mSTS) {
mSTS->IsOnCurrentThread(&on);
@ -426,7 +431,8 @@ class DataChannel {
mIsRecvBinary(false),
mBufferedThreshold(0), // default from spec
mBufferedAmount(0),
mMainThreadEventTarget(connection->GetNeckoTarget()) {
mMainThreadEventTarget(connection->GetNeckoTarget()),
mStatsLock("netwer::sctp::DataChannel::mStatsLock") {
NS_ASSERTION(mConnection, "NULL connection");
}
@ -508,6 +514,15 @@ class DataChannel {
void SendOrQueue(DataChannelOnMessageAvailable* aMessage);
struct TrafficCounters {
uint32_t mMessagesSent = 0;
uint64_t mBytesSent = 0;
uint32_t mMessagesReceived = 0;
uint64_t mBytesReceived = 0;
};
TrafficCounters GetTrafficCounters() const;
protected:
// These are both mainthread only
DataChannelListener* mListener;
@ -516,6 +531,7 @@ class DataChannel {
private:
nsresult AddDataToBinaryMsg(const char* data, uint32_t size);
bool EnsureValidStream(ErrorResult& aRv);
void WithTrafficCounters(const std::function<void(TrafficCounters&)>&);
RefPtr<DataChannelConnection> mConnection;
nsCString mLabel;
@ -538,6 +554,8 @@ class DataChannel {
nsTArray<UniquePtr<BufferedOutgoingMsg>>
mBufferedData; // GUARDED_BY(mConnection->mLock)
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
mutable Mutex mStatsLock; // protects mTrafficCounters
TrafficCounters mTrafficCounters;
};
// used to dispatch notifications of incoming data to the main thread