From 487a4442152e2c70146aa2d2c6ccb370233c056c Mon Sep 17 00:00:00 2001 From: "decurtis@webrtc.org" Date: Thu, 15 Jan 2015 22:55:07 +0000 Subject: [PATCH] Add stats collection for the data channel. BUG=1805 R=bemasc@chromium.org, hta@webrtc.org, pthatcher@webrtc.org, tommi@webrtc.org Review URL: https://webrtc-codereview.appspot.com/34619004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@8083 4adac7df-926f-26a2-2b94-8c16560cd09d --- talk/app/webrtc/datachannelinterface.h | 16 ++++ talk/app/webrtc/mediastreamsignaling.h | 7 +- talk/app/webrtc/statscollector.cc | 26 ++++- talk/app/webrtc/statscollector.h | 4 +- talk/app/webrtc/statscollector_unittest.cc | 106 +++++++++++++++++---- talk/app/webrtc/statstypes.cc | 9 ++ talk/app/webrtc/statstypes.h | 8 ++ talk/app/webrtc/webrtcsession.h | 4 + 8 files changed, 153 insertions(+), 27 deletions(-) diff --git a/talk/app/webrtc/datachannelinterface.h b/talk/app/webrtc/datachannelinterface.h index 5684cc242..eb8a0b7b5 100644 --- a/talk/app/webrtc/datachannelinterface.h +++ b/talk/app/webrtc/datachannelinterface.h @@ -35,6 +35,7 @@ #include "webrtc/base/basictypes.h" #include "webrtc/base/buffer.h" +#include "webrtc/base/checks.h" #include "webrtc/base/refcount.h" @@ -106,6 +107,21 @@ class DataChannelInterface : public rtc::RefCountInterface { kClosed }; + static const char* DataStateString(DataState state) { + switch (state) { + case kConnecting: + return "connecting"; + case kOpen: + return "open"; + case kClosing: + return "closing"; + case kClosed: + return "closed"; + } + CHECK(false) << "Unknown DataChannel state: " << state; + return ""; + } + virtual void RegisterObserver(DataChannelObserver* observer) = 0; virtual void UnregisterObserver() = 0; // The label attribute represents a label that can be used to distinguish this diff --git a/talk/app/webrtc/mediastreamsignaling.h b/talk/app/webrtc/mediastreamsignaling.h index d4b1be8e2..7b8cf979b 100644 --- a/talk/app/webrtc/mediastreamsignaling.h +++ b/talk/app/webrtc/mediastreamsignaling.h @@ -162,6 +162,7 @@ class MediaStreamSignaling : public sigslot::has_slots<> { public: typedef std::map > RtpDataChannels; + typedef std::vector> SctpDataChannels; MediaStreamSignaling(rtc::Thread* signaling_thread, MediaStreamSignalingObserver* stream_observer, @@ -255,6 +256,10 @@ class MediaStreamSignaling : public sigslot::has_slots<> { void OnDtlsRoleReadyForSctp(rtc::SSLRole role); void OnRemoteSctpDataChannelClosed(uint32 sid); + const SctpDataChannels& sctp_data_channels() const { + return sctp_data_channels_; + } + private: struct RemotePeerInfo { RemotePeerInfo() @@ -392,8 +397,6 @@ class MediaStreamSignaling : public sigslot::has_slots<> { int last_allocated_sctp_even_sid_; int last_allocated_sctp_odd_sid_; - typedef std::vector > SctpDataChannels; - RtpDataChannels rtp_data_channels_; SctpDataChannels sctp_data_channels_; }; diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc index 1e3a1d92b..05695c04e 100644 --- a/talk/app/webrtc/statscollector.cc +++ b/talk/app/webrtc/statscollector.cc @@ -403,7 +403,8 @@ const char* AdapterTypeToStatsType(rtc::AdapterType type) { } StatsCollector::StatsCollector(WebRtcSession* session) - : session_(session), stats_gathering_started_(0) { + : session_(session), + stats_gathering_started_(0) { ASSERT(session_); } @@ -516,6 +517,7 @@ StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) { ExtractSessionInfo(); ExtractVoiceInfo(); ExtractVideoInfo(level); + ExtractDataInfo(); } } @@ -756,14 +758,16 @@ void StatsCollector::ExtractSessionInfo() { channel_report->timestamp = stats_gathering_started_; channel_report->AddValue(StatsReport::kStatsValueNameComponent, channel_iter->component); - if (!local_cert_report_id.empty()) + if (!local_cert_report_id.empty()) { channel_report->AddValue( StatsReport::kStatsValueNameLocalCertificateId, local_cert_report_id); - if (!remote_cert_report_id.empty()) + } + if (!remote_cert_report_id.empty()) { channel_report->AddValue( StatsReport::kStatsValueNameRemoteCertificateId, remote_cert_report_id); + } for (size_t i = 0; i < channel_iter->connection_infos.size(); ++i) { @@ -880,6 +884,22 @@ void StatsCollector::ExtractVideoInfo( } } +void StatsCollector::ExtractDataInfo() { + ASSERT(session_->signaling_thread()->IsCurrent()); + + for (const auto& dc : + session_->mediastream_signaling()->sctp_data_channels()) { + StatsReport* report = reports_.ReplaceOrAddNew( + StatsId(StatsReport::kStatsReportTypeDataChannel, dc->label())); + report->type = StatsReport::kStatsReportTypeDataChannel; + report->AddValue(StatsReport::kStatsValueNameLabel, dc->label()); + report->AddValue(StatsReport::kStatsValueNameDataChannelId, dc->id()); + report->AddValue(StatsReport::kStatsValueNameProtocol, dc->protocol()); + report->AddValue(StatsReport::kStatsValueNameState, + DataChannelInterface::DataStateString(dc->state())); + } +} + StatsReport* StatsCollector::GetReport(const std::string& type, const std::string& id, TrackDirection direction) { diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h index f8d19c19d..45626af32 100644 --- a/talk/app/webrtc/statscollector.h +++ b/talk/app/webrtc/statscollector.h @@ -36,6 +36,7 @@ #include #include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/peerconnectioninterface.h" #include "talk/app/webrtc/statstypes.h" #include "talk/app/webrtc/webrtcsession.h" @@ -60,7 +61,7 @@ class StatsCollector { // The caller is responsible for ensuring that the session outlives the // StatsCollector instance. - explicit StatsCollector(WebRtcSession* session); + StatsCollector(WebRtcSession* session); virtual ~StatsCollector(); // Adds a MediaStream with tracks that can be used as a |selector| in a call @@ -119,6 +120,7 @@ class StatsCollector { // returns the leaf certificate's report's ID. std::string AddCertificateReports(const rtc::SSLCertificate* cert); + void ExtractDataInfo(); void ExtractSessionInfo(); void ExtractVoiceInfo(); void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level); diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc index 539bf2352..cba400390 100644 --- a/talk/app/webrtc/statscollector_unittest.cc +++ b/talk/app/webrtc/statscollector_unittest.cc @@ -31,11 +31,13 @@ #include "talk/app/webrtc/mediastream.h" #include "talk/app/webrtc/mediastreaminterface.h" +#include "talk/app/webrtc/mediastreamsignaling.h" #include "talk/app/webrtc/mediastreamtrack.h" +#include "talk/app/webrtc/test/fakedatachannelprovider.h" +#include "talk/app/webrtc/test/fakemediastreamsignaling.h" #include "talk/app/webrtc/videotrack.h" #include "talk/media/base/fakemediaengine.h" #include "talk/media/devices/fakedevicemanager.h" -#include "webrtc/p2p/base/fakesession.h" #include "talk/session/media/channelmanager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -43,6 +45,7 @@ #include "webrtc/base/fakesslidentity.h" #include "webrtc/base/gunit.h" #include "webrtc/base/network.h" +#include "webrtc/p2p/base/fakesession.h" using cricket::StatsOptions; using testing::_; @@ -81,6 +84,7 @@ class MockWebRtcSession : public webrtc::WebRtcSession { } MOCK_METHOD0(voice_channel, cricket::VoiceChannel*()); MOCK_METHOD0(video_channel, cricket::VideoChannel*()); + MOCK_CONST_METHOD0(mediastream_signaling, const MediaStreamSignaling*()); // Libjingle uses "local" for a outgoing track, and "remote" for a incoming // track. MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32, std::string*)); @@ -438,9 +442,12 @@ class StatsCollectorTest : public testing::Test { new cricket::ChannelManager(media_engine_, new cricket::FakeDeviceManager(), rtc::Thread::Current())), + signaling_(channel_manager_.get()), session_(channel_manager_.get()) { // By default, we ignore session GetStats calls. EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false)); + EXPECT_CALL(session_, mediastream_signaling()).WillRepeatedly( + Return(&signaling_)); } ~StatsCollectorTest() {} @@ -587,7 +594,8 @@ class StatsCollectorTest : public testing::Test { const std::vector& local_ders, const rtc::FakeSSLCertificate& remote_cert, const std::vector& remote_ders) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. // Fake stats to process. @@ -665,15 +673,53 @@ class StatsCollectorTest : public testing::Test { cricket::FakeMediaEngine* media_engine_; rtc::scoped_ptr channel_manager_; MockWebRtcSession session_; + FakeMediaStreamSignaling signaling_; + FakeDataChannelProvider data_channel_provider_; cricket::SessionStats session_stats_; rtc::scoped_refptr stream_; rtc::scoped_refptr track_; rtc::scoped_refptr audio_track_; }; +// Verify that ExtractDataInfo populates reports. +TEST_F(StatsCollectorTest, ExtractDataInfo) { + const std::string label = "hacks"; + const int id = 31337; + const std::string state = DataChannelInterface::DataStateString( + DataChannelInterface::DataState::kConnecting); + + EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); + EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); + + InternalDataChannelInit config; + config.id = id; + signaling_.AddDataChannel(DataChannel::Create( + &data_channel_provider_, cricket::DCT_SCTP, label, config)); + webrtc::StatsCollector stats(&session_); + + stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); + + StatsReports reports; + stats.GetStats(NULL, &reports); + EXPECT_EQ(label, ExtractStatsValue(StatsReport::kStatsReportTypeDataChannel, + reports, + StatsReport::kStatsValueNameLabel)); + EXPECT_EQ(rtc::ToString(id), + ExtractStatsValue(StatsReport::kStatsReportTypeDataChannel, + reports, + StatsReport::kStatsValueNameDataChannelId)); + EXPECT_EQ(state, ExtractStatsValue(StatsReport::kStatsReportTypeDataChannel, + reports, + StatsReport::kStatsValueNameState)); + EXPECT_EQ("", ExtractStatsValue(StatsReport::kStatsReportTypeDataChannel, + reports, + StatsReport::kStatsValueNameProtocol)); +} + // This test verifies that 64-bit counters are passed successfully. TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -706,7 +752,8 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) { // Test that BWE information is reported via stats. TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -750,7 +797,8 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) { // This test verifies that an object of type "googSession" always // exists in the returned stats. TEST_F(StatsCollectorTest, SessionObjectExists) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); @@ -764,7 +812,8 @@ TEST_F(StatsCollectorTest, SessionObjectExists) { // This test verifies that only one object of type "googSession" exists // in the returned stats. TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); @@ -782,7 +831,8 @@ TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) { // This test verifies that the empty track report exists in the returned stats // without calling StatsCollector::UpdateStats. TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -806,7 +856,8 @@ TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) { // This test verifies that the empty track report exists in the returned stats // when StatsCollector::UpdateStats is called with ssrc stats. TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -861,7 +912,8 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) { // This test verifies that an SSRC object has the identifier of a Transport // stats object, and that this transport stats object exists in stats. TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -910,7 +962,8 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) { // This test verifies that a remote stats object will not be created for // an outgoing SSRC where remote stats are not returned. TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); // The content_name known by the video channel. const std::string kVcName("vcname"); @@ -933,7 +986,8 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) { // This test verifies that a remote stats object will be created for // an outgoing SSRC where stats are returned. TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -981,7 +1035,8 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) { // This test verifies that the empty track report exists in the returned stats // when StatsCollector::UpdateStats is called with ssrc stats. TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -1026,7 +1081,8 @@ TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) { // This test verifies the Ice Candidate report should contain the correct // information from local/remote candidates. TEST_F(StatsCollectorTest, IceCandidateReport) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. const int local_port = 2000; @@ -1157,7 +1213,8 @@ TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) { // This test verifies that the stats are generated correctly when no // transport is present. TEST_F(StatsCollectorTest, NoTransport) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. // Fake stats to process. @@ -1203,7 +1260,8 @@ TEST_F(StatsCollectorTest, NoTransport) { // This test verifies that the stats are generated correctly when the transport // does not have any certificates. TEST_F(StatsCollectorTest, NoCertificates) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + StatsReports reports; // returned values. // Fake stats to process. @@ -1271,7 +1329,8 @@ TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) { // Verifies the correct optons are passed to the VideoMediaChannel when using // verbose output level. TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); cricket::VideoChannel video_channel(rtc::Thread::Current(), media_engine_, media_channel, &session_, "", false, NULL); @@ -1316,7 +1375,8 @@ TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) { // This test verifies that a local stats object can get statistics via // AudioTrackInterface::GetStats() method. TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -1349,7 +1409,8 @@ TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) { // This test verifies that audio receive streams populate stats reports // correctly. TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -1375,7 +1436,8 @@ TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) { // This test verifies that a local stats object won't update its statistics // after a RemoveLocalAudioTrack() call. TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -1432,7 +1494,8 @@ TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) { // This test verifies that when ongoing and incoming audio tracks are using // the same ssrc, they populate stats reports correctly. TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); @@ -1514,7 +1577,8 @@ TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) { // TODO(xians): Figure out if it is possible to encapsulate the setup and // avoid duplication of code in test cases. TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) { - webrtc::StatsCollector stats(&session_); // Implementation under test. + webrtc::StatsCollector stats(&session_); + // Ignore unused callback (logspam). EXPECT_CALL(session_, GetTransport(_)) .WillRepeatedly(Return(static_cast(NULL))); diff --git a/talk/app/webrtc/statstypes.cc b/talk/app/webrtc/statstypes.cc index fd96b1070..b15dba5d2 100644 --- a/talk/app/webrtc/statstypes.cc +++ b/talk/app/webrtc/statstypes.cc @@ -41,6 +41,7 @@ const char StatsReport::kStatsReportTypeTransport[] = "googTransport"; const char StatsReport::kStatsReportTypeComponent[] = "googComponent"; const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair"; const char StatsReport::kStatsReportTypeCertificate[] = "googCertificate"; +const char StatsReport::kStatsReportTypeDataChannel[] = "datachannel"; const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo"; @@ -109,14 +110,22 @@ const char* StatsReport::Value::display_name() const { return "packetsSent"; case kStatsValueNameBytesReceived: return "bytesReceived"; + case kStatsValueNameLabel: + return "label"; case kStatsValueNamePacketsReceived: return "packetsReceived"; case kStatsValueNamePacketsLost: return "packetsLost"; + case kStatsValueNameProtocol: + return "protocol"; case kStatsValueNameTransportId: return "transportId"; case kStatsValueNameSsrc: return "ssrc"; + case kStatsValueNameState: + return "state"; + case kStatsValueNameDataChannelId: + return "datachannelid"; // 'goog' prefixed constants. case kStatsValueNameActiveConnection: diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h index bca771c37..15a12d892 100644 --- a/talk/app/webrtc/statstypes.h +++ b/talk/app/webrtc/statstypes.h @@ -79,11 +79,14 @@ class StatsReport { kStatsValueNameAudioOutputLevel, kStatsValueNameBytesReceived, kStatsValueNameBytesSent, + kStatsValueNameDataChannelId, kStatsValueNamePacketsLost, kStatsValueNamePacketsReceived, kStatsValueNamePacketsSent, + kStatsValueNameProtocol, kStatsValueNameReadable, kStatsValueNameSsrc, + kStatsValueNameState, kStatsValueNameTransportId, // Internal StatsValue names. @@ -143,6 +146,7 @@ class StatsReport { kStatsValueNameIssuerId, kStatsValueNameJitterBufferMs, kStatsValueNameJitterReceived, + kStatsValueNameLabel, kStatsValueNameLocalAddress, kStatsValueNameLocalCandidateId, kStatsValueNameLocalCandidateType, @@ -262,6 +266,10 @@ class StatsReport { // The id of StatsReport of type VideoBWE. static const char kStatsReportVideoBweId[]; + + // A StatsReport of |type| = "datachannel" with statistics for a + // particular DataChannel. + static const char kStatsReportTypeDataChannel[]; }; // This class is provided for the cases where we need to keep diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h index 1d8281cc5..e3f71a5c2 100644 --- a/talk/app/webrtc/webrtcsession.h +++ b/talk/app/webrtc/webrtcsession.h @@ -137,6 +137,10 @@ class WebRtcSession : public cricket::BaseSession, return data_channel_.get(); } + virtual const MediaStreamSignaling* mediastream_signaling() const { + return mediastream_signaling_; + } + void SetSdesPolicy(cricket::SecurePolicy secure_policy); cricket::SecurePolicy SdesPolicy() const;