1/* 2 * libjingle 3 * Copyright 2014, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <stdio.h> 29 30#include "talk/app/webrtc/statscollector.h" 31 32#include "talk/app/webrtc/mediastream.h" 33#include "talk/app/webrtc/mediastreaminterface.h" 34#include "talk/app/webrtc/mediastreamtrack.h" 35#include "talk/app/webrtc/videotrack.h" 36#include "talk/media/base/fakemediaengine.h" 37#include "talk/media/devices/fakedevicemanager.h" 38#include "talk/p2p/base/fakesession.h" 39#include "talk/session/media/channelmanager.h" 40#include "testing/gmock/include/gmock/gmock.h" 41#include "testing/gtest/include/gtest/gtest.h" 42#include "webrtc/base/base64.h" 43#include "webrtc/base/fakesslidentity.h" 44#include "webrtc/base/gunit.h" 45 46using cricket::StatsOptions; 47using testing::_; 48using testing::DoAll; 49using testing::Field; 50using testing::Return; 51using testing::ReturnNull; 52using testing::SetArgPointee; 53using webrtc::PeerConnectionInterface; 54using webrtc::StatsReport; 55using webrtc::StatsReports; 56 57namespace cricket { 58 59class ChannelManager; 60class FakeDeviceManager; 61 62} // namespace cricket 63 64namespace { 65 66// Error return values 67const char kNotFound[] = "NOT FOUND"; 68const char kNoReports[] = "NO REPORTS"; 69 70// Constant names for track identification. 71const char kLocalTrackId[] = "local_track_id"; 72const char kRemoteTrackId[] = "remote_track_id"; 73const uint32 kSsrcOfTrack = 1234; 74 75class MockWebRtcSession : public webrtc::WebRtcSession { 76 public: 77 explicit MockWebRtcSession(cricket::ChannelManager* channel_manager) 78 : WebRtcSession(channel_manager, rtc::Thread::Current(), 79 rtc::Thread::Current(), NULL, NULL) { 80 } 81 MOCK_METHOD0(voice_channel, cricket::VoiceChannel*()); 82 MOCK_METHOD0(video_channel, cricket::VideoChannel*()); 83 // Libjingle uses "local" for a outgoing track, and "remote" for a incoming 84 // track. 85 MOCK_METHOD2(GetLocalTrackIdBySsrc, bool(uint32, std::string*)); 86 MOCK_METHOD2(GetRemoteTrackIdBySsrc, bool(uint32, std::string*)); 87 MOCK_METHOD1(GetStats, bool(cricket::SessionStats*)); 88 MOCK_METHOD1(GetTransport, cricket::Transport*(const std::string&)); 89}; 90 91class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel { 92 public: 93 MockVideoMediaChannel() 94 : cricket::FakeVideoMediaChannel(NULL) { 95 } 96 // MOCK_METHOD0(transport_channel, cricket::TransportChannel*()); 97 MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*)); 98}; 99 100class MockVoiceMediaChannel : public cricket::FakeVoiceMediaChannel { 101 public: 102 MockVoiceMediaChannel() : cricket::FakeVoiceMediaChannel(NULL) { 103 } 104 MOCK_METHOD1(GetStats, bool(cricket::VoiceMediaInfo*)); 105}; 106 107class FakeAudioProcessor : public webrtc::AudioProcessorInterface { 108 public: 109 FakeAudioProcessor() {} 110 ~FakeAudioProcessor() {} 111 112 private: 113 virtual void GetStats( 114 AudioProcessorInterface::AudioProcessorStats* stats) OVERRIDE { 115 stats->typing_noise_detected = true; 116 stats->echo_return_loss = 2; 117 stats->echo_return_loss_enhancement = 3; 118 stats->echo_delay_median_ms = 4; 119 stats->aec_quality_min = 5.1f; 120 stats->echo_delay_std_ms = 6; 121 } 122}; 123 124class FakeAudioTrack 125 : public webrtc::MediaStreamTrack<webrtc::AudioTrackInterface> { 126 public: 127 explicit FakeAudioTrack(const std::string& id) 128 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(id), 129 processor_(new rtc::RefCountedObject<FakeAudioProcessor>()) {} 130 std::string kind() const OVERRIDE { 131 return "audio"; 132 } 133 virtual webrtc::AudioSourceInterface* GetSource() const OVERRIDE { 134 return NULL; 135 } 136 virtual void AddSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {} 137 virtual void RemoveSink(webrtc::AudioTrackSinkInterface* sink) OVERRIDE {} 138 virtual bool GetSignalLevel(int* level) OVERRIDE { 139 *level = 1; 140 return true; 141 } 142 virtual rtc::scoped_refptr<webrtc::AudioProcessorInterface> 143 GetAudioProcessor() OVERRIDE { 144 return processor_; 145 } 146 147 private: 148 rtc::scoped_refptr<FakeAudioProcessor> processor_; 149}; 150 151bool GetValue(const StatsReport* report, 152 StatsReport::StatsValueName name, 153 std::string* value) { 154 StatsReport::Values::const_iterator it = report->values.begin(); 155 for (; it != report->values.end(); ++it) { 156 if (it->name == name) { 157 *value = it->value; 158 return true; 159 } 160 } 161 return false; 162} 163 164std::string ExtractStatsValue(const std::string& type, 165 const StatsReports& reports, 166 StatsReport::StatsValueName name) { 167 if (reports.empty()) { 168 return kNoReports; 169 } 170 for (size_t i = 0; i < reports.size(); ++i) { 171 if (reports[i]->type != type) 172 continue; 173 std::string ret; 174 if (GetValue(reports[i], name, &ret)) { 175 return ret; 176 } 177 } 178 179 return kNotFound; 180} 181 182// Finds the |n|-th report of type |type| in |reports|. 183// |n| starts from 1 for finding the first report. 184const StatsReport* FindNthReportByType( 185 const StatsReports& reports, const std::string& type, int n) { 186 for (size_t i = 0; i < reports.size(); ++i) { 187 if (reports[i]->type == type) { 188 n--; 189 if (n == 0) 190 return reports[i]; 191 } 192 } 193 return NULL; 194} 195 196const StatsReport* FindReportById(const StatsReports& reports, 197 const std::string& id) { 198 for (size_t i = 0; i < reports.size(); ++i) { 199 if (reports[i]->id == id) { 200 return reports[i]; 201 } 202 } 203 return NULL; 204} 205 206std::string ExtractSsrcStatsValue(StatsReports reports, 207 StatsReport::StatsValueName name) { 208 return ExtractStatsValue( 209 StatsReport::kStatsReportTypeSsrc, reports, name); 210} 211 212std::string ExtractBweStatsValue(StatsReports reports, 213 StatsReport::StatsValueName name) { 214 return ExtractStatsValue( 215 StatsReport::kStatsReportTypeBwe, reports, name); 216} 217 218std::string DerToPem(const std::string& der) { 219 return rtc::SSLIdentity::DerToPem( 220 rtc::kPemTypeCertificate, 221 reinterpret_cast<const unsigned char*>(der.c_str()), 222 der.length()); 223} 224 225std::vector<std::string> DersToPems( 226 const std::vector<std::string>& ders) { 227 std::vector<std::string> pems(ders.size()); 228 std::transform(ders.begin(), ders.end(), pems.begin(), DerToPem); 229 return pems; 230} 231 232void CheckCertChainReports(const StatsReports& reports, 233 const std::vector<std::string>& ders, 234 const std::string& start_id) { 235 std::string certificate_id = start_id; 236 size_t i = 0; 237 while (true) { 238 const StatsReport* report = FindReportById(reports, certificate_id); 239 ASSERT_TRUE(report != NULL); 240 241 std::string der_base64; 242 EXPECT_TRUE(GetValue( 243 report, StatsReport::kStatsValueNameDer, &der_base64)); 244 std::string der = rtc::Base64::Decode(der_base64, 245 rtc::Base64::DO_STRICT); 246 EXPECT_EQ(ders[i], der); 247 248 std::string fingerprint_algorithm; 249 EXPECT_TRUE(GetValue( 250 report, 251 StatsReport::kStatsValueNameFingerprintAlgorithm, 252 &fingerprint_algorithm)); 253 // The digest algorithm for a FakeSSLCertificate is always SHA-1. 254 std::string sha_1_str = rtc::DIGEST_SHA_1; 255 EXPECT_EQ(sha_1_str, fingerprint_algorithm); 256 257 std::string dummy_fingerprint; // Value is not checked. 258 EXPECT_TRUE(GetValue( 259 report, 260 StatsReport::kStatsValueNameFingerprint, 261 &dummy_fingerprint)); 262 263 ++i; 264 if (!GetValue( 265 report, StatsReport::kStatsValueNameIssuerId, &certificate_id)) 266 break; 267 } 268 EXPECT_EQ(ders.size(), i); 269} 270 271void VerifyVoiceReceiverInfoReport( 272 const StatsReport* report, 273 const cricket::VoiceReceiverInfo& info) { 274 std::string value_in_report; 275 EXPECT_TRUE(GetValue( 276 report, StatsReport::kStatsValueNameAudioOutputLevel, &value_in_report)); 277 EXPECT_EQ(rtc::ToString<int>(info.audio_level), value_in_report); 278 EXPECT_TRUE(GetValue( 279 report, StatsReport::kStatsValueNameBytesReceived, &value_in_report)); 280 EXPECT_EQ(rtc::ToString<int64>(info.bytes_rcvd), value_in_report); 281 EXPECT_TRUE(GetValue( 282 report, StatsReport::kStatsValueNameJitterReceived, &value_in_report)); 283 EXPECT_EQ(rtc::ToString<int>(info.jitter_ms), value_in_report); 284 EXPECT_TRUE(GetValue( 285 report, StatsReport::kStatsValueNameJitterBufferMs, &value_in_report)); 286 EXPECT_EQ(rtc::ToString<int>(info.jitter_buffer_ms), value_in_report); 287 EXPECT_TRUE(GetValue( 288 report, StatsReport::kStatsValueNamePreferredJitterBufferMs, 289 &value_in_report)); 290 EXPECT_EQ(rtc::ToString<int>(info.jitter_buffer_preferred_ms), 291 value_in_report); 292 EXPECT_TRUE(GetValue( 293 report, StatsReport::kStatsValueNameCurrentDelayMs, &value_in_report)); 294 EXPECT_EQ(rtc::ToString<int>(info.delay_estimate_ms), value_in_report); 295 EXPECT_TRUE(GetValue( 296 report, StatsReport::kStatsValueNameExpandRate, &value_in_report)); 297 EXPECT_EQ(rtc::ToString<float>(info.expand_rate), value_in_report); 298 EXPECT_TRUE(GetValue( 299 report, StatsReport::kStatsValueNamePacketsReceived, &value_in_report)); 300 EXPECT_EQ(rtc::ToString<int>(info.packets_rcvd), value_in_report); 301 EXPECT_TRUE(GetValue( 302 report, StatsReport::kStatsValueNameDecodingCTSG, &value_in_report)); 303 EXPECT_EQ(rtc::ToString<int>(info.decoding_calls_to_silence_generator), 304 value_in_report); 305 EXPECT_TRUE(GetValue( 306 report, StatsReport::kStatsValueNameDecodingCTN, &value_in_report)); 307 EXPECT_EQ(rtc::ToString<int>(info.decoding_calls_to_neteq), 308 value_in_report); 309 EXPECT_TRUE(GetValue( 310 report, StatsReport::kStatsValueNameDecodingNormal, &value_in_report)); 311 EXPECT_EQ(rtc::ToString<int>(info.decoding_normal), value_in_report); 312 EXPECT_TRUE(GetValue( 313 report, StatsReport::kStatsValueNameDecodingPLC, &value_in_report)); 314 EXPECT_EQ(rtc::ToString<int>(info.decoding_plc), value_in_report); 315 EXPECT_TRUE(GetValue( 316 report, StatsReport::kStatsValueNameDecodingCNG, &value_in_report)); 317 EXPECT_EQ(rtc::ToString<int>(info.decoding_cng), value_in_report); 318 EXPECT_TRUE(GetValue( 319 report, StatsReport::kStatsValueNameDecodingPLCCNG, &value_in_report)); 320 EXPECT_EQ(rtc::ToString<int>(info.decoding_plc_cng), value_in_report); 321 EXPECT_TRUE(GetValue( 322 report, StatsReport::kStatsValueNameCodecName, &value_in_report)); 323} 324 325 326void VerifyVoiceSenderInfoReport(const StatsReport* report, 327 const cricket::VoiceSenderInfo& sinfo) { 328 std::string value_in_report; 329 EXPECT_TRUE(GetValue( 330 report, StatsReport::kStatsValueNameCodecName, &value_in_report)); 331 EXPECT_EQ(sinfo.codec_name, value_in_report); 332 EXPECT_TRUE(GetValue( 333 report, StatsReport::kStatsValueNameBytesSent, &value_in_report)); 334 EXPECT_EQ(rtc::ToString<int64>(sinfo.bytes_sent), value_in_report); 335 EXPECT_TRUE(GetValue( 336 report, StatsReport::kStatsValueNamePacketsSent, &value_in_report)); 337 EXPECT_EQ(rtc::ToString<int>(sinfo.packets_sent), value_in_report); 338 EXPECT_TRUE(GetValue( 339 report, StatsReport::kStatsValueNamePacketsLost, &value_in_report)); 340 EXPECT_EQ(rtc::ToString<int>(sinfo.packets_lost), value_in_report); 341 EXPECT_TRUE(GetValue( 342 report, StatsReport::kStatsValueNameRtt, &value_in_report)); 343 EXPECT_EQ(rtc::ToString<int>(sinfo.rtt_ms), value_in_report); 344 EXPECT_TRUE(GetValue( 345 report, StatsReport::kStatsValueNameRtt, &value_in_report)); 346 EXPECT_EQ(rtc::ToString<int>(sinfo.rtt_ms), value_in_report); 347 EXPECT_TRUE(GetValue( 348 report, StatsReport::kStatsValueNameJitterReceived, &value_in_report)); 349 EXPECT_EQ(rtc::ToString<int>(sinfo.jitter_ms), value_in_report); 350 EXPECT_TRUE(GetValue( 351 report, StatsReport::kStatsValueNameEchoCancellationQualityMin, 352 &value_in_report)); 353 EXPECT_EQ(rtc::ToString<float>(sinfo.aec_quality_min), value_in_report); 354 EXPECT_TRUE(GetValue( 355 report, StatsReport::kStatsValueNameEchoDelayMedian, &value_in_report)); 356 EXPECT_EQ(rtc::ToString<int>(sinfo.echo_delay_median_ms), 357 value_in_report); 358 EXPECT_TRUE(GetValue( 359 report, StatsReport::kStatsValueNameEchoDelayStdDev, &value_in_report)); 360 EXPECT_EQ(rtc::ToString<int>(sinfo.echo_delay_std_ms), 361 value_in_report); 362 EXPECT_TRUE(GetValue( 363 report, StatsReport::kStatsValueNameEchoReturnLoss, &value_in_report)); 364 EXPECT_EQ(rtc::ToString<int>(sinfo.echo_return_loss), 365 value_in_report); 366 EXPECT_TRUE(GetValue( 367 report, StatsReport::kStatsValueNameEchoReturnLossEnhancement, 368 &value_in_report)); 369 EXPECT_EQ(rtc::ToString<int>(sinfo.echo_return_loss_enhancement), 370 value_in_report); 371 EXPECT_TRUE(GetValue( 372 report, StatsReport::kStatsValueNameAudioInputLevel, &value_in_report)); 373 EXPECT_EQ(rtc::ToString<int>(sinfo.audio_level), value_in_report); 374 EXPECT_TRUE(GetValue( 375 report, StatsReport::kStatsValueNameTypingNoiseState, &value_in_report)); 376 std::string typing_detected = sinfo.typing_noise_detected ? "true" : "false"; 377 EXPECT_EQ(typing_detected, value_in_report); 378} 379 380// Helper methods to avoid duplication of code. 381void InitVoiceSenderInfo(cricket::VoiceSenderInfo* voice_sender_info) { 382 voice_sender_info->add_ssrc(kSsrcOfTrack); 383 voice_sender_info->codec_name = "fake_codec"; 384 voice_sender_info->bytes_sent = 100; 385 voice_sender_info->packets_sent = 101; 386 voice_sender_info->rtt_ms = 102; 387 voice_sender_info->fraction_lost = 103; 388 voice_sender_info->jitter_ms = 104; 389 voice_sender_info->packets_lost = 105; 390 voice_sender_info->ext_seqnum = 106; 391 voice_sender_info->audio_level = 107; 392 voice_sender_info->echo_return_loss = 108; 393 voice_sender_info->echo_return_loss_enhancement = 109; 394 voice_sender_info->echo_delay_median_ms = 110; 395 voice_sender_info->echo_delay_std_ms = 111; 396 voice_sender_info->aec_quality_min = 112.0f; 397 voice_sender_info->typing_noise_detected = false; 398} 399 400void UpdateVoiceSenderInfoFromAudioTrack( 401 FakeAudioTrack* audio_track, cricket::VoiceSenderInfo* voice_sender_info) { 402 audio_track->GetSignalLevel(&voice_sender_info->audio_level); 403 webrtc::AudioProcessorInterface::AudioProcessorStats audio_processor_stats; 404 audio_track->GetAudioProcessor()->GetStats(&audio_processor_stats); 405 voice_sender_info->typing_noise_detected = 406 audio_processor_stats.typing_noise_detected; 407 voice_sender_info->echo_return_loss = audio_processor_stats.echo_return_loss; 408 voice_sender_info->echo_return_loss_enhancement = 409 audio_processor_stats.echo_return_loss_enhancement; 410 voice_sender_info->echo_delay_median_ms = 411 audio_processor_stats.echo_delay_median_ms; 412 voice_sender_info->aec_quality_min = audio_processor_stats.aec_quality_min; 413 voice_sender_info->echo_delay_std_ms = 414 audio_processor_stats.echo_delay_std_ms; 415} 416 417void InitVoiceReceiverInfo(cricket::VoiceReceiverInfo* voice_receiver_info) { 418 voice_receiver_info->add_ssrc(kSsrcOfTrack); 419 voice_receiver_info->bytes_rcvd = 110; 420 voice_receiver_info->packets_rcvd = 111; 421 voice_receiver_info->packets_lost = 112; 422 voice_receiver_info->fraction_lost = 113; 423 voice_receiver_info->packets_lost = 114; 424 voice_receiver_info->ext_seqnum = 115; 425 voice_receiver_info->jitter_ms = 116; 426 voice_receiver_info->jitter_buffer_ms = 117; 427 voice_receiver_info->jitter_buffer_preferred_ms = 118; 428 voice_receiver_info->delay_estimate_ms = 119; 429 voice_receiver_info->audio_level = 120; 430 voice_receiver_info->expand_rate = 121; 431} 432 433class StatsCollectorTest : public testing::Test { 434 protected: 435 StatsCollectorTest() 436 : media_engine_(new cricket::FakeMediaEngine()), 437 channel_manager_( 438 new cricket::ChannelManager(media_engine_, 439 new cricket::FakeDeviceManager(), 440 rtc::Thread::Current())), 441 session_(channel_manager_.get()) { 442 // By default, we ignore session GetStats calls. 443 EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false)); 444 } 445 446 ~StatsCollectorTest() {} 447 448 // This creates a standard setup with a transport called "trspname" 449 // having one transport channel 450 // and the specified virtual connection name. 451 void InitSessionStats(const std::string& vc_name) { 452 const std::string kTransportName("trspname"); 453 cricket::TransportStats transport_stats; 454 cricket::TransportChannelStats channel_stats; 455 channel_stats.component = 1; 456 transport_stats.content_name = kTransportName; 457 transport_stats.channel_stats.push_back(channel_stats); 458 459 session_stats_.transport_stats[kTransportName] = transport_stats; 460 session_stats_.proxy_to_transport[vc_name] = kTransportName; 461 } 462 463 // Adds a outgoing video track with a given SSRC into the stats. 464 void AddOutgoingVideoTrackStats() { 465 stream_ = webrtc::MediaStream::Create("streamlabel"); 466 track_= webrtc::VideoTrack::Create(kLocalTrackId, NULL); 467 stream_->AddTrack(track_); 468 EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _)) 469 .WillRepeatedly(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true))); 470 } 471 472 // Adds a incoming video track with a given SSRC into the stats. 473 void AddIncomingVideoTrackStats() { 474 stream_ = webrtc::MediaStream::Create("streamlabel"); 475 track_= webrtc::VideoTrack::Create(kRemoteTrackId, NULL); 476 stream_->AddTrack(track_); 477 EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _)) 478 .WillRepeatedly(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true))); 479 } 480 481 // Adds a outgoing audio track with a given SSRC into the stats. 482 void AddOutgoingAudioTrackStats() { 483 if (stream_ == NULL) 484 stream_ = webrtc::MediaStream::Create("streamlabel"); 485 486 audio_track_ = new rtc::RefCountedObject<FakeAudioTrack>( 487 kLocalTrackId); 488 stream_->AddTrack(audio_track_); 489 EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _)) 490 .WillOnce(DoAll(SetArgPointee<1>(kLocalTrackId), Return(true))); 491 } 492 493 // Adds a incoming audio track with a given SSRC into the stats. 494 void AddIncomingAudioTrackStats() { 495 if (stream_ == NULL) 496 stream_ = webrtc::MediaStream::Create("streamlabel"); 497 498 audio_track_ = new rtc::RefCountedObject<FakeAudioTrack>( 499 kRemoteTrackId); 500 stream_->AddTrack(audio_track_); 501 EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _)) 502 .WillOnce(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true))); 503 } 504 505 void SetupAndVerifyAudioTrackStats( 506 FakeAudioTrack* audio_track, 507 webrtc::MediaStream* stream, 508 webrtc::StatsCollector* stats, 509 cricket::VoiceChannel* voice_channel, 510 const std::string& vc_name, 511 MockVoiceMediaChannel* media_channel, 512 cricket::VoiceSenderInfo* voice_sender_info, 513 cricket::VoiceReceiverInfo* voice_receiver_info, 514 cricket::VoiceMediaInfo* stats_read, 515 StatsReports* reports) { 516 // A track can't have both sender report and recv report at the same time 517 // for now, this might change in the future though. 518 ASSERT((voice_sender_info == NULL) ^ (voice_receiver_info == NULL)); 519 520 // Instruct the session to return stats containing the transport channel. 521 InitSessionStats(vc_name); 522 EXPECT_CALL(session_, GetStats(_)) 523 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), 524 Return(true))); 525 526 // Constructs an ssrc stats update. 527 if (voice_sender_info) 528 stats_read->senders.push_back(*voice_sender_info); 529 if (voice_receiver_info) 530 stats_read->receivers.push_back(*voice_receiver_info); 531 532 EXPECT_CALL(session_, voice_channel()).WillRepeatedly( 533 Return(voice_channel)); 534 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 535 EXPECT_CALL(*media_channel, GetStats(_)) 536 .WillOnce(DoAll(SetArgPointee<0>(*stats_read), Return(true))); 537 538 stats->UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 539 stats->ClearUpdateStatsCache(); 540 stats->GetStats(NULL, reports); 541 542 // Verify the existence of the track report. 543 const StatsReport* report = FindNthReportByType( 544 *reports, StatsReport::kStatsReportTypeSsrc, 1); 545 EXPECT_FALSE(report == NULL); 546 std::string track_id = ExtractSsrcStatsValue( 547 *reports, StatsReport::kStatsValueNameTrackId); 548 EXPECT_EQ(audio_track->id(), track_id); 549 std::string ssrc_id = ExtractSsrcStatsValue( 550 *reports, StatsReport::kStatsValueNameSsrc); 551 EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id); 552 553 // Verifies the values in the track report. 554 if (voice_sender_info) { 555 UpdateVoiceSenderInfoFromAudioTrack(audio_track, voice_sender_info); 556 VerifyVoiceSenderInfoReport(report, *voice_sender_info); 557 } 558 if (voice_receiver_info) { 559 VerifyVoiceReceiverInfoReport(report, *voice_receiver_info); 560 } 561 562 // Verify we get the same result by passing a track to GetStats(). 563 StatsReports track_reports; // returned values. 564 stats->GetStats(audio_track, &track_reports); 565 const StatsReport* track_report = FindNthReportByType( 566 track_reports, StatsReport::kStatsReportTypeSsrc, 1); 567 EXPECT_TRUE(track_report); 568 track_id = ExtractSsrcStatsValue(track_reports, 569 StatsReport::kStatsValueNameTrackId); 570 EXPECT_EQ(audio_track->id(), track_id); 571 ssrc_id = ExtractSsrcStatsValue(track_reports, 572 StatsReport::kStatsValueNameSsrc); 573 EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id); 574 if (voice_sender_info) 575 VerifyVoiceSenderInfoReport(track_report, *voice_sender_info); 576 if (voice_receiver_info) 577 VerifyVoiceReceiverInfoReport(track_report, *voice_receiver_info); 578 } 579 580 void TestCertificateReports(const rtc::FakeSSLCertificate& local_cert, 581 const std::vector<std::string>& local_ders, 582 const rtc::FakeSSLCertificate& remote_cert, 583 const std::vector<std::string>& remote_ders) { 584 webrtc::StatsCollector stats(&session_); // Implementation under test. 585 StatsReports reports; // returned values. 586 587 // Fake stats to process. 588 cricket::TransportChannelStats channel_stats; 589 channel_stats.component = 1; 590 591 cricket::TransportStats transport_stats; 592 transport_stats.content_name = "audio"; 593 transport_stats.channel_stats.push_back(channel_stats); 594 595 cricket::SessionStats session_stats; 596 session_stats.transport_stats[transport_stats.content_name] = 597 transport_stats; 598 599 // Fake certificates to report. 600 rtc::FakeSSLIdentity local_identity(local_cert); 601 rtc::scoped_ptr<rtc::FakeSSLCertificate> remote_cert_copy( 602 remote_cert.GetReference()); 603 604 // Fake transport object. 605 rtc::scoped_ptr<cricket::FakeTransport> transport( 606 new cricket::FakeTransport( 607 session_.signaling_thread(), 608 session_.worker_thread(), 609 transport_stats.content_name)); 610 transport->SetIdentity(&local_identity); 611 cricket::FakeTransportChannel* channel = 612 static_cast<cricket::FakeTransportChannel*>( 613 transport->CreateChannel(channel_stats.component)); 614 EXPECT_FALSE(channel == NULL); 615 channel->SetRemoteCertificate(remote_cert_copy.get()); 616 617 // Configure MockWebRtcSession 618 EXPECT_CALL(session_, GetTransport(transport_stats.content_name)) 619 .WillRepeatedly(Return(transport.get())); 620 EXPECT_CALL(session_, GetStats(_)) 621 .WillOnce(DoAll(SetArgPointee<0>(session_stats), 622 Return(true))); 623 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 624 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 625 626 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 627 628 stats.GetStats(NULL, &reports); 629 630 const StatsReport* channel_report = FindNthReportByType( 631 reports, StatsReport::kStatsReportTypeComponent, 1); 632 EXPECT_TRUE(channel_report != NULL); 633 634 // Check local certificate chain. 635 std::string local_certificate_id = ExtractStatsValue( 636 StatsReport::kStatsReportTypeComponent, 637 reports, 638 StatsReport::kStatsValueNameLocalCertificateId); 639 if (local_ders.size() > 0) { 640 EXPECT_NE(kNotFound, local_certificate_id); 641 CheckCertChainReports(reports, local_ders, local_certificate_id); 642 } else { 643 EXPECT_EQ(kNotFound, local_certificate_id); 644 } 645 646 // Check remote certificate chain. 647 std::string remote_certificate_id = ExtractStatsValue( 648 StatsReport::kStatsReportTypeComponent, 649 reports, 650 StatsReport::kStatsValueNameRemoteCertificateId); 651 if (remote_ders.size() > 0) { 652 EXPECT_NE(kNotFound, remote_certificate_id); 653 CheckCertChainReports(reports, remote_ders, remote_certificate_id); 654 } else { 655 EXPECT_EQ(kNotFound, remote_certificate_id); 656 } 657 } 658 659 cricket::FakeMediaEngine* media_engine_; 660 rtc::scoped_ptr<cricket::ChannelManager> channel_manager_; 661 MockWebRtcSession session_; 662 cricket::SessionStats session_stats_; 663 rtc::scoped_refptr<webrtc::MediaStream> stream_; 664 rtc::scoped_refptr<webrtc::VideoTrack> track_; 665 rtc::scoped_refptr<FakeAudioTrack> audio_track_; 666}; 667 668// This test verifies that 64-bit counters are passed successfully. 669TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) { 670 webrtc::StatsCollector stats(&session_); // Implementation under test. 671 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 672 cricket::VideoChannel video_channel(rtc::Thread::Current(), 673 media_engine_, media_channel, &session_, "", false, NULL); 674 StatsReports reports; // returned values. 675 cricket::VideoSenderInfo video_sender_info; 676 cricket::VideoMediaInfo stats_read; 677 // The number of bytes must be larger than 0xFFFFFFFF for this test. 678 const int64 kBytesSent = 12345678901234LL; 679 const std::string kBytesSentString("12345678901234"); 680 681 AddOutgoingVideoTrackStats(); 682 stats.AddStream(stream_); 683 684 // Construct a stats value to read. 685 video_sender_info.add_ssrc(1234); 686 video_sender_info.bytes_sent = kBytesSent; 687 stats_read.senders.push_back(video_sender_info); 688 689 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 690 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 691 EXPECT_CALL(*media_channel, GetStats(_, _)) 692 .WillOnce(DoAll(SetArgPointee<1>(stats_read), 693 Return(true))); 694 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 695 stats.GetStats(NULL, &reports); 696 std::string result = ExtractSsrcStatsValue(reports, 697 StatsReport::kStatsValueNameBytesSent); 698 EXPECT_EQ(kBytesSentString, result); 699} 700 701// Test that BWE information is reported via stats. 702TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) { 703 webrtc::StatsCollector stats(&session_); // Implementation under test. 704 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 705 cricket::VideoChannel video_channel(rtc::Thread::Current(), 706 media_engine_, media_channel, &session_, "", false, NULL); 707 StatsReports reports; // returned values. 708 cricket::VideoSenderInfo video_sender_info; 709 cricket::VideoMediaInfo stats_read; 710 // Set up an SSRC just to test that we get both kinds of stats back: SSRC and 711 // BWE. 712 const int64 kBytesSent = 12345678901234LL; 713 const std::string kBytesSentString("12345678901234"); 714 715 AddOutgoingVideoTrackStats(); 716 stats.AddStream(stream_); 717 718 // Construct a stats value to read. 719 video_sender_info.add_ssrc(1234); 720 video_sender_info.bytes_sent = kBytesSent; 721 stats_read.senders.push_back(video_sender_info); 722 cricket::BandwidthEstimationInfo bwe; 723 const int kTargetEncBitrate = 123456; 724 const std::string kTargetEncBitrateString("123456"); 725 bwe.target_enc_bitrate = kTargetEncBitrate; 726 stats_read.bw_estimations.push_back(bwe); 727 728 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 729 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 730 EXPECT_CALL(*media_channel, GetStats(_, _)) 731 .WillOnce(DoAll(SetArgPointee<1>(stats_read), 732 Return(true))); 733 734 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 735 stats.GetStats(NULL, &reports); 736 std::string result = ExtractSsrcStatsValue(reports, 737 StatsReport::kStatsValueNameBytesSent); 738 EXPECT_EQ(kBytesSentString, result); 739 result = ExtractBweStatsValue(reports, 740 StatsReport::kStatsValueNameTargetEncBitrate); 741 EXPECT_EQ(kTargetEncBitrateString, result); 742} 743 744// This test verifies that an object of type "googSession" always 745// exists in the returned stats. 746TEST_F(StatsCollectorTest, SessionObjectExists) { 747 webrtc::StatsCollector stats(&session_); // Implementation under test. 748 StatsReports reports; // returned values. 749 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 750 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 751 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 752 stats.GetStats(NULL, &reports); 753 const StatsReport* session_report = FindNthReportByType( 754 reports, StatsReport::kStatsReportTypeSession, 1); 755 EXPECT_FALSE(session_report == NULL); 756} 757 758// This test verifies that only one object of type "googSession" exists 759// in the returned stats. 760TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) { 761 webrtc::StatsCollector stats(&session_); // Implementation under test. 762 StatsReports reports; // returned values. 763 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 764 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 765 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 766 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 767 stats.GetStats(NULL, &reports); 768 const StatsReport* session_report = FindNthReportByType( 769 reports, StatsReport::kStatsReportTypeSession, 1); 770 EXPECT_FALSE(session_report == NULL); 771 session_report = FindNthReportByType( 772 reports, StatsReport::kStatsReportTypeSession, 2); 773 EXPECT_EQ(NULL, session_report); 774} 775 776// This test verifies that the empty track report exists in the returned stats 777// without calling StatsCollector::UpdateStats. 778TEST_F(StatsCollectorTest, TrackObjectExistsWithoutUpdateStats) { 779 webrtc::StatsCollector stats(&session_); // Implementation under test. 780 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 781 cricket::VideoChannel video_channel(rtc::Thread::Current(), 782 media_engine_, media_channel, &session_, "", false, NULL); 783 AddOutgoingVideoTrackStats(); 784 stats.AddStream(stream_); 785 786 // Verfies the existence of the track report. 787 StatsReports reports; 788 stats.GetStats(NULL, &reports); 789 EXPECT_EQ((size_t)1, reports.size()); 790 EXPECT_EQ(std::string(StatsReport::kStatsReportTypeTrack), 791 reports[0]->type); 792 793 std::string trackValue = 794 ExtractStatsValue(StatsReport::kStatsReportTypeTrack, 795 reports, 796 StatsReport::kStatsValueNameTrackId); 797 EXPECT_EQ(kLocalTrackId, trackValue); 798} 799 800// This test verifies that the empty track report exists in the returned stats 801// when StatsCollector::UpdateStats is called with ssrc stats. 802TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) { 803 webrtc::StatsCollector stats(&session_); // Implementation under test. 804 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 805 cricket::VideoChannel video_channel(rtc::Thread::Current(), 806 media_engine_, media_channel, &session_, "", false, NULL); 807 AddOutgoingVideoTrackStats(); 808 stats.AddStream(stream_); 809 810 // Constructs an ssrc stats update. 811 cricket::VideoSenderInfo video_sender_info; 812 cricket::VideoMediaInfo stats_read; 813 const int64 kBytesSent = 12345678901234LL; 814 815 // Construct a stats value to read. 816 video_sender_info.add_ssrc(1234); 817 video_sender_info.bytes_sent = kBytesSent; 818 stats_read.senders.push_back(video_sender_info); 819 820 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 821 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 822 EXPECT_CALL(*media_channel, GetStats(_, _)) 823 .WillOnce(DoAll(SetArgPointee<1>(stats_read), 824 Return(true))); 825 826 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 827 StatsReports reports; 828 stats.GetStats(NULL, &reports); 829 // |reports| should contain at least one session report, one track report, 830 // and one ssrc report. 831 EXPECT_LE((size_t)3, reports.size()); 832 const StatsReport* track_report = FindNthReportByType( 833 reports, StatsReport::kStatsReportTypeTrack, 1); 834 EXPECT_TRUE(track_report); 835 836 // Get report for the specific |track|. 837 reports.clear(); 838 stats.GetStats(track_, &reports); 839 // |reports| should contain at least one session report, one track report, 840 // and one ssrc report. 841 EXPECT_LE((size_t)3, reports.size()); 842 track_report = FindNthReportByType( 843 reports, StatsReport::kStatsReportTypeTrack, 1); 844 EXPECT_TRUE(track_report); 845 846 std::string ssrc_id = ExtractSsrcStatsValue( 847 reports, StatsReport::kStatsValueNameSsrc); 848 EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id); 849 850 std::string track_id = ExtractSsrcStatsValue( 851 reports, StatsReport::kStatsValueNameTrackId); 852 EXPECT_EQ(kLocalTrackId, track_id); 853} 854 855// This test verifies that an SSRC object has the identifier of a Transport 856// stats object, and that this transport stats object exists in stats. 857TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) { 858 webrtc::StatsCollector stats(&session_); // Implementation under test. 859 // Ignore unused callback (logspam). 860 EXPECT_CALL(session_, GetTransport(_)) 861 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 862 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 863 // The content_name known by the video channel. 864 const std::string kVcName("vcname"); 865 cricket::VideoChannel video_channel(rtc::Thread::Current(), 866 media_engine_, media_channel, &session_, kVcName, false, NULL); 867 AddOutgoingVideoTrackStats(); 868 stats.AddStream(stream_); 869 870 // Constructs an ssrc stats update. 871 cricket::VideoSenderInfo video_sender_info; 872 cricket::VideoMediaInfo stats_read; 873 const int64 kBytesSent = 12345678901234LL; 874 875 // Construct a stats value to read. 876 video_sender_info.add_ssrc(1234); 877 video_sender_info.bytes_sent = kBytesSent; 878 stats_read.senders.push_back(video_sender_info); 879 880 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 881 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 882 EXPECT_CALL(*media_channel, GetStats(_, _)) 883 .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read), 884 Return(true))); 885 886 InitSessionStats(kVcName); 887 EXPECT_CALL(session_, GetStats(_)) 888 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), 889 Return(true))); 890 891 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 892 StatsReports reports; 893 stats.GetStats(NULL, &reports); 894 std::string transport_id = ExtractStatsValue( 895 StatsReport::kStatsReportTypeSsrc, 896 reports, 897 StatsReport::kStatsValueNameTransportId); 898 ASSERT_NE(kNotFound, transport_id); 899 const StatsReport* transport_report = FindReportById(reports, 900 transport_id); 901 ASSERT_FALSE(transport_report == NULL); 902} 903 904// This test verifies that a remote stats object will not be created for 905// an outgoing SSRC where remote stats are not returned. 906TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) { 907 webrtc::StatsCollector stats(&session_); // Implementation under test. 908 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 909 // The content_name known by the video channel. 910 const std::string kVcName("vcname"); 911 cricket::VideoChannel video_channel(rtc::Thread::Current(), 912 media_engine_, media_channel, &session_, kVcName, false, NULL); 913 AddOutgoingVideoTrackStats(); 914 stats.AddStream(stream_); 915 916 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 917 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 918 919 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 920 StatsReports reports; 921 stats.GetStats(NULL, &reports); 922 const StatsReport* remote_report = FindNthReportByType(reports, 923 StatsReport::kStatsReportTypeRemoteSsrc, 1); 924 EXPECT_TRUE(remote_report == NULL); 925} 926 927// This test verifies that a remote stats object will be created for 928// an outgoing SSRC where stats are returned. 929TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) { 930 webrtc::StatsCollector stats(&session_); // Implementation under test. 931 // Ignore unused callback (logspam). 932 EXPECT_CALL(session_, GetTransport(_)) 933 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 934 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 935 // The content_name known by the video channel. 936 const std::string kVcName("vcname"); 937 cricket::VideoChannel video_channel(rtc::Thread::Current(), 938 media_engine_, media_channel, &session_, kVcName, false, NULL); 939 AddOutgoingVideoTrackStats(); 940 stats.AddStream(stream_); 941 942 // Instruct the session to return stats containing the transport channel. 943 InitSessionStats(kVcName); 944 EXPECT_CALL(session_, GetStats(_)) 945 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), 946 Return(true))); 947 948 // Constructs an ssrc stats update. 949 cricket::VideoMediaInfo stats_read; 950 951 cricket::SsrcReceiverInfo remote_ssrc_stats; 952 remote_ssrc_stats.timestamp = 12345.678; 953 remote_ssrc_stats.ssrc = kSsrcOfTrack; 954 cricket::VideoSenderInfo video_sender_info; 955 video_sender_info.add_ssrc(kSsrcOfTrack); 956 video_sender_info.remote_stats.push_back(remote_ssrc_stats); 957 stats_read.senders.push_back(video_sender_info); 958 959 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 960 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 961 EXPECT_CALL(*media_channel, GetStats(_, _)) 962 .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read), 963 Return(true))); 964 965 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 966 StatsReports reports; 967 stats.GetStats(NULL, &reports); 968 969 const StatsReport* remote_report = FindNthReportByType(reports, 970 StatsReport::kStatsReportTypeRemoteSsrc, 1); 971 EXPECT_FALSE(remote_report == NULL); 972 EXPECT_NE(0, remote_report->timestamp); 973} 974 975// This test verifies that the empty track report exists in the returned stats 976// when StatsCollector::UpdateStats is called with ssrc stats. 977TEST_F(StatsCollectorTest, ReportsFromRemoteTrack) { 978 webrtc::StatsCollector stats(&session_); // Implementation under test. 979 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 980 cricket::VideoChannel video_channel(rtc::Thread::Current(), 981 media_engine_, media_channel, &session_, "", false, NULL); 982 AddIncomingVideoTrackStats(); 983 stats.AddStream(stream_); 984 985 // Constructs an ssrc stats update. 986 cricket::VideoReceiverInfo video_receiver_info; 987 cricket::VideoMediaInfo stats_read; 988 const int64 kNumOfPacketsConcealed = 54321; 989 990 // Construct a stats value to read. 991 video_receiver_info.add_ssrc(1234); 992 video_receiver_info.packets_concealed = kNumOfPacketsConcealed; 993 stats_read.receivers.push_back(video_receiver_info); 994 995 EXPECT_CALL(session_, video_channel()).WillRepeatedly(Return(&video_channel)); 996 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 997 EXPECT_CALL(*media_channel, GetStats(_, _)) 998 .WillOnce(DoAll(SetArgPointee<1>(stats_read), 999 Return(true))); 1000 1001 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 1002 StatsReports reports; 1003 stats.GetStats(NULL, &reports); 1004 // |reports| should contain at least one session report, one track report, 1005 // and one ssrc report. 1006 EXPECT_LE(static_cast<size_t>(3), reports.size()); 1007 const StatsReport* track_report = FindNthReportByType( 1008 reports, StatsReport::kStatsReportTypeTrack, 1); 1009 EXPECT_TRUE(track_report); 1010 1011 std::string ssrc_id = ExtractSsrcStatsValue( 1012 reports, StatsReport::kStatsValueNameSsrc); 1013 EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id); 1014 1015 std::string track_id = ExtractSsrcStatsValue( 1016 reports, StatsReport::kStatsValueNameTrackId); 1017 EXPECT_EQ(kRemoteTrackId, track_id); 1018} 1019 1020// This test verifies that all chained certificates are correctly 1021// reported 1022TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) { 1023 // Build local certificate chain. 1024 std::vector<std::string> local_ders(5); 1025 local_ders[0] = "These"; 1026 local_ders[1] = "are"; 1027 local_ders[2] = "some"; 1028 local_ders[3] = "der"; 1029 local_ders[4] = "values"; 1030 rtc::FakeSSLCertificate local_cert(DersToPems(local_ders)); 1031 1032 // Build remote certificate chain 1033 std::vector<std::string> remote_ders(4); 1034 remote_ders[0] = "A"; 1035 remote_ders[1] = "non-"; 1036 remote_ders[2] = "intersecting"; 1037 remote_ders[3] = "set"; 1038 rtc::FakeSSLCertificate remote_cert(DersToPems(remote_ders)); 1039 1040 TestCertificateReports(local_cert, local_ders, remote_cert, remote_ders); 1041} 1042 1043// This test verifies that all certificates without chains are correctly 1044// reported. 1045TEST_F(StatsCollectorTest, ChainlessCertificateReportsCreated) { 1046 // Build local certificate. 1047 std::string local_der = "This is the local der."; 1048 rtc::FakeSSLCertificate local_cert(DerToPem(local_der)); 1049 1050 // Build remote certificate. 1051 std::string remote_der = "This is somebody else's der."; 1052 rtc::FakeSSLCertificate remote_cert(DerToPem(remote_der)); 1053 1054 TestCertificateReports(local_cert, std::vector<std::string>(1, local_der), 1055 remote_cert, std::vector<std::string>(1, remote_der)); 1056} 1057 1058// This test verifies that the stats are generated correctly when no 1059// transport is present. 1060TEST_F(StatsCollectorTest, NoTransport) { 1061 webrtc::StatsCollector stats(&session_); // Implementation under test. 1062 StatsReports reports; // returned values. 1063 1064 // Fake stats to process. 1065 cricket::TransportChannelStats channel_stats; 1066 channel_stats.component = 1; 1067 1068 cricket::TransportStats transport_stats; 1069 transport_stats.content_name = "audio"; 1070 transport_stats.channel_stats.push_back(channel_stats); 1071 1072 cricket::SessionStats session_stats; 1073 session_stats.transport_stats[transport_stats.content_name] = 1074 transport_stats; 1075 1076 // Configure MockWebRtcSession 1077 EXPECT_CALL(session_, GetTransport(transport_stats.content_name)) 1078 .WillRepeatedly(ReturnNull()); 1079 EXPECT_CALL(session_, GetStats(_)) 1080 .WillOnce(DoAll(SetArgPointee<0>(session_stats), 1081 Return(true))); 1082 1083 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 1084 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 1085 1086 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 1087 stats.GetStats(NULL, &reports); 1088 1089 // Check that the local certificate is absent. 1090 std::string local_certificate_id = ExtractStatsValue( 1091 StatsReport::kStatsReportTypeComponent, 1092 reports, 1093 StatsReport::kStatsValueNameLocalCertificateId); 1094 ASSERT_EQ(kNotFound, local_certificate_id); 1095 1096 // Check that the remote certificate is absent. 1097 std::string remote_certificate_id = ExtractStatsValue( 1098 StatsReport::kStatsReportTypeComponent, 1099 reports, 1100 StatsReport::kStatsValueNameRemoteCertificateId); 1101 ASSERT_EQ(kNotFound, remote_certificate_id); 1102} 1103 1104// This test verifies that the stats are generated correctly when the transport 1105// does not have any certificates. 1106TEST_F(StatsCollectorTest, NoCertificates) { 1107 webrtc::StatsCollector stats(&session_); // Implementation under test. 1108 StatsReports reports; // returned values. 1109 1110 // Fake stats to process. 1111 cricket::TransportChannelStats channel_stats; 1112 channel_stats.component = 1; 1113 1114 cricket::TransportStats transport_stats; 1115 transport_stats.content_name = "audio"; 1116 transport_stats.channel_stats.push_back(channel_stats); 1117 1118 cricket::SessionStats session_stats; 1119 session_stats.transport_stats[transport_stats.content_name] = 1120 transport_stats; 1121 1122 // Fake transport object. 1123 rtc::scoped_ptr<cricket::FakeTransport> transport( 1124 new cricket::FakeTransport( 1125 session_.signaling_thread(), 1126 session_.worker_thread(), 1127 transport_stats.content_name)); 1128 1129 // Configure MockWebRtcSession 1130 EXPECT_CALL(session_, GetTransport(transport_stats.content_name)) 1131 .WillRepeatedly(Return(transport.get())); 1132 EXPECT_CALL(session_, GetStats(_)) 1133 .WillOnce(DoAll(SetArgPointee<0>(session_stats), 1134 Return(true))); 1135 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 1136 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 1137 1138 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 1139 stats.GetStats(NULL, &reports); 1140 1141 // Check that the local certificate is absent. 1142 std::string local_certificate_id = ExtractStatsValue( 1143 StatsReport::kStatsReportTypeComponent, 1144 reports, 1145 StatsReport::kStatsValueNameLocalCertificateId); 1146 ASSERT_EQ(kNotFound, local_certificate_id); 1147 1148 // Check that the remote certificate is absent. 1149 std::string remote_certificate_id = ExtractStatsValue( 1150 StatsReport::kStatsReportTypeComponent, 1151 reports, 1152 StatsReport::kStatsValueNameRemoteCertificateId); 1153 ASSERT_EQ(kNotFound, remote_certificate_id); 1154} 1155 1156// This test verifies that a remote certificate with an unsupported digest 1157// algorithm is correctly ignored. 1158TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) { 1159 // Build a local certificate. 1160 std::string local_der = "This is the local der."; 1161 rtc::FakeSSLCertificate local_cert(DerToPem(local_der)); 1162 1163 // Build a remote certificate with an unsupported digest algorithm. 1164 std::string remote_der = "This is somebody else's der."; 1165 rtc::FakeSSLCertificate remote_cert(DerToPem(remote_der)); 1166 remote_cert.set_digest_algorithm("foobar"); 1167 1168 TestCertificateReports(local_cert, std::vector<std::string>(1, local_der), 1169 remote_cert, std::vector<std::string>()); 1170} 1171 1172// Verifies the correct optons are passed to the VideoMediaChannel when using 1173// verbose output level. 1174TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) { 1175 webrtc::StatsCollector stats(&session_); // Implementation under test. 1176 MockVideoMediaChannel* media_channel = new MockVideoMediaChannel(); 1177 cricket::VideoChannel video_channel(rtc::Thread::Current(), 1178 media_engine_, media_channel, &session_, "", false, NULL); 1179 1180 cricket::VideoMediaInfo stats_read; 1181 cricket::BandwidthEstimationInfo bwe; 1182 bwe.total_received_propagation_delta_ms = 10; 1183 bwe.recent_received_propagation_delta_ms.push_back(100); 1184 bwe.recent_received_propagation_delta_ms.push_back(200); 1185 bwe.recent_received_packet_group_arrival_time_ms.push_back(1000); 1186 bwe.recent_received_packet_group_arrival_time_ms.push_back(2000); 1187 stats_read.bw_estimations.push_back(bwe); 1188 1189 EXPECT_CALL(session_, video_channel()) 1190 .WillRepeatedly(Return(&video_channel)); 1191 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(ReturnNull()); 1192 1193 StatsOptions options; 1194 options.include_received_propagation_stats = true; 1195 EXPECT_CALL(*media_channel, GetStats( 1196 Field(&StatsOptions::include_received_propagation_stats, true), 1197 _)) 1198 .WillOnce(DoAll(SetArgPointee<1>(stats_read), 1199 Return(true))); 1200 1201 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelDebug); 1202 StatsReports reports; // returned values. 1203 stats.GetStats(NULL, &reports); 1204 std::string result = ExtractBweStatsValue( 1205 reports, 1206 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug); 1207 EXPECT_EQ("10", result); 1208 result = ExtractBweStatsValue( 1209 reports, 1210 StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug); 1211 EXPECT_EQ("[100, 200]", result); 1212 result = ExtractBweStatsValue( 1213 reports, StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug); 1214 EXPECT_EQ("[1000, 2000]", result); 1215} 1216 1217// This test verifies that a local stats object can get statistics via 1218// AudioTrackInterface::GetStats() method. 1219TEST_F(StatsCollectorTest, GetStatsFromLocalAudioTrack) { 1220 webrtc::StatsCollector stats(&session_); // Implementation under test. 1221 // Ignore unused callback (logspam). 1222 EXPECT_CALL(session_, GetTransport(_)) 1223 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 1224 1225 MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); 1226 // The content_name known by the voice channel. 1227 const std::string kVcName("vcname"); 1228 cricket::VoiceChannel voice_channel(rtc::Thread::Current(), 1229 media_engine_, media_channel, &session_, kVcName, false); 1230 AddOutgoingAudioTrackStats(); 1231 stats.AddStream(stream_); 1232 stats.AddLocalAudioTrack(audio_track_, kSsrcOfTrack); 1233 1234 cricket::VoiceSenderInfo voice_sender_info; 1235 InitVoiceSenderInfo(&voice_sender_info); 1236 1237 cricket::VoiceMediaInfo stats_read; 1238 StatsReports reports; // returned values. 1239 SetupAndVerifyAudioTrackStats( 1240 audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName, 1241 media_channel, &voice_sender_info, NULL, &stats_read, &reports); 1242 1243 // Verify that there is no remote report for the local audio track because 1244 // we did not set it up. 1245 const StatsReport* remote_report = FindNthReportByType(reports, 1246 StatsReport::kStatsReportTypeRemoteSsrc, 1); 1247 EXPECT_TRUE(remote_report == NULL); 1248} 1249 1250// This test verifies that audio receive streams populate stats reports 1251// correctly. 1252TEST_F(StatsCollectorTest, GetStatsFromRemoteStream) { 1253 webrtc::StatsCollector stats(&session_); // Implementation under test. 1254 // Ignore unused callback (logspam). 1255 EXPECT_CALL(session_, GetTransport(_)) 1256 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 1257 MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); 1258 // The content_name known by the voice channel. 1259 const std::string kVcName("vcname"); 1260 cricket::VoiceChannel voice_channel(rtc::Thread::Current(), 1261 media_engine_, media_channel, &session_, kVcName, false); 1262 AddIncomingAudioTrackStats(); 1263 stats.AddStream(stream_); 1264 1265 cricket::VoiceReceiverInfo voice_receiver_info; 1266 InitVoiceReceiverInfo(&voice_receiver_info); 1267 voice_receiver_info.codec_name = "fake_codec"; 1268 1269 cricket::VoiceMediaInfo stats_read; 1270 StatsReports reports; // returned values. 1271 SetupAndVerifyAudioTrackStats( 1272 audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName, 1273 media_channel, NULL, &voice_receiver_info, &stats_read, &reports); 1274} 1275 1276// This test verifies that a local stats object won't update its statistics 1277// after a RemoveLocalAudioTrack() call. 1278TEST_F(StatsCollectorTest, GetStatsAfterRemoveAudioStream) { 1279 webrtc::StatsCollector stats(&session_); // Implementation under test. 1280 // Ignore unused callback (logspam). 1281 EXPECT_CALL(session_, GetTransport(_)) 1282 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 1283 MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); 1284 // The content_name known by the voice channel. 1285 const std::string kVcName("vcname"); 1286 cricket::VoiceChannel voice_channel(rtc::Thread::Current(), 1287 media_engine_, media_channel, &session_, kVcName, false); 1288 AddOutgoingAudioTrackStats(); 1289 stats.AddStream(stream_); 1290 stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack); 1291 1292 // Instruct the session to return stats containing the transport channel. 1293 InitSessionStats(kVcName); 1294 EXPECT_CALL(session_, GetStats(_)) 1295 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), 1296 Return(true))); 1297 1298 stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack); 1299 cricket::VoiceSenderInfo voice_sender_info; 1300 InitVoiceSenderInfo(&voice_sender_info); 1301 1302 // Constructs an ssrc stats update. 1303 cricket::VoiceMediaInfo stats_read; 1304 stats_read.senders.push_back(voice_sender_info); 1305 1306 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel)); 1307 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 1308 EXPECT_CALL(*media_channel, GetStats(_)) 1309 .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read), 1310 Return(true))); 1311 1312 StatsReports reports; // returned values. 1313 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 1314 stats.GetStats(NULL, &reports); 1315 1316 // The report will exist since we don't remove them in RemoveStream(). 1317 const StatsReport* report = FindNthReportByType( 1318 reports, StatsReport::kStatsReportTypeSsrc, 1); 1319 EXPECT_FALSE(report == NULL); 1320 std::string track_id = ExtractSsrcStatsValue( 1321 reports, StatsReport::kStatsValueNameTrackId); 1322 EXPECT_EQ(kLocalTrackId, track_id); 1323 std::string ssrc_id = ExtractSsrcStatsValue( 1324 reports, StatsReport::kStatsValueNameSsrc); 1325 EXPECT_EQ(rtc::ToString<uint32>(kSsrcOfTrack), ssrc_id); 1326 1327 // Verifies the values in the track report, no value will be changed by the 1328 // AudioTrackInterface::GetSignalValue() and 1329 // AudioProcessorInterface::AudioProcessorStats::GetStats(); 1330 VerifyVoiceSenderInfoReport(report, voice_sender_info); 1331} 1332 1333// This test verifies that when ongoing and incoming audio tracks are using 1334// the same ssrc, they populate stats reports correctly. 1335TEST_F(StatsCollectorTest, LocalAndRemoteTracksWithSameSsrc) { 1336 webrtc::StatsCollector stats(&session_); // Implementation under test. 1337 // Ignore unused callback (logspam). 1338 EXPECT_CALL(session_, GetTransport(_)) 1339 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 1340 MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); 1341 // The content_name known by the voice channel. 1342 const std::string kVcName("vcname"); 1343 cricket::VoiceChannel voice_channel(rtc::Thread::Current(), 1344 media_engine_, media_channel, &session_, kVcName, false); 1345 1346 // Create a local stream with a local audio track and adds it to the stats. 1347 AddOutgoingAudioTrackStats(); 1348 stats.AddStream(stream_); 1349 stats.AddLocalAudioTrack(audio_track_.get(), kSsrcOfTrack); 1350 1351 // Create a remote stream with a remote audio track and adds it to the stats. 1352 rtc::scoped_refptr<webrtc::MediaStream> remote_stream( 1353 webrtc::MediaStream::Create("remotestreamlabel")); 1354 rtc::scoped_refptr<FakeAudioTrack> remote_track( 1355 new rtc::RefCountedObject<FakeAudioTrack>(kRemoteTrackId)); 1356 EXPECT_CALL(session_, GetRemoteTrackIdBySsrc(kSsrcOfTrack, _)) 1357 .WillOnce(DoAll(SetArgPointee<1>(kRemoteTrackId), Return(true))); 1358 remote_stream->AddTrack(remote_track); 1359 stats.AddStream(remote_stream); 1360 1361 // Instruct the session to return stats containing the transport channel. 1362 InitSessionStats(kVcName); 1363 EXPECT_CALL(session_, GetStats(_)) 1364 .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_), 1365 Return(true))); 1366 1367 cricket::VoiceSenderInfo voice_sender_info; 1368 InitVoiceSenderInfo(&voice_sender_info); 1369 1370 // Some of the contents in |voice_sender_info| needs to be updated from the 1371 // |audio_track_|. 1372 UpdateVoiceSenderInfoFromAudioTrack(audio_track_.get(), &voice_sender_info); 1373 1374 cricket::VoiceReceiverInfo voice_receiver_info; 1375 InitVoiceReceiverInfo(&voice_receiver_info); 1376 1377 // Constructs an ssrc stats update. 1378 cricket::VoiceMediaInfo stats_read; 1379 stats_read.senders.push_back(voice_sender_info); 1380 stats_read.receivers.push_back(voice_receiver_info); 1381 1382 EXPECT_CALL(session_, voice_channel()).WillRepeatedly(Return(&voice_channel)); 1383 EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull()); 1384 EXPECT_CALL(*media_channel, GetStats(_)) 1385 .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read), 1386 Return(true))); 1387 1388 StatsReports reports; // returned values. 1389 stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard); 1390 1391 // Get stats for the local track. 1392 stats.GetStats(audio_track_.get(), &reports); 1393 const StatsReport* track_report = FindNthReportByType( 1394 reports, StatsReport::kStatsReportTypeSsrc, 1); 1395 EXPECT_TRUE(track_report); 1396 std::string track_id = ExtractSsrcStatsValue( 1397 reports, StatsReport::kStatsValueNameTrackId); 1398 EXPECT_EQ(kLocalTrackId, track_id); 1399 VerifyVoiceSenderInfoReport(track_report, voice_sender_info); 1400 1401 // Get stats for the remote track. 1402 reports.clear(); 1403 stats.GetStats(remote_track.get(), &reports); 1404 track_report = FindNthReportByType(reports, 1405 StatsReport::kStatsReportTypeSsrc, 1); 1406 EXPECT_TRUE(track_report); 1407 track_id = ExtractSsrcStatsValue(reports, 1408 StatsReport::kStatsValueNameTrackId); 1409 EXPECT_EQ(kRemoteTrackId, track_id); 1410 VerifyVoiceReceiverInfoReport(track_report, voice_receiver_info); 1411} 1412 1413// This test verifies that when two outgoing audio tracks are using the same 1414// ssrc at different times, they populate stats reports correctly. 1415// TODO(xians): Figure out if it is possible to encapsulate the setup and 1416// avoid duplication of code in test cases. 1417TEST_F(StatsCollectorTest, TwoLocalTracksWithSameSsrc) { 1418 webrtc::StatsCollector stats(&session_); // Implementation under test. 1419 // Ignore unused callback (logspam). 1420 EXPECT_CALL(session_, GetTransport(_)) 1421 .WillRepeatedly(Return(static_cast<cricket::Transport*>(NULL))); 1422 MockVoiceMediaChannel* media_channel = new MockVoiceMediaChannel(); 1423 // The content_name known by the voice channel. 1424 const std::string kVcName("vcname"); 1425 cricket::VoiceChannel voice_channel(rtc::Thread::Current(), 1426 media_engine_, media_channel, &session_, kVcName, false); 1427 1428 // Create a local stream with a local audio track and adds it to the stats. 1429 AddOutgoingAudioTrackStats(); 1430 stats.AddStream(stream_); 1431 stats.AddLocalAudioTrack(audio_track_, kSsrcOfTrack); 1432 1433 cricket::VoiceSenderInfo voice_sender_info; 1434 voice_sender_info.add_ssrc(kSsrcOfTrack); 1435 1436 cricket::VoiceMediaInfo stats_read; 1437 StatsReports reports; // returned values. 1438 SetupAndVerifyAudioTrackStats( 1439 audio_track_.get(), stream_.get(), &stats, &voice_channel, kVcName, 1440 media_channel, &voice_sender_info, NULL, &stats_read, &reports); 1441 1442 // Remove the previous audio track from the stream. 1443 stream_->RemoveTrack(audio_track_.get()); 1444 stats.RemoveLocalAudioTrack(audio_track_.get(), kSsrcOfTrack); 1445 1446 // Create a new audio track and adds it to the stream and stats. 1447 static const std::string kNewTrackId = "new_track_id"; 1448 rtc::scoped_refptr<FakeAudioTrack> new_audio_track( 1449 new rtc::RefCountedObject<FakeAudioTrack>(kNewTrackId)); 1450 EXPECT_CALL(session_, GetLocalTrackIdBySsrc(kSsrcOfTrack, _)) 1451 .WillOnce(DoAll(SetArgPointee<1>(kNewTrackId), Return(true))); 1452 stream_->AddTrack(new_audio_track); 1453 1454 stats.AddLocalAudioTrack(new_audio_track, kSsrcOfTrack); 1455 stats.ClearUpdateStatsCache(); 1456 cricket::VoiceSenderInfo new_voice_sender_info; 1457 InitVoiceSenderInfo(&new_voice_sender_info); 1458 cricket::VoiceMediaInfo new_stats_read; 1459 reports.clear(); 1460 SetupAndVerifyAudioTrackStats( 1461 new_audio_track.get(), stream_.get(), &stats, &voice_channel, kVcName, 1462 media_channel, &new_voice_sender_info, NULL, &new_stats_read, &reports); 1463} 1464 1465} // namespace 1466