Index: webrtc/stats/rtcstatscollector.cc |
diff --git a/webrtc/stats/rtcstatscollector.cc b/webrtc/stats/rtcstatscollector.cc |
index 6cb2a31b44b155beddcfbf0d97d63603e6170568..992b32c7b07573c21bc348f0a1ffc45c836426f3 100644 |
--- a/webrtc/stats/rtcstatscollector.cc |
+++ b/webrtc/stats/rtcstatscollector.cc |
@@ -19,45 +19,162 @@ |
namespace webrtc { |
+rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create( |
+ PeerConnection* pc, |
+ double cache_lifetime, |
+ std::unique_ptr<rtc::Timing> timing) { |
+ return rtc::scoped_refptr<RTCStatsCollector>( |
+ new rtc::RefCountedObject<RTCStatsCollector>( |
+ pc, cache_lifetime, timing.release())); |
+} |
+ |
RTCStatsCollector::RTCStatsCollector( |
PeerConnection* pc, |
double cache_lifetime, |
- std::unique_ptr<rtc::Timing> timing) |
+ rtc::Timing* timing) |
: pc_(pc), |
- timing_(std::move(timing)), |
+ signaling_thread_(pc->session()->signaling_thread()), |
+ worker_thread_(pc->session()->worker_thread()), |
+ network_thread_(pc->session()->network_thread()), |
+ num_pending_partial_reports_(0), |
+ timing_(timing), |
cache_timestamp_(0.0), |
cache_lifetime_(cache_lifetime) { |
RTC_DCHECK(pc_); |
+ RTC_DCHECK(signaling_thread_); |
+ RTC_DCHECK(worker_thread_); |
+ RTC_DCHECK(network_thread_); |
RTC_DCHECK(timing_); |
- RTC_DCHECK(IsOnSignalingThread()); |
RTC_DCHECK_GE(cache_lifetime_, 0.0); |
} |
-rtc::scoped_refptr<const RTCStatsReport> RTCStatsCollector::GetStatsReport() { |
- RTC_DCHECK(IsOnSignalingThread()); |
- double now = timing_->TimerNow(); |
- if (cached_report_ && now - cache_timestamp_ <= cache_lifetime_) |
- return cached_report_; |
- cache_timestamp_ = now; |
+void RTCStatsCollector::GetStatsReport( |
+ rtc::scoped_refptr<RTCStatsCollectorCallback> callback) { |
+ RTC_DCHECK(signaling_thread_->IsCurrent()); |
+ RTC_DCHECK(callback); |
+ rtc::scoped_refptr<const RTCStatsReport> cached_report; |
+ std::vector<rtc::scoped_refptr<RTCStatsCollectorCallback>> callbacks; |
+ { |
+ rtc::CritScope cs(&lock_); |
+ callbacks_.push_back(callback); |
+ double now = timing_->TimerNow(); |
+ if (cached_report_ && now - cache_timestamp_ <= cache_lifetime_) { |
+ // We have a fresh cached report to immediately deliver. |
+ cached_report = cached_report_; |
+ callbacks = callbacks_; |
hta-webrtc
2016/08/31 09:57:36
So you use "callbacks" to pass the list of callbac
hbos
2016/09/01 14:16:16
Ah, only |num_pending_partial_reports_| and |parti
|
+ callbacks_.clear(); |
+ } else if (!num_pending_partial_reports_) { |
+ // We don't have a fresh cached report and we are not already in the |
+ // process of gathering stats. |
+ num_pending_partial_reports_ = 3; |
+ invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
+ rtc::Bind( |
+ &RTCStatsCollector::ProducePartialResultsOnSignalingThread_s, |
+ rtc::scoped_refptr<RTCStatsCollector>(this), now)); |
+ invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_, |
+ rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnWorkerThread_w, |
+ rtc::scoped_refptr<RTCStatsCollector>(this), now)); |
+ invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_, |
+ rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread_n, |
+ rtc::scoped_refptr<RTCStatsCollector>(this), now)); |
+ } |
hta-webrtc
2016/08/31 09:57:36
Where's the "else" branch (the report isn't fresh
hbos
2016/09/01 14:16:16
callback_ has been added to callbacks_ and will be
|
+ } |
+ // Do we have a cached report that is still fresh to deliver? |
+ // Then do so without holding the lock. |
+ if (cached_report) { |
+ for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback : |
+ callbacks) { |
+ callback->OnStatsDelivered(cached_report); |
+ } |
+ return; |
+ } |
+} |
+ |
+void RTCStatsCollector::ClearCachedStatsReport() { |
+ RTC_DCHECK(signaling_thread_->IsCurrent()); |
+ rtc::CritScope cs(&lock_); |
+ cached_report_ = nullptr; |
+} |
+void RTCStatsCollector::ProducePartialResultsOnSignalingThread_s( |
+ double timestamp) { |
+ RTC_DCHECK(signaling_thread_->IsCurrent()); |
rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
- report->AddStats(ProducePeerConnectionStats()); |
- cached_report_ = report; |
- return cached_report_; |
+ report->AddStats(ProducePeerConnectionStats_s(timestamp)); |
+ |
+ AddPartialResults(report, timestamp); |
} |
-void RTCStatsCollector::ClearCachedStatsReport() { |
- RTC_DCHECK(IsOnSignalingThread()); |
- cached_report_ = nullptr; |
+void RTCStatsCollector::ProducePartialResultsOnWorkerThread_w( |
+ double timestamp) { |
+ RTC_DCHECK(worker_thread_->IsCurrent()); |
+ rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
+ |
+ // TODO(hbos): Gather stats on worker thread. |
+ |
+ AddPartialResults(report, timestamp); |
+} |
+ |
+void RTCStatsCollector::ProducePartialResultsOnNetworkThread_n( |
+ double timestamp) { |
+ RTC_DCHECK(network_thread_->IsCurrent()); |
+ rtc::scoped_refptr<RTCStatsReport> report = RTCStatsReport::Create(); |
+ |
+ // TODO(hbos): Gather stats on network thread. |
+ |
+ AddPartialResults(report, timestamp); |
+} |
+ |
+void RTCStatsCollector::AddPartialResults( |
+ const rtc::scoped_refptr<RTCStatsReport>& partial_report, |
+ double timestamp) { |
+ if (!signaling_thread_->IsCurrent()) { |
+ invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, |
+ rtc::Bind(&RTCStatsCollector::AddPartialResults_s, |
+ rtc::scoped_refptr<RTCStatsCollector>(this), |
+ partial_report, timestamp)); |
+ return; |
+ } |
+ AddPartialResults_s(partial_report, timestamp); |
} |
-bool RTCStatsCollector::IsOnSignalingThread() const { |
- return pc_->session()->signaling_thread()->IsCurrent(); |
+void RTCStatsCollector::AddPartialResults_s( |
+ rtc::scoped_refptr<RTCStatsReport> partial_report, double timestamp) { |
+ RTC_DCHECK(signaling_thread_->IsCurrent()); |
+ rtc::scoped_refptr<const RTCStatsReport> result; |
+ std::vector<rtc::scoped_refptr<RTCStatsCollectorCallback>> callbacks; |
+ { |
+ rtc::CritScope cs(&lock_); |
+ RTC_DCHECK_GT(num_pending_partial_reports_, 0); |
+ if (!partial_report_) |
+ partial_report_ = partial_report; |
+ else |
+ partial_report_->TakeMembersFrom(partial_report); |
+ --num_pending_partial_reports_; |
+ |
+ // Was this the last pending partial report, resulting in a complete and |
+ // deliverable |result|? |
+ if (!num_pending_partial_reports_) { |
+ result = cached_report_ = partial_report_; |
+ cache_timestamp_ = timestamp; |
+ partial_report_ = nullptr; |
+ callbacks = callbacks_; |
+ callbacks_.clear(); |
+ } |
+ } |
+ // Do we have a report to deliver? Then do so without holding the lock. |
+ if (result) { |
+ for (const rtc::scoped_refptr<RTCStatsCollectorCallback>& callback : |
+ callbacks) { |
+ callback->OnStatsDelivered(result); |
+ } |
+ } |
} |
std::unique_ptr<RTCPeerConnectionStats> |
-RTCStatsCollector::ProducePeerConnectionStats() const { |
+RTCStatsCollector::ProducePeerConnectionStats_s(double timestamp) const { |
+ RTC_DCHECK(signaling_thread_->IsCurrent()); |
// TODO(hbos): If data channels are removed from the peer connection this will |
// yield incorrect counts. Address before closing crbug.com/636818. See |
// https://w3c.github.io/webrtc-stats/webrtc-stats.html#pcstats-dict*. |
@@ -71,7 +188,7 @@ RTCStatsCollector::ProducePeerConnectionStats() const { |
// There is always just one |RTCPeerConnectionStats| so its |id| can be a |
// constant. |
std::unique_ptr<RTCPeerConnectionStats> stats( |
- new RTCPeerConnectionStats("RTCPeerConnection", cache_timestamp_)); |
+ new RTCPeerConnectionStats("RTCPeerConnection", timestamp)); |
stats->data_channels_opened = data_channels_opened; |
stats->data_channels_closed = static_cast<uint32_t>(data_channels.size()) - |
data_channels_opened; |