blob: 06c4b44b082f0fb42b3b08af0ba7068871642027 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, 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 "talk/app/webrtc/statscollector.h"
29
30#include <utility>
31#include <vector>
32
33#include "talk/session/media/channel.h"
34
35namespace webrtc {
36
37// The items below are in alphabetical order.
38const char StatsReport::kStatsValueNameActiveConnection[] =
39 "googActiveConnection";
40const char StatsReport::kStatsValueNameActualEncBitrate[] =
41 "googActualEncBitrate";
42const char StatsReport::kStatsValueNameAudioOutputLevel[] = "audioOutputLevel";
43const char StatsReport::kStatsValueNameAudioInputLevel[] = "audioInputLevel";
44const char StatsReport::kStatsValueNameAvailableReceiveBandwidth[] =
45 "googAvailableReceiveBandwidth";
46const char StatsReport::kStatsValueNameAvailableSendBandwidth[] =
47 "googAvailableSendBandwidth";
48const char StatsReport::kStatsValueNameBucketDelay[] = "googBucketDelay";
49const char StatsReport::kStatsValueNameBytesReceived[] = "bytesReceived";
50const char StatsReport::kStatsValueNameBytesSent[] = "bytesSent";
51const char StatsReport::kStatsValueNameChannelId[] = "googChannelId";
52const char StatsReport::kStatsValueNameCodecName[] = "googCodecName";
53const char StatsReport::kStatsValueNameComponent[] = "googComponent";
54const char StatsReport::kStatsValueNameContentName[] = "googContentName";
55// Echo metrics from the audio processing module.
56const char StatsReport::kStatsValueNameEchoCancellationQualityMin[] =
57 "googEchoCancellationQualityMin";
58const char StatsReport::kStatsValueNameEchoDelayMedian[] =
59 "googEchoCancellationEchoDelayMedian";
60const char StatsReport::kStatsValueNameEchoDelayStdDev[] =
61 "googEchoCancellationEchoDelayStdDev";
62const char StatsReport::kStatsValueNameEchoReturnLoss[] =
63 "googEchoCancellationReturnLoss";
64const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
65 "googEchoCancellationReturnLossEnhancement";
66
67const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
68const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
69const char StatsReport::kStatsValueNameFrameHeightReceived[] =
70 "googFrameHeightReceived";
71const char StatsReport::kStatsValueNameFrameHeightSent[] =
72 "googFrameHeightSent";
73const char StatsReport::kStatsValueNameFrameRateReceived[] =
74 "googFrameRateReceived";
75const char StatsReport::kStatsValueNameFrameRateDecoded[] =
76 "googFrameRateDecoded";
77const char StatsReport::kStatsValueNameFrameRateOutput[] =
78 "googFrameRateOutput";
79const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
80const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
81const char StatsReport::kStatsValueNameFrameWidthReceived[] =
82 "googFrameWidthReceived";
83const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
84const char StatsReport::kStatsValueNameInitiator[] = "googInitiator";
85const char StatsReport::kStatsValueNameJitterReceived[] = "googJitterReceived";
86const char StatsReport::kStatsValueNameLocalAddress[] = "googLocalAddress";
87const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
88const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
89const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
90const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
91const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
92const char StatsReport::kStatsValueNameReadable[] = "googReadable";
93const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
94const char StatsReport::kStatsValueNameRetransmitBitrate[] =
95 "googRetransmitBitrate";
96const char StatsReport::kStatsValueNameRtt[] = "googRtt";
wu@webrtc.org967bfff2013-09-19 05:49:50 +000097const char StatsReport::kStatsValueNameSsrc[] = "ssrc";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098const char StatsReport::kStatsValueNameTargetEncBitrate[] =
99 "googTargetEncBitrate";
100const char StatsReport::kStatsValueNameTransmitBitrate[] =
101 "googTransmitBitrate";
102const char StatsReport::kStatsValueNameTransportId[] = "transportId";
103const char StatsReport::kStatsValueNameTransportType[] = "googTransportType";
104const char StatsReport::kStatsValueNameTrackId[] = "googTrackId";
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000105const char StatsReport::kStatsValueNameTypingNoiseState[] =
106 "googTypingNoiseState";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107const char StatsReport::kStatsValueNameWritable[] = "googWritable";
108
109const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
110const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
111const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
112const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
113const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
114const char StatsReport::kStatsReportTypeTransport[] = "googTransport";
115const char StatsReport::kStatsReportTypeComponent[] = "googComponent";
116const char StatsReport::kStatsReportTypeCandidatePair[] = "googCandidatePair";
117
118const char StatsReport::kStatsReportVideoBweId[] = "bweforvideo";
119
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000120
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121// Implementations of functions in statstypes.h
122void StatsReport::AddValue(const std::string& name, const std::string& value) {
123 Value temp;
124 temp.name = name;
125 temp.value = value;
126 values.push_back(temp);
127}
128
129void StatsReport::AddValue(const std::string& name, int64 value) {
130 AddValue(name, talk_base::ToString<int64>(value));
131}
132
133void StatsReport::AddBoolean(const std::string& name, bool value) {
134 AddValue(name, value ? "true" : "false");
135}
136
137namespace {
138typedef std::map<std::string, StatsReport> StatsMap;
139
140std::string StatsId(const std::string& type, const std::string& id) {
141 return type + "_" + id;
142}
143
144bool ExtractValueFromReport(
145 const StatsReport& report,
146 const std::string& name,
147 std::string* value) {
148 StatsReport::Values::const_iterator it = report.values.begin();
149 for (; it != report.values.end(); ++it) {
150 if (it->name == name) {
151 *value = it->value;
152 return true;
153 }
154 }
155 return false;
156}
157
158template <class TrackVector>
159void CreateTrackReports(const TrackVector& tracks, StatsMap* reports) {
160 for (size_t j = 0; j < tracks.size(); ++j) {
161 webrtc::MediaStreamTrackInterface* track = tracks[j];
162 // Adds an empty track report.
163 StatsReport report;
164 report.type = StatsReport::kStatsReportTypeTrack;
165 report.id = StatsId(StatsReport::kStatsReportTypeTrack, track->id());
166 report.AddValue(StatsReport::kStatsValueNameTrackId,
167 track->id());
168 (*reports)[report.id] = report;
169 }
170}
171
172void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
173 report->AddValue(StatsReport::kStatsValueNameAudioOutputLevel,
174 info.audio_level);
175 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
176 info.bytes_rcvd);
177 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
178 info.jitter_ms);
179 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
180 info.packets_rcvd);
181 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
182 info.packets_lost);
183}
184
185void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
186 report->AddValue(StatsReport::kStatsValueNameAudioInputLevel,
187 info.audio_level);
188 report->AddValue(StatsReport::kStatsValueNameBytesSent,
189 info.bytes_sent);
190 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
191 info.packets_sent);
192 report->AddValue(StatsReport::kStatsValueNameJitterReceived,
193 info.jitter_ms);
194 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
195 report->AddValue(StatsReport::kStatsValueNameEchoCancellationQualityMin,
196 talk_base::ToString<float>(info.aec_quality_min));
197 report->AddValue(StatsReport::kStatsValueNameEchoDelayMedian,
198 info.echo_delay_median_ms);
199 report->AddValue(StatsReport::kStatsValueNameEchoDelayStdDev,
200 info.echo_delay_std_ms);
201 report->AddValue(StatsReport::kStatsValueNameEchoReturnLoss,
202 info.echo_return_loss);
203 report->AddValue(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
204 info.echo_return_loss_enhancement);
205 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000206 report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
207 info.typing_noise_detected);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208}
209
210void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
211 report->AddValue(StatsReport::kStatsValueNameBytesReceived,
212 info.bytes_rcvd);
213 report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
214 info.packets_rcvd);
215 report->AddValue(StatsReport::kStatsValueNamePacketsLost,
216 info.packets_lost);
217
218 report->AddValue(StatsReport::kStatsValueNameFirsSent,
219 info.firs_sent);
220 report->AddValue(StatsReport::kStatsValueNameNacksSent,
221 info.nacks_sent);
222 report->AddValue(StatsReport::kStatsValueNameFrameWidthReceived,
223 info.frame_width);
224 report->AddValue(StatsReport::kStatsValueNameFrameHeightReceived,
225 info.frame_height);
226 report->AddValue(StatsReport::kStatsValueNameFrameRateReceived,
227 info.framerate_rcvd);
228 report->AddValue(StatsReport::kStatsValueNameFrameRateDecoded,
229 info.framerate_decoded);
230 report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
231 info.framerate_output);
232}
233
234void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
235 report->AddValue(StatsReport::kStatsValueNameBytesSent,
236 info.bytes_sent);
237 report->AddValue(StatsReport::kStatsValueNamePacketsSent,
238 info.packets_sent);
239
240 report->AddValue(StatsReport::kStatsValueNameFirsReceived,
241 info.firs_rcvd);
242 report->AddValue(StatsReport::kStatsValueNameNacksReceived,
243 info.nacks_rcvd);
244 report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
245 info.frame_width);
246 report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
247 info.frame_height);
248 report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
249 info.framerate_input);
250 report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
251 info.framerate_sent);
252 report->AddValue(StatsReport::kStatsValueNameRtt, info.rtt_ms);
253 report->AddValue(StatsReport::kStatsValueNameCodecName, info.codec_name);
254}
255
256void ExtractStats(const cricket::BandwidthEstimationInfo& info,
257 double stats_gathering_started,
258 StatsReport* report) {
259 report->id = StatsReport::kStatsReportVideoBweId;
260 report->type = StatsReport::kStatsReportTypeBwe;
261
262 // Clear out stats from previous GatherStats calls if any.
263 if (report->timestamp != stats_gathering_started) {
264 report->values.clear();
265 report->timestamp = stats_gathering_started;
266 }
267
268 report->AddValue(StatsReport::kStatsValueNameAvailableSendBandwidth,
269 info.available_send_bandwidth);
270 report->AddValue(StatsReport::kStatsValueNameAvailableReceiveBandwidth,
271 info.available_recv_bandwidth);
272 report->AddValue(StatsReport::kStatsValueNameTargetEncBitrate,
273 info.target_enc_bitrate);
274 report->AddValue(StatsReport::kStatsValueNameActualEncBitrate,
275 info.actual_enc_bitrate);
276 report->AddValue(StatsReport::kStatsValueNameRetransmitBitrate,
277 info.retransmit_bitrate);
278 report->AddValue(StatsReport::kStatsValueNameTransmitBitrate,
279 info.transmit_bitrate);
280 report->AddValue(StatsReport::kStatsValueNameBucketDelay,
281 info.bucket_delay);
282}
283
284uint32 ExtractSsrc(const cricket::VoiceReceiverInfo& info) {
285 return info.ssrc;
286}
287
288uint32 ExtractSsrc(const cricket::VoiceSenderInfo& info) {
289 return info.ssrc;
290}
291
292uint32 ExtractSsrc(const cricket::VideoReceiverInfo& info) {
293 return info.ssrcs[0];
294}
295
296uint32 ExtractSsrc(const cricket::VideoSenderInfo& info) {
297 return info.ssrcs[0];
298}
299
300// Template to extract stats from a data vector.
301// ExtractSsrc and ExtractStats must be defined and overloaded for each type.
302template<typename T>
303void ExtractStatsFromList(const std::vector<T>& data,
304 const std::string& transport_id,
305 StatsCollector* collector) {
306 typename std::vector<T>::const_iterator it = data.begin();
307 for (; it != data.end(); ++it) {
308 std::string id;
309 uint32 ssrc = ExtractSsrc(*it);
310 StatsReport* report = collector->PrepareReport(ssrc, transport_id);
311 if (!report) {
312 continue;
313 }
314 ExtractStats(*it, report);
315 }
316};
317
318} // namespace
319
320StatsCollector::StatsCollector()
321 : session_(NULL), stats_gathering_started_(0) {
322}
323
324// Adds a MediaStream with tracks that can be used as a |selector| in a call
325// to GetStats.
326void StatsCollector::AddStream(MediaStreamInterface* stream) {
327 ASSERT(stream != NULL);
328
329 CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(),
330 &reports_);
331 CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(),
332 &reports_);
333}
334
335bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
336 StatsReports* reports) {
337 ASSERT(reports != NULL);
338 reports->clear();
339
340 StatsMap::iterator it;
341 if (!track) {
342 for (it = reports_.begin(); it != reports_.end(); ++it) {
343 reports->push_back(it->second);
344 }
345 return true;
346 }
347
348 it = reports_.find(StatsId(StatsReport::kStatsReportTypeSession,
349 session_->id()));
350 if (it != reports_.end()) {
351 reports->push_back(it->second);
352 }
353
354 it = reports_.find(StatsId(StatsReport::kStatsReportTypeTrack, track->id()));
355
356 if (it == reports_.end()) {
357 LOG(LS_WARNING) << "No StatsReport is available for "<< track->id();
358 return false;
359 }
360
361 reports->push_back(it->second);
362
363 std::string track_id;
364 for (it = reports_.begin(); it != reports_.end(); ++it) {
365 if (it->second.type != StatsReport::kStatsReportTypeSsrc) {
366 continue;
367 }
368 if (ExtractValueFromReport(it->second,
369 StatsReport::kStatsValueNameTrackId,
370 &track_id)) {
371 if (track_id == track->id()) {
372 reports->push_back(it->second);
373 }
374 }
375 }
376
377 return true;
378}
379
380void StatsCollector::UpdateStats() {
381 double time_now = GetTimeNow();
382 // Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
383 // ms apart will be ignored.
384 const double kMinGatherStatsPeriod = 50;
385 if (stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
386 return;
387 }
388 stats_gathering_started_ = time_now;
389
390 if (session_) {
391 ExtractSessionInfo();
392 ExtractVoiceInfo();
393 ExtractVideoInfo();
394 }
395}
396
397StatsReport* StatsCollector::PrepareReport(uint32 ssrc,
398 const std::string& transport_id) {
399 std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
400 StatsMap::iterator it = reports_.find(StatsId(
401 StatsReport::kStatsReportTypeSsrc, ssrc_id));
402
403 std::string track_id;
404 if (it == reports_.end()) {
405 if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000406 LOG(LS_WARNING) << "The SSRC " << ssrc
407 << " is not associated with a track";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408 return NULL;
409 }
410 } else {
411 // Keeps the old track id since we want to report the stats for inactive
412 // tracks.
413 ExtractValueFromReport(it->second,
414 StatsReport::kStatsValueNameTrackId,
415 &track_id);
416 }
417
418 StatsReport* report = &reports_[
419 StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id)];
420 report->id = StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id);
421 report->type = StatsReport::kStatsReportTypeSsrc;
422
423 // Clear out stats from previous GatherStats calls if any.
424 if (report->timestamp != stats_gathering_started_) {
425 report->values.clear();
426 report->timestamp = stats_gathering_started_;
427 }
428
429 report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
430 report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
431 // Add the mapping of SSRC to transport.
432 report->AddValue(StatsReport::kStatsValueNameTransportId,
433 transport_id);
434 return report;
435}
436
437void StatsCollector::ExtractSessionInfo() {
438 // Extract information from the base session.
439 StatsReport report;
440 report.id = StatsId(StatsReport::kStatsReportTypeSession, session_->id());
441 report.type = StatsReport::kStatsReportTypeSession;
442 report.timestamp = stats_gathering_started_;
443 report.values.clear();
444 report.AddBoolean(StatsReport::kStatsValueNameInitiator,
445 session_->initiator());
446
447 reports_[report.id] = report;
448
449 cricket::SessionStats stats;
450 if (session_->GetStats(&stats)) {
451 // Store the proxy map away for use in SSRC reporting.
452 proxy_to_transport_ = stats.proxy_to_transport;
453
454 for (cricket::TransportStatsMap::iterator transport_iter
455 = stats.transport_stats.begin();
456 transport_iter != stats.transport_stats.end(); ++transport_iter) {
457 for (cricket::TransportChannelStatsList::iterator channel_iter
458 = transport_iter->second.channel_stats.begin();
459 channel_iter != transport_iter->second.channel_stats.end();
460 ++channel_iter) {
461 StatsReport channel_report;
462 std::ostringstream ostc;
463 ostc << "Channel-" << transport_iter->second.content_name
464 << "-" << channel_iter->component;
465 channel_report.id = ostc.str();
466 channel_report.type = StatsReport::kStatsReportTypeComponent;
467 channel_report.timestamp = stats_gathering_started_;
468 channel_report.AddValue(StatsReport::kStatsValueNameComponent,
469 channel_iter->component);
470 reports_[channel_report.id] = channel_report;
471 for (size_t i = 0;
472 i < channel_iter->connection_infos.size();
473 ++i) {
474 StatsReport report;
475 const cricket::ConnectionInfo& info
476 = channel_iter->connection_infos[i];
477 std::ostringstream ost;
478 ost << "Conn-" << transport_iter->first << "-"
479 << channel_iter->component << "-" << i;
480 report.id = ost.str();
481 report.type = StatsReport::kStatsReportTypeCandidatePair;
482 report.timestamp = stats_gathering_started_;
483 // Link from connection to its containing channel.
484 report.AddValue(StatsReport::kStatsValueNameChannelId,
485 channel_report.id);
486 report.AddValue(StatsReport::kStatsValueNameBytesSent,
487 info.sent_total_bytes);
488 report.AddValue(StatsReport::kStatsValueNameBytesReceived,
489 info.recv_total_bytes);
490 report.AddBoolean(StatsReport::kStatsValueNameWritable,
491 info.writable);
492 report.AddBoolean(StatsReport::kStatsValueNameReadable,
493 info.readable);
494 report.AddBoolean(StatsReport::kStatsValueNameActiveConnection,
495 info.best_connection);
496 report.AddValue(StatsReport::kStatsValueNameLocalAddress,
497 info.local_candidate.address().ToString());
498 report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
499 info.remote_candidate.address().ToString());
500 reports_[report.id] = report;
501 }
502 }
503 }
504 }
505}
506
507void StatsCollector::ExtractVoiceInfo() {
508 if (!session_->voice_channel()) {
509 return;
510 }
511 cricket::VoiceMediaInfo voice_info;
512 if (!session_->voice_channel()->GetStats(&voice_info)) {
513 LOG(LS_ERROR) << "Failed to get voice channel stats.";
514 return;
515 }
516 std::string transport_id;
517 if (!GetTransportIdFromProxy(session_->voice_channel()->content_name(),
518 &transport_id)) {
519 LOG(LS_ERROR) << "Failed to get transport name for proxy "
520 << session_->voice_channel()->content_name();
521 return;
522 }
523 ExtractStatsFromList(voice_info.receivers, transport_id, this);
524 ExtractStatsFromList(voice_info.senders, transport_id, this);
525}
526
527void StatsCollector::ExtractVideoInfo() {
528 if (!session_->video_channel()) {
529 return;
530 }
531 cricket::VideoMediaInfo video_info;
532 if (!session_->video_channel()->GetStats(&video_info)) {
533 LOG(LS_ERROR) << "Failed to get video channel stats.";
534 return;
535 }
536 std::string transport_id;
537 if (!GetTransportIdFromProxy(session_->video_channel()->content_name(),
538 &transport_id)) {
539 LOG(LS_ERROR) << "Failed to get transport name for proxy "
540 << session_->video_channel()->content_name();
541 return;
542 }
543 ExtractStatsFromList(video_info.receivers, transport_id, this);
544 ExtractStatsFromList(video_info.senders, transport_id, this);
545 if (video_info.bw_estimations.size() != 1) {
546 LOG(LS_ERROR) << "BWEs count: " << video_info.bw_estimations.size();
547 } else {
548 StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
549 ExtractStats(
550 video_info.bw_estimations[0], stats_gathering_started_, report);
551 }
552}
553
554double StatsCollector::GetTimeNow() {
555 return timing_.WallTimeNow() * talk_base::kNumMillisecsPerSec;
556}
557
558bool StatsCollector::GetTransportIdFromProxy(const std::string& proxy,
559 std::string* transport) {
560 // TODO(hta): Remove handling of empty proxy name once tests do not use it.
561 if (proxy.empty()) {
562 transport->clear();
563 return true;
564 }
565 if (proxy_to_transport_.find(proxy) == proxy_to_transport_.end()) {
566 LOG(LS_ERROR) << "No transport ID mapping for " << proxy;
567 return false;
568 }
569 std::ostringstream ost;
570 // Component 1 is always used for RTP.
571 ost << "Channel-" << proxy_to_transport_[proxy] << "-1";
572 *transport = ost.str();
573 return true;
574}
575
576} // namespace webrtc