Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: talk/app/webrtc/statscollector.cc

Issue 1393563002: Moving MediaStreamSignaling logic into PeerConnection. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fixing copyright header Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « talk/app/webrtc/statscollector.h ('k') | talk/app/webrtc/statscollector_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2012 Google Inc. 3 * Copyright 2012 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 12 matching lines...) Expand all
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 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 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 #include "talk/app/webrtc/statscollector.h" 28 #include "talk/app/webrtc/statscollector.h"
29 29
30 #include <utility> 30 #include <utility>
31 #include <vector> 31 #include <vector>
32 32
33 #include "talk/app/webrtc/peerconnection.h"
33 #include "talk/session/media/channel.h" 34 #include "talk/session/media/channel.h"
34 #include "webrtc/base/base64.h" 35 #include "webrtc/base/base64.h"
35 #include "webrtc/base/checks.h" 36 #include "webrtc/base/checks.h"
36 #include "webrtc/base/scoped_ptr.h" 37 #include "webrtc/base/scoped_ptr.h"
37 #include "webrtc/base/timing.h" 38 #include "webrtc/base/timing.h"
38 39
39 using rtc::scoped_ptr; 40 using rtc::scoped_ptr;
40 41
41 namespace webrtc { 42 namespace webrtc {
42 namespace { 43 namespace {
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 case rtc::ADAPTER_TYPE_VPN: 350 case rtc::ADAPTER_TYPE_VPN:
350 return STATSREPORT_ADAPTER_TYPE_VPN; 351 return STATSREPORT_ADAPTER_TYPE_VPN;
351 case rtc::ADAPTER_TYPE_LOOPBACK: 352 case rtc::ADAPTER_TYPE_LOOPBACK:
352 return STATSREPORT_ADAPTER_TYPE_LOOPBACK; 353 return STATSREPORT_ADAPTER_TYPE_LOOPBACK;
353 default: 354 default:
354 RTC_DCHECK(false); 355 RTC_DCHECK(false);
355 return ""; 356 return "";
356 } 357 }
357 } 358 }
358 359
359 StatsCollector::StatsCollector(WebRtcSession* session) 360 StatsCollector::StatsCollector(PeerConnection* pc)
360 : session_(session), 361 : pc_(pc), stats_gathering_started_(0) {
361 stats_gathering_started_(0) { 362 RTC_DCHECK(pc_);
362 RTC_DCHECK(session_);
363 } 363 }
364 364
365 StatsCollector::~StatsCollector() { 365 StatsCollector::~StatsCollector() {
366 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 366 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
367 } 367 }
368 368
369 double StatsCollector::GetTimeNow() { 369 double StatsCollector::GetTimeNow() {
370 return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec; 370 return rtc::Timing::WallTimeNow() * rtc::kNumMillisecsPerSec;
371 } 371 }
372 372
373 // Adds a MediaStream with tracks that can be used as a |selector| in a call 373 // Adds a MediaStream with tracks that can be used as a |selector| in a call
374 // to GetStats. 374 // to GetStats.
375 void StatsCollector::AddStream(MediaStreamInterface* stream) { 375 void StatsCollector::AddStream(MediaStreamInterface* stream) {
376 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 376 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
377 RTC_DCHECK(stream != NULL); 377 RTC_DCHECK(stream != NULL);
378 378
379 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(), 379 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
380 &reports_, track_ids_); 380 &reports_, track_ids_);
381 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(), 381 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
382 &reports_, track_ids_); 382 &reports_, track_ids_);
383 } 383 }
384 384
385 void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track, 385 void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
386 uint32_t ssrc) { 386 uint32_t ssrc) {
387 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 387 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
388 RTC_DCHECK(audio_track != NULL); 388 RTC_DCHECK(audio_track != NULL);
389 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) 389 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
390 for (const auto& track : local_audio_tracks_) 390 for (const auto& track : local_audio_tracks_)
391 RTC_DCHECK(track.first != audio_track || track.second != ssrc); 391 RTC_DCHECK(track.first != audio_track || track.second != ssrc);
392 #endif 392 #endif
393 393
394 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc)); 394 local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
395 395
396 // Create the kStatsReportTypeTrack report for the new track if there is no 396 // Create the kStatsReportTypeTrack report for the new track if there is no
397 // report yet. 397 // report yet.
(...skipping 11 matching lines...) Expand all
409 RTC_DCHECK(audio_track != NULL); 409 RTC_DCHECK(audio_track != NULL);
410 local_audio_tracks_.erase(std::remove_if(local_audio_tracks_.begin(), 410 local_audio_tracks_.erase(std::remove_if(local_audio_tracks_.begin(),
411 local_audio_tracks_.end(), 411 local_audio_tracks_.end(),
412 [audio_track, ssrc](const LocalAudioTrackVector::value_type& track) { 412 [audio_track, ssrc](const LocalAudioTrackVector::value_type& track) {
413 return track.first == audio_track && track.second == ssrc; 413 return track.first == audio_track && track.second == ssrc;
414 })); 414 }));
415 } 415 }
416 416
417 void StatsCollector::GetStats(MediaStreamTrackInterface* track, 417 void StatsCollector::GetStats(MediaStreamTrackInterface* track,
418 StatsReports* reports) { 418 StatsReports* reports) {
419 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 419 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
420 RTC_DCHECK(reports != NULL); 420 RTC_DCHECK(reports != NULL);
421 RTC_DCHECK(reports->empty()); 421 RTC_DCHECK(reports->empty());
422 422
423 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; 423 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
424 424
425 if (!track) { 425 if (!track) {
426 reports->reserve(reports_.size()); 426 reports->reserve(reports_.size());
427 for (auto* r : reports_) 427 for (auto* r : reports_)
428 reports->push_back(r); 428 reports->push_back(r);
429 return; 429 return;
430 } 430 }
431 431
432 StatsReport* report = reports_.Find(StatsReport::NewTypedId( 432 StatsReport* report = reports_.Find(StatsReport::NewTypedId(
433 StatsReport::kStatsReportTypeSession, session_->id())); 433 StatsReport::kStatsReportTypeSession, pc_->session()->id()));
434 if (report) 434 if (report)
435 reports->push_back(report); 435 reports->push_back(report);
436 436
437 report = reports_.Find(StatsReport::NewTypedId( 437 report = reports_.Find(StatsReport::NewTypedId(
438 StatsReport::kStatsReportTypeTrack, track->id())); 438 StatsReport::kStatsReportTypeTrack, track->id()));
439 439
440 if (!report) 440 if (!report)
441 return; 441 return;
442 442
443 reports->push_back(report); 443 reports->push_back(report);
444 444
445 std::string track_id; 445 std::string track_id;
446 for (const auto* r : reports_) { 446 for (const auto* r : reports_) {
447 if (r->type() != StatsReport::kStatsReportTypeSsrc) 447 if (r->type() != StatsReport::kStatsReportTypeSsrc)
448 continue; 448 continue;
449 449
450 const StatsReport::Value* v = 450 const StatsReport::Value* v =
451 r->FindValue(StatsReport::kStatsValueNameTrackId); 451 r->FindValue(StatsReport::kStatsValueNameTrackId);
452 if (v && v->string_val() == track->id()) 452 if (v && v->string_val() == track->id())
453 reports->push_back(r); 453 reports->push_back(r);
454 } 454 }
455 } 455 }
456 456
457 void 457 void
458 StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) { 458 StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
459 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 459 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
460 double time_now = GetTimeNow(); 460 double time_now = GetTimeNow();
461 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of 461 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
462 // ms apart will be ignored. 462 // ms apart will be ignored.
463 const double kMinGatherStatsPeriod = 50; 463 const double kMinGatherStatsPeriod = 50;
464 if (stats_gathering_started_ != 0 && 464 if (stats_gathering_started_ != 0 &&
465 stats_gathering_started_ + kMinGatherStatsPeriod > time_now) { 465 stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
466 return; 466 return;
467 } 467 }
468 stats_gathering_started_ = time_now; 468 stats_gathering_started_ = time_now;
469 469
470 if (session_) { 470 if (pc_->session()) {
471 // TODO(tommi): All of these hop over to the worker thread to fetch 471 // TODO(tommi): All of these hop over to the worker thread to fetch
472 // information. We could use an AsyncInvoker to run all of these and post 472 // information. We could use an AsyncInvoker to run all of these and post
473 // the information back to the signaling thread where we can create and 473 // the information back to the signaling thread where we can create and
474 // update stats reports. That would also clean up the threading story a bit 474 // update stats reports. That would also clean up the threading story a bit
475 // since we'd be creating/updating the stats report objects consistently on 475 // since we'd be creating/updating the stats report objects consistently on
476 // the same thread (this class has no locks right now). 476 // the same thread (this class has no locks right now).
477 ExtractSessionInfo(); 477 ExtractSessionInfo();
478 ExtractVoiceInfo(); 478 ExtractVoiceInfo();
479 ExtractVideoInfo(level); 479 ExtractVideoInfo(level);
480 ExtractDataInfo(); 480 ExtractDataInfo();
481 UpdateTrackReports(); 481 UpdateTrackReports();
482 } 482 }
483 } 483 }
484 484
485 StatsReport* StatsCollector::PrepareReport(bool local, 485 StatsReport* StatsCollector::PrepareReport(
486 uint32_t ssrc, 486 bool local,
487 const StatsReport::Id& transport_id, 487 uint32_t ssrc,
488 StatsReport::Direction direction) { 488 const StatsReport::Id& transport_id,
489 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 489 StatsReport::Direction direction) {
490 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
490 StatsReport::Id id(StatsReport::NewIdWithDirection( 491 StatsReport::Id id(StatsReport::NewIdWithDirection(
491 local ? StatsReport::kStatsReportTypeSsrc 492 local ? StatsReport::kStatsReportTypeSsrc
492 : StatsReport::kStatsReportTypeRemoteSsrc, 493 : StatsReport::kStatsReportTypeRemoteSsrc,
493 rtc::ToString<uint32_t>(ssrc), direction)); 494 rtc::ToString<uint32_t>(ssrc), direction));
494 StatsReport* report = reports_.Find(id); 495 StatsReport* report = reports_.Find(id);
495 496
496 // Use the ID of the track that is currently mapped to the SSRC, if any. 497 // Use the ID of the track that is currently mapped to the SSRC, if any.
497 std::string track_id; 498 std::string track_id;
498 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) { 499 if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
499 if (!report) { 500 if (!report) {
(...skipping 18 matching lines...) Expand all
518 519
519 report->AddInt64(StatsReport::kStatsValueNameSsrc, ssrc); 520 report->AddInt64(StatsReport::kStatsValueNameSsrc, ssrc);
520 report->AddString(StatsReport::kStatsValueNameTrackId, track_id); 521 report->AddString(StatsReport::kStatsValueNameTrackId, track_id);
521 // Add the mapping of SSRC to transport. 522 // Add the mapping of SSRC to transport.
522 report->AddId(StatsReport::kStatsValueNameTransportId, transport_id); 523 report->AddId(StatsReport::kStatsValueNameTransportId, transport_id);
523 return report; 524 return report;
524 } 525 }
525 526
526 StatsReport* StatsCollector::AddOneCertificateReport( 527 StatsReport* StatsCollector::AddOneCertificateReport(
527 const rtc::SSLCertificate* cert, const StatsReport* issuer) { 528 const rtc::SSLCertificate* cert, const StatsReport* issuer) {
528 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 529 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
529 530
530 // TODO(bemasc): Move this computation to a helper class that caches these 531 // TODO(bemasc): Move this computation to a helper class that caches these
531 // values to reduce CPU use in GetStats. This will require adding a fast 532 // values to reduce CPU use in GetStats. This will require adding a fast
532 // SSLCertificate::Equals() method to detect certificate changes. 533 // SSLCertificate::Equals() method to detect certificate changes.
533 534
534 std::string digest_algorithm; 535 std::string digest_algorithm;
535 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm)) 536 if (!cert->GetSignatureDigestAlgorithm(&digest_algorithm))
536 return nullptr; 537 return nullptr;
537 538
538 rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint( 539 rtc::scoped_ptr<rtc::SSLFingerprint> ssl_fingerprint(
(...skipping 22 matching lines...) Expand all
561 report->AddString(StatsReport::kStatsValueNameFingerprintAlgorithm, 562 report->AddString(StatsReport::kStatsValueNameFingerprintAlgorithm,
562 digest_algorithm); 563 digest_algorithm);
563 report->AddString(StatsReport::kStatsValueNameDer, der_base64); 564 report->AddString(StatsReport::kStatsValueNameDer, der_base64);
564 if (issuer) 565 if (issuer)
565 report->AddId(StatsReport::kStatsValueNameIssuerId, issuer->id()); 566 report->AddId(StatsReport::kStatsValueNameIssuerId, issuer->id());
566 return report; 567 return report;
567 } 568 }
568 569
569 StatsReport* StatsCollector::AddCertificateReports( 570 StatsReport* StatsCollector::AddCertificateReports(
570 const rtc::SSLCertificate* cert) { 571 const rtc::SSLCertificate* cert) {
571 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 572 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
572 // Produces a chain of StatsReports representing this certificate and the rest 573 // Produces a chain of StatsReports representing this certificate and the rest
573 // of its chain, and adds those reports to |reports_|. The return value is 574 // of its chain, and adds those reports to |reports_|. The return value is
574 // the id of the leaf report. The provided cert must be non-null, so at least 575 // the id of the leaf report. The provided cert must be non-null, so at least
575 // one report will always be provided and the returned string will never be 576 // one report will always be provided and the returned string will never be
576 // empty. 577 // empty.
577 RTC_DCHECK(cert != NULL); 578 RTC_DCHECK(cert != NULL);
578 579
579 StatsReport* issuer = nullptr; 580 StatsReport* issuer = nullptr;
580 rtc::scoped_ptr<rtc::SSLCertChain> chain; 581 rtc::scoped_ptr<rtc::SSLCertChain> chain;
581 if (cert->GetChain(chain.accept())) { 582 if (cert->GetChain(chain.accept())) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 report->AddString(StatsReport::kStatsValueNameCandidateType, 662 report->AddString(StatsReport::kStatsValueNameCandidateType,
662 IceCandidateTypeToStatsType(candidate.type())); 663 IceCandidateTypeToStatsType(candidate.type()));
663 report->AddString(StatsReport::kStatsValueNameCandidateTransportType, 664 report->AddString(StatsReport::kStatsValueNameCandidateTransportType,
664 candidate.protocol()); 665 candidate.protocol());
665 } 666 }
666 667
667 return report; 668 return report;
668 } 669 }
669 670
670 void StatsCollector::ExtractSessionInfo() { 671 void StatsCollector::ExtractSessionInfo() {
671 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 672 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
672 673
673 // Extract information from the base session. 674 // Extract information from the base session.
674 StatsReport::Id id(StatsReport::NewTypedId( 675 StatsReport::Id id(StatsReport::NewTypedId(
675 StatsReport::kStatsReportTypeSession, session_->id())); 676 StatsReport::kStatsReportTypeSession, pc_->session()->id()));
676 StatsReport* report = reports_.ReplaceOrAddNew(id); 677 StatsReport* report = reports_.ReplaceOrAddNew(id);
677 report->set_timestamp(stats_gathering_started_); 678 report->set_timestamp(stats_gathering_started_);
678 report->AddBoolean(StatsReport::kStatsValueNameInitiator, 679 report->AddBoolean(StatsReport::kStatsValueNameInitiator,
679 session_->initiator()); 680 pc_->session()->initiator());
680 681
681 cricket::SessionStats stats; 682 cricket::SessionStats stats;
682 if (!session_->GetTransportStats(&stats)) { 683 if (!pc_->session()->GetTransportStats(&stats)) {
683 return; 684 return;
684 } 685 }
685 686
686 // Store the proxy map away for use in SSRC reporting. 687 // Store the proxy map away for use in SSRC reporting.
687 // TODO(tommi): This shouldn't be necessary if we post the stats back to the 688 // TODO(tommi): This shouldn't be necessary if we post the stats back to the
688 // signaling thread after fetching them on the worker thread, then just use 689 // signaling thread after fetching them on the worker thread, then just use
689 // the proxy map directly from the session stats. 690 // the proxy map directly from the session stats.
690 // As is, if GetStats() failed, we could be using old (incorrect?) proxy 691 // As is, if GetStats() failed, we could be using old (incorrect?) proxy
691 // data. 692 // data.
692 proxy_to_transport_ = stats.proxy_to_transport; 693 proxy_to_transport_ = stats.proxy_to_transport;
693 694
694 for (const auto& transport_iter : stats.transport_stats) { 695 for (const auto& transport_iter : stats.transport_stats) {
695 // Attempt to get a copy of the certificates from the transport and 696 // Attempt to get a copy of the certificates from the transport and
696 // expose them in stats reports. All channels in a transport share the 697 // expose them in stats reports. All channels in a transport share the
697 // same local and remote certificates. 698 // same local and remote certificates.
698 // 699 //
699 StatsReport::Id local_cert_report_id, remote_cert_report_id; 700 StatsReport::Id local_cert_report_id, remote_cert_report_id;
700 rtc::scoped_refptr<rtc::RTCCertificate> certificate; 701 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
701 if (session_->GetLocalCertificate(transport_iter.second.transport_name, 702 if (pc_->session()->GetLocalCertificate(
702 &certificate)) { 703 transport_iter.second.transport_name, &certificate)) {
703 StatsReport* r = AddCertificateReports(&(certificate->ssl_certificate())); 704 StatsReport* r = AddCertificateReports(&(certificate->ssl_certificate()));
704 if (r) 705 if (r)
705 local_cert_report_id = r->id(); 706 local_cert_report_id = r->id();
706 } 707 }
707 708
708 rtc::scoped_ptr<rtc::SSLCertificate> cert; 709 rtc::scoped_ptr<rtc::SSLCertificate> cert;
709 if (session_->GetRemoteSSLCertificate(transport_iter.second.transport_name, 710 if (pc_->session()->GetRemoteSSLCertificate(
710 cert.accept())) { 711 transport_iter.second.transport_name, cert.accept())) {
711 StatsReport* r = AddCertificateReports(cert.get()); 712 StatsReport* r = AddCertificateReports(cert.get());
712 if (r) 713 if (r)
713 remote_cert_report_id = r->id(); 714 remote_cert_report_id = r->id();
714 } 715 }
715 716
716 for (const auto& channel_iter : transport_iter.second.channel_stats) { 717 for (const auto& channel_iter : transport_iter.second.channel_stats) {
717 StatsReport::Id id(StatsReport::NewComponentId( 718 StatsReport::Id id(StatsReport::NewComponentId(
718 transport_iter.second.transport_name, channel_iter.component)); 719 transport_iter.second.transport_name, channel_iter.component));
719 StatsReport* channel_report = reports_.ReplaceOrAddNew(id); 720 StatsReport* channel_report = reports_.ReplaceOrAddNew(id);
720 channel_report->set_timestamp(stats_gathering_started_); 721 channel_report->set_timestamp(stats_gathering_started_);
(...skipping 30 matching lines...) Expand all
751 channel_report->AddId( 752 channel_report->AddId(
752 StatsReport::kStatsValueNameSelectedCandidatePairId, 753 StatsReport::kStatsValueNameSelectedCandidatePairId,
753 connection_report->id()); 754 connection_report->id());
754 } 755 }
755 } 756 }
756 } 757 }
757 } 758 }
758 } 759 }
759 760
760 void StatsCollector::ExtractVoiceInfo() { 761 void StatsCollector::ExtractVoiceInfo() {
761 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 762 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
762 763
763 if (!session_->voice_channel()) { 764 if (!pc_->session()->voice_channel()) {
764 return; 765 return;
765 } 766 }
766 cricket::VoiceMediaInfo voice_info; 767 cricket::VoiceMediaInfo voice_info;
767 if (!session_->voice_channel()->GetStats(&voice_info)) { 768 if (!pc_->session()->voice_channel()->GetStats(&voice_info)) {
768 LOG(LS_ERROR) << "Failed to get voice channel stats."; 769 LOG(LS_ERROR) << "Failed to get voice channel stats.";
769 return; 770 return;
770 } 771 }
771 772
772 // TODO(tommi): The above code should run on the worker thread and post the 773 // TODO(tommi): The above code should run on the worker thread and post the
773 // results back to the signaling thread, where we can add data to the reports. 774 // results back to the signaling thread, where we can add data to the reports.
774 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; 775 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
775 776
776 StatsReport::Id transport_id(GetTransportIdFromProxy(proxy_to_transport_, 777 StatsReport::Id transport_id(GetTransportIdFromProxy(
777 session_->voice_channel()->content_name())); 778 proxy_to_transport_, pc_->session()->voice_channel()->content_name()));
778 if (!transport_id.get()) { 779 if (!transport_id.get()) {
779 LOG(LS_ERROR) << "Failed to get transport name for proxy " 780 LOG(LS_ERROR) << "Failed to get transport name for proxy "
780 << session_->voice_channel()->content_name(); 781 << pc_->session()->voice_channel()->content_name();
781 return; 782 return;
782 } 783 }
783 784
784 ExtractStatsFromList(voice_info.receivers, transport_id, this, 785 ExtractStatsFromList(voice_info.receivers, transport_id, this,
785 StatsReport::kReceive); 786 StatsReport::kReceive);
786 ExtractStatsFromList(voice_info.senders, transport_id, this, 787 ExtractStatsFromList(voice_info.senders, transport_id, this,
787 StatsReport::kSend); 788 StatsReport::kSend);
788 789
789 UpdateStatsFromExistingLocalAudioTracks(); 790 UpdateStatsFromExistingLocalAudioTracks();
790 } 791 }
791 792
792 void StatsCollector::ExtractVideoInfo( 793 void StatsCollector::ExtractVideoInfo(
793 PeerConnectionInterface::StatsOutputLevel level) { 794 PeerConnectionInterface::StatsOutputLevel level) {
794 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 795 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
795 796
796 if (!session_->video_channel()) 797 if (!pc_->session()->video_channel())
797 return; 798 return;
798 799
799 cricket::VideoMediaInfo video_info; 800 cricket::VideoMediaInfo video_info;
800 if (!session_->video_channel()->GetStats(&video_info)) { 801 if (!pc_->session()->video_channel()->GetStats(&video_info)) {
801 LOG(LS_ERROR) << "Failed to get video channel stats."; 802 LOG(LS_ERROR) << "Failed to get video channel stats.";
802 return; 803 return;
803 } 804 }
804 805
805 // TODO(tommi): The above code should run on the worker thread and post the 806 // TODO(tommi): The above code should run on the worker thread and post the
806 // results back to the signaling thread, where we can add data to the reports. 807 // results back to the signaling thread, where we can add data to the reports.
807 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; 808 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
808 809
809 StatsReport::Id transport_id(GetTransportIdFromProxy(proxy_to_transport_, 810 StatsReport::Id transport_id(GetTransportIdFromProxy(
810 session_->video_channel()->content_name())); 811 proxy_to_transport_, pc_->session()->video_channel()->content_name()));
811 if (!transport_id.get()) { 812 if (!transport_id.get()) {
812 LOG(LS_ERROR) << "Failed to get transport name for proxy " 813 LOG(LS_ERROR) << "Failed to get transport name for proxy "
813 << session_->video_channel()->content_name(); 814 << pc_->session()->video_channel()->content_name();
814 return; 815 return;
815 } 816 }
816 ExtractStatsFromList(video_info.receivers, transport_id, this, 817 ExtractStatsFromList(video_info.receivers, transport_id, this,
817 StatsReport::kReceive); 818 StatsReport::kReceive);
818 ExtractStatsFromList(video_info.senders, transport_id, this, 819 ExtractStatsFromList(video_info.senders, transport_id, this,
819 StatsReport::kSend); 820 StatsReport::kSend);
820 if (video_info.bw_estimations.size() != 1) { 821 if (video_info.bw_estimations.size() != 1) {
821 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size(); 822 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
822 } else { 823 } else {
823 StatsReport::Id report_id(StatsReport::NewBandwidthEstimationId()); 824 StatsReport::Id report_id(StatsReport::NewBandwidthEstimationId());
824 StatsReport* report = reports_.FindOrAddNew(report_id); 825 StatsReport* report = reports_.FindOrAddNew(report_id);
825 ExtractStats( 826 ExtractStats(
826 video_info.bw_estimations[0], stats_gathering_started_, level, report); 827 video_info.bw_estimations[0], stats_gathering_started_, level, report);
827 } 828 }
828 } 829 }
829 830
830 void StatsCollector::ExtractDataInfo() { 831 void StatsCollector::ExtractDataInfo() {
831 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 832 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
832 833
833 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; 834 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
834 835
835 for (const auto& dc : 836 for (const auto& dc : pc_->sctp_data_channels()) {
836 session_->mediastream_signaling()->sctp_data_channels()) {
837 StatsReport::Id id(StatsReport::NewTypedIntId( 837 StatsReport::Id id(StatsReport::NewTypedIntId(
838 StatsReport::kStatsReportTypeDataChannel, dc->id())); 838 StatsReport::kStatsReportTypeDataChannel, dc->id()));
839 StatsReport* report = reports_.ReplaceOrAddNew(id); 839 StatsReport* report = reports_.ReplaceOrAddNew(id);
840 report->set_timestamp(stats_gathering_started_); 840 report->set_timestamp(stats_gathering_started_);
841 report->AddString(StatsReport::kStatsValueNameLabel, dc->label()); 841 report->AddString(StatsReport::kStatsValueNameLabel, dc->label());
842 report->AddInt(StatsReport::kStatsValueNameDataChannelId, dc->id()); 842 report->AddInt(StatsReport::kStatsValueNameDataChannelId, dc->id());
843 report->AddString(StatsReport::kStatsValueNameProtocol, dc->protocol()); 843 report->AddString(StatsReport::kStatsValueNameProtocol, dc->protocol());
844 report->AddString(StatsReport::kStatsValueNameState, 844 report->AddString(StatsReport::kStatsValueNameState,
845 DataChannelInterface::DataStateString(dc->state())); 845 DataChannelInterface::DataStateString(dc->state()));
846 } 846 }
847 } 847 }
848 848
849 StatsReport* StatsCollector::GetReport(const StatsReport::StatsType& type, 849 StatsReport* StatsCollector::GetReport(const StatsReport::StatsType& type,
850 const std::string& id, 850 const std::string& id,
851 StatsReport::Direction direction) { 851 StatsReport::Direction direction) {
852 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 852 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
853 RTC_DCHECK(type == StatsReport::kStatsReportTypeSsrc || 853 RTC_DCHECK(type == StatsReport::kStatsReportTypeSsrc ||
854 type == StatsReport::kStatsReportTypeRemoteSsrc); 854 type == StatsReport::kStatsReportTypeRemoteSsrc);
855 return reports_.Find(StatsReport::NewIdWithDirection(type, id, direction)); 855 return reports_.Find(StatsReport::NewIdWithDirection(type, id, direction));
856 } 856 }
857 857
858 void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() { 858 void StatsCollector::UpdateStatsFromExistingLocalAudioTracks() {
859 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 859 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
860 // Loop through the existing local audio tracks. 860 // Loop through the existing local audio tracks.
861 for (const auto& it : local_audio_tracks_) { 861 for (const auto& it : local_audio_tracks_) {
862 AudioTrackInterface* track = it.first; 862 AudioTrackInterface* track = it.first;
863 uint32_t ssrc = it.second; 863 uint32_t ssrc = it.second;
864 StatsReport* report = 864 StatsReport* report =
865 GetReport(StatsReport::kStatsReportTypeSsrc, 865 GetReport(StatsReport::kStatsReportTypeSsrc,
866 rtc::ToString<uint32_t>(ssrc), StatsReport::kSend); 866 rtc::ToString<uint32_t>(ssrc), StatsReport::kSend);
867 if (report == NULL) { 867 if (report == NULL) {
868 // This can happen if a local audio track is added to a stream on the 868 // This can happen if a local audio track is added to a stream on the
869 // fly and the report has not been set up yet. Do nothing in this case. 869 // fly and the report has not been set up yet. Do nothing in this case.
870 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc; 870 LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
871 continue; 871 continue;
872 } 872 }
873 873
874 // The same ssrc can be used by both local and remote audio tracks. 874 // The same ssrc can be used by both local and remote audio tracks.
875 const StatsReport::Value* v = 875 const StatsReport::Value* v =
876 report->FindValue(StatsReport::kStatsValueNameTrackId); 876 report->FindValue(StatsReport::kStatsValueNameTrackId);
877 if (!v || v->string_val() != track->id()) 877 if (!v || v->string_val() != track->id())
878 continue; 878 continue;
879 879
880 report->set_timestamp(stats_gathering_started_); 880 report->set_timestamp(stats_gathering_started_);
881 UpdateReportFromAudioTrack(track, report); 881 UpdateReportFromAudioTrack(track, report);
882 } 882 }
883 } 883 }
884 884
885 void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track, 885 void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
886 StatsReport* report) { 886 StatsReport* report) {
887 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 887 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
888 RTC_DCHECK(track != NULL); 888 RTC_DCHECK(track != NULL);
889 889
890 int signal_level = 0; 890 int signal_level = 0;
891 if (!track->GetSignalLevel(&signal_level)) 891 if (!track->GetSignalLevel(&signal_level))
892 signal_level = -1; 892 signal_level = -1;
893 893
894 rtc::scoped_refptr<AudioProcessorInterface> audio_processor( 894 rtc::scoped_refptr<AudioProcessorInterface> audio_processor(
895 track->GetAudioProcessor()); 895 track->GetAudioProcessor());
896 896
897 AudioProcessorInterface::AudioProcessorStats stats; 897 AudioProcessorInterface::AudioProcessorStats stats;
898 if (audio_processor.get()) 898 if (audio_processor.get())
899 audio_processor->GetStats(&stats); 899 audio_processor->GetStats(&stats);
900 900
901 SetAudioProcessingStats(report, signal_level, stats.typing_noise_detected, 901 SetAudioProcessingStats(report, signal_level, stats.typing_noise_detected,
902 stats.echo_return_loss, stats.echo_return_loss_enhancement, 902 stats.echo_return_loss, stats.echo_return_loss_enhancement,
903 stats.echo_delay_median_ms, stats.aec_quality_min, 903 stats.echo_delay_median_ms, stats.aec_quality_min,
904 stats.echo_delay_std_ms); 904 stats.echo_delay_std_ms);
905 } 905 }
906 906
907 bool StatsCollector::GetTrackIdBySsrc(uint32_t ssrc, 907 bool StatsCollector::GetTrackIdBySsrc(uint32_t ssrc,
908 std::string* track_id, 908 std::string* track_id,
909 StatsReport::Direction direction) { 909 StatsReport::Direction direction) {
910 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 910 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
911 if (direction == StatsReport::kSend) { 911 if (direction == StatsReport::kSend) {
912 if (!session_->GetLocalTrackIdBySsrc(ssrc, track_id)) { 912 if (!pc_->session()->GetLocalTrackIdBySsrc(ssrc, track_id)) {
913 LOG(LS_WARNING) << "The SSRC " << ssrc 913 LOG(LS_WARNING) << "The SSRC " << ssrc
914 << " is not associated with a sending track"; 914 << " is not associated with a sending track";
915 return false; 915 return false;
916 } 916 }
917 } else { 917 } else {
918 RTC_DCHECK(direction == StatsReport::kReceive); 918 RTC_DCHECK(direction == StatsReport::kReceive);
919 if (!session_->GetRemoteTrackIdBySsrc(ssrc, track_id)) { 919 if (!pc_->session()->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
920 LOG(LS_WARNING) << "The SSRC " << ssrc 920 LOG(LS_WARNING) << "The SSRC " << ssrc
921 << " is not associated with a receiving track"; 921 << " is not associated with a receiving track";
922 return false; 922 return false;
923 } 923 }
924 } 924 }
925 925
926 return true; 926 return true;
927 } 927 }
928 928
929 void StatsCollector::UpdateTrackReports() { 929 void StatsCollector::UpdateTrackReports() {
930 RTC_DCHECK(session_->signaling_thread()->IsCurrent()); 930 RTC_DCHECK(pc_->session()->signaling_thread()->IsCurrent());
931 931
932 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; 932 rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
933 933
934 for (const auto& entry : track_ids_) { 934 for (const auto& entry : track_ids_) {
935 StatsReport* report = entry.second; 935 StatsReport* report = entry.second;
936 report->set_timestamp(stats_gathering_started_); 936 report->set_timestamp(stats_gathering_started_);
937 } 937 }
938 } 938 }
939 939
940 void StatsCollector::ClearUpdateStatsCacheForTest() { 940 void StatsCollector::ClearUpdateStatsCacheForTest() {
941 stats_gathering_started_ = 0; 941 stats_gathering_started_ = 0;
942 } 942 }
943 943
944 } // namespace webrtc 944 } // namespace webrtc
OLDNEW
« no previous file with comments | « talk/app/webrtc/statscollector.h ('k') | talk/app/webrtc/statscollector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698