OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/rtcp/rtcp.h" | 5 #include "media/cast/rtcp/rtcp.h" |
6 | 6 |
7 #include "base/big_endian.h" | 7 #include "base/big_endian.h" |
8 #include "base/rand_util.h" | 8 #include "base/rand_util.h" |
9 #include "media/cast/cast_config.h" | 9 #include "media/cast/cast_config.h" |
10 #include "media/cast/cast_defines.h" | 10 #include "media/cast/cast_defines.h" |
11 #include "media/cast/cast_environment.h" | 11 #include "media/cast/cast_environment.h" |
12 #include "media/cast/rtcp/rtcp_defines.h" | 12 #include "media/cast/rtcp/rtcp_defines.h" |
13 #include "media/cast/rtcp/rtcp_receiver.h" | 13 #include "media/cast/rtcp/rtcp_receiver.h" |
14 #include "media/cast/rtcp/rtcp_sender.h" | 14 #include "media/cast/rtcp/rtcp_sender.h" |
15 #include "media/cast/rtcp/rtcp_utility.h" | 15 #include "media/cast/rtcp/rtcp_utility.h" |
16 #include "media/cast/transport/cast_transport_defines.h" | 16 #include "media/cast/transport/cast_transport_defines.h" |
17 | 17 |
18 namespace media { | 18 namespace media { |
19 namespace cast { | 19 namespace cast { |
20 | 20 |
21 static const int kMaxRttMs = 10000; // 10 seconds. | 21 static const int kMaxRttMs = 10000; // 10 seconds. |
22 static const uint16 kMaxDelay = 2000; | 22 static const int kMaxDelay = 2000; |
23 | |
24 // Time limit for received RTCP messages when we stop using it for lip-sync. | |
25 static const int64 kMaxDiffSinceReceivedRtcpMs = 100000; // 100 seconds. | |
26 | 23 |
27 class LocalRtcpRttFeedback : public RtcpRttFeedback { | 24 class LocalRtcpRttFeedback : public RtcpRttFeedback { |
28 public: | 25 public: |
29 explicit LocalRtcpRttFeedback(Rtcp* rtcp) : rtcp_(rtcp) {} | 26 explicit LocalRtcpRttFeedback(Rtcp* rtcp) : rtcp_(rtcp) {} |
30 | 27 |
31 virtual void OnReceivedDelaySinceLastReport( | 28 virtual void OnReceivedDelaySinceLastReport( |
32 uint32 receivers_ssrc, uint32 last_report, | 29 uint32 receivers_ssrc, uint32 last_report, |
33 uint32 delay_since_last_report) OVERRIDE { | 30 uint32 delay_since_last_report) OVERRIDE { |
34 rtcp_->OnReceivedDelaySinceLastReport(receivers_ssrc, last_report, | 31 rtcp_->OnReceivedDelaySinceLastReport(receivers_ssrc, last_report, |
35 delay_since_last_report); | 32 delay_since_last_report); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 rtcp_interval_(rtcp_interval), | 85 rtcp_interval_(rtcp_interval), |
89 rtcp_mode_(rtcp_mode), | 86 rtcp_mode_(rtcp_mode), |
90 local_ssrc_(local_ssrc), | 87 local_ssrc_(local_ssrc), |
91 remote_ssrc_(remote_ssrc), | 88 remote_ssrc_(remote_ssrc), |
92 c_name_(c_name), | 89 c_name_(c_name), |
93 rtp_receiver_statistics_(rtp_receiver_statistics), | 90 rtp_receiver_statistics_(rtp_receiver_statistics), |
94 rtt_feedback_(new LocalRtcpRttFeedback(this)), | 91 rtt_feedback_(new LocalRtcpRttFeedback(this)), |
95 receiver_feedback_(new LocalRtcpReceiverFeedback(this, cast_environment)), | 92 receiver_feedback_(new LocalRtcpReceiverFeedback(this, cast_environment)), |
96 rtcp_sender_(new RtcpSender(cast_environment, paced_packet_sender, | 93 rtcp_sender_(new RtcpSender(cast_environment, paced_packet_sender, |
97 local_ssrc, c_name)), | 94 local_ssrc, c_name)), |
98 last_report_received_(0), | 95 last_report_truncated_ntp_(0), |
99 last_received_rtp_timestamp_(0), | 96 local_clock_ahead_by_(ClockDriftSmoother::GetDefaultTimeConstant()), |
100 last_received_ntp_seconds_(0), | 97 lip_sync_rtp_timestamp_(0), |
101 last_received_ntp_fraction_(0), | 98 lip_sync_ntp_timestamp_(0), |
102 min_rtt_(base::TimeDelta::FromMilliseconds(kMaxRttMs)), | 99 min_rtt_(base::TimeDelta::FromMilliseconds(kMaxRttMs)), |
103 number_of_rtt_in_avg_(0), | 100 number_of_rtt_in_avg_(0), |
104 is_audio_(is_audio) { | 101 is_audio_(is_audio) { |
105 rtcp_receiver_.reset(new RtcpReceiver(cast_environment, sender_feedback, | 102 rtcp_receiver_.reset(new RtcpReceiver(cast_environment, sender_feedback, |
106 receiver_feedback_.get(), | 103 receiver_feedback_.get(), |
107 rtt_feedback_.get(), local_ssrc)); | 104 rtt_feedback_.get(), local_ssrc)); |
108 rtcp_receiver_->SetRemoteSSRC(remote_ssrc); | 105 rtcp_receiver_->SetRemoteSSRC(remote_ssrc); |
109 } | 106 } |
110 | 107 |
111 Rtcp::~Rtcp() {} | 108 Rtcp::~Rtcp() {} |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 packet_type_flags |= transport::kRtcpRr; | 174 packet_type_flags |= transport::kRtcpRr; |
178 | 175 |
179 report_block.remote_ssrc = 0; // Not needed to set send side. | 176 report_block.remote_ssrc = 0; // Not needed to set send side. |
180 report_block.media_ssrc = remote_ssrc_; // SSRC of the RTP packet sender. | 177 report_block.media_ssrc = remote_ssrc_; // SSRC of the RTP packet sender. |
181 if (rtp_receiver_statistics_) { | 178 if (rtp_receiver_statistics_) { |
182 rtp_receiver_statistics_->GetStatistics( | 179 rtp_receiver_statistics_->GetStatistics( |
183 &report_block.fraction_lost, &report_block.cumulative_lost, | 180 &report_block.fraction_lost, &report_block.cumulative_lost, |
184 &report_block.extended_high_sequence_number, &report_block.jitter); | 181 &report_block.extended_high_sequence_number, &report_block.jitter); |
185 } | 182 } |
186 | 183 |
187 report_block.last_sr = last_report_received_; | 184 report_block.last_sr = last_report_truncated_ntp_; |
188 if (!time_last_report_received_.is_null()) { | 185 if (!time_last_report_received_.is_null()) { |
189 uint32 delay_seconds = 0; | 186 uint32 delay_seconds = 0; |
190 uint32 delay_fraction = 0; | 187 uint32 delay_fraction = 0; |
191 base::TimeDelta delta = now - time_last_report_received_; | 188 base::TimeDelta delta = now - time_last_report_received_; |
192 ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, | 189 ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, |
193 &delay_fraction); | 190 &delay_fraction); |
194 report_block.delay_since_last_sr = | 191 report_block.delay_since_last_sr = |
195 ConvertToNtpDiff(delay_seconds, delay_fraction); | 192 ConvertToNtpDiff(delay_seconds, delay_fraction); |
196 } else { | 193 } else { |
197 report_block.delay_since_last_sr = 0; | 194 report_block.delay_since_last_sr = 0; |
(...skipping 15 matching lines...) Expand all Loading... |
213 uint32 current_ntp_seconds = 0; | 210 uint32 current_ntp_seconds = 0; |
214 uint32 current_ntp_fractions = 0; | 211 uint32 current_ntp_fractions = 0; |
215 ConvertTimeTicksToNtp(current_time, ¤t_ntp_seconds, | 212 ConvertTimeTicksToNtp(current_time, ¤t_ntp_seconds, |
216 ¤t_ntp_fractions); | 213 ¤t_ntp_fractions); |
217 SaveLastSentNtpTime(current_time, current_ntp_seconds, | 214 SaveLastSentNtpTime(current_time, current_ntp_seconds, |
218 current_ntp_fractions); | 215 current_ntp_fractions); |
219 | 216 |
220 transport::RtcpDlrrReportBlock dlrr; | 217 transport::RtcpDlrrReportBlock dlrr; |
221 if (!time_last_report_received_.is_null()) { | 218 if (!time_last_report_received_.is_null()) { |
222 packet_type_flags |= transport::kRtcpDlrr; | 219 packet_type_flags |= transport::kRtcpDlrr; |
223 dlrr.last_rr = last_report_received_; | 220 dlrr.last_rr = last_report_truncated_ntp_; |
224 uint32 delay_seconds = 0; | 221 uint32 delay_seconds = 0; |
225 uint32 delay_fraction = 0; | 222 uint32 delay_fraction = 0; |
226 base::TimeDelta delta = current_time - time_last_report_received_; | 223 base::TimeDelta delta = current_time - time_last_report_received_; |
227 ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, | 224 ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, |
228 &delay_fraction); | 225 &delay_fraction); |
229 | 226 |
230 dlrr.delay_since_last_rr = ConvertToNtpDiff(delay_seconds, delay_fraction); | 227 dlrr.delay_since_last_rr = ConvertToNtpDiff(delay_seconds, delay_fraction); |
231 } | 228 } |
232 | 229 |
233 transport_sender_->SendRtcpFromRtpSender( | 230 transport_sender_->SendRtcpFromRtpSender( |
234 packet_type_flags, current_ntp_seconds, current_ntp_fractions, | 231 packet_type_flags, current_ntp_seconds, current_ntp_fractions, |
235 current_time_as_rtp_timestamp, dlrr, local_ssrc_, c_name_); | 232 current_time_as_rtp_timestamp, dlrr, local_ssrc_, c_name_); |
236 UpdateNextTimeToSendRtcp(); | 233 UpdateNextTimeToSendRtcp(); |
237 } | 234 } |
238 | 235 |
239 void Rtcp::OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction) { | 236 void Rtcp::OnReceivedNtp(uint32 ntp_seconds, uint32 ntp_fraction) { |
240 last_report_received_ = (ntp_seconds << 16) + (ntp_fraction >> 16); | 237 last_report_truncated_ntp_ = ConvertToNtpDiff(ntp_seconds, ntp_fraction); |
241 | 238 |
242 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 239 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
243 time_last_report_received_ = now; | 240 time_last_report_received_ = now; |
| 241 |
| 242 // TODO(miu): This clock offset calculation does not account for packet |
| 243 // transit time over the network. End2EndTest.EvilNetwork confirms that this |
| 244 // contributes a very significant source of error here. Fix this along with |
| 245 // the RTT clean-up. |
| 246 const base::TimeDelta measured_offset = |
| 247 now - ConvertNtpToTimeTicks(ntp_seconds, ntp_fraction); |
| 248 local_clock_ahead_by_.Update(now, measured_offset); |
| 249 if (measured_offset < local_clock_ahead_by_.Current()) { |
| 250 // Logically, the minimum offset between the clocks has to be the correct |
| 251 // one. For example, the time it took to transmit the current report may |
| 252 // have been lower than usual, and so some of the error introduced by the |
| 253 // transmission time can be eliminated. |
| 254 local_clock_ahead_by_.Reset(now, measured_offset); |
| 255 } |
| 256 VLOG(1) << "Local clock is ahead of the remote clock by: " |
| 257 << "measured=" << measured_offset.InMicroseconds() << " usec, " |
| 258 << "filtered=" << local_clock_ahead_by_.Current().InMicroseconds() |
| 259 << " usec."; |
244 } | 260 } |
245 | 261 |
246 void Rtcp::OnReceivedLipSyncInfo(uint32 rtp_timestamp, uint32 ntp_seconds, | 262 void Rtcp::OnReceivedLipSyncInfo(uint32 rtp_timestamp, uint32 ntp_seconds, |
247 uint32 ntp_fraction) { | 263 uint32 ntp_fraction) { |
248 last_received_rtp_timestamp_ = rtp_timestamp; | 264 if (ntp_seconds == 0) { |
249 last_received_ntp_seconds_ = ntp_seconds; | 265 NOTREACHED(); |
250 last_received_ntp_fraction_ = ntp_fraction; | 266 return; |
| 267 } |
| 268 lip_sync_rtp_timestamp_ = rtp_timestamp; |
| 269 lip_sync_ntp_timestamp_ = |
| 270 (static_cast<uint64>(ntp_seconds) << 32) | ntp_fraction; |
| 271 } |
| 272 |
| 273 bool Rtcp::GetLatestLipSyncTimes(uint32* rtp_timestamp, |
| 274 base::TimeTicks* reference_time) const { |
| 275 if (!lip_sync_ntp_timestamp_) |
| 276 return false; |
| 277 |
| 278 const base::TimeTicks local_reference_time = |
| 279 ConvertNtpToTimeTicks(static_cast<uint32>(lip_sync_ntp_timestamp_ >> 32), |
| 280 static_cast<uint32>(lip_sync_ntp_timestamp_)) + |
| 281 local_clock_ahead_by_.Current(); |
| 282 |
| 283 // Sanity-check: Getting regular lip sync updates? |
| 284 DCHECK((cast_environment_->Clock()->NowTicks() - local_reference_time) < |
| 285 base::TimeDelta::FromMinutes(1)); |
| 286 |
| 287 *rtp_timestamp = lip_sync_rtp_timestamp_; |
| 288 *reference_time = local_reference_time; |
| 289 return true; |
251 } | 290 } |
252 | 291 |
253 void Rtcp::OnReceivedSendReportRequest() { | 292 void Rtcp::OnReceivedSendReportRequest() { |
254 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 293 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
255 | 294 |
256 // Trigger a new RTCP report at next timer. | 295 // Trigger a new RTCP report at next timer. |
257 next_time_to_send_rtcp_ = now; | 296 next_time_to_send_rtcp_ = now; |
258 } | 297 } |
259 | 298 |
260 bool Rtcp::RtpTimestampInSenderTime(int frequency, uint32 rtp_timestamp, | |
261 base::TimeTicks* rtp_timestamp_in_ticks) | |
262 const { | |
263 if (last_received_ntp_seconds_ == 0) | |
264 return false; | |
265 | |
266 int wrap = CheckForWrapAround(rtp_timestamp, last_received_rtp_timestamp_); | |
267 int64 rtp_timestamp_int64 = rtp_timestamp; | |
268 int64 last_received_rtp_timestamp_int64 = last_received_rtp_timestamp_; | |
269 | |
270 if (wrap == 1) { | |
271 rtp_timestamp_int64 += (1LL << 32); | |
272 } else if (wrap == -1) { | |
273 last_received_rtp_timestamp_int64 += (1LL << 32); | |
274 } | |
275 // Time since the last RTCP message. | |
276 // Note that this can be negative since we can compare a rtp timestamp from | |
277 // a frame older than the last received RTCP message. | |
278 int64 rtp_timestamp_diff = | |
279 rtp_timestamp_int64 - last_received_rtp_timestamp_int64; | |
280 | |
281 int frequency_khz = frequency / 1000; | |
282 int64 rtp_time_diff_ms = rtp_timestamp_diff / frequency_khz; | |
283 | |
284 // Sanity check. | |
285 if (std::abs(rtp_time_diff_ms) > kMaxDiffSinceReceivedRtcpMs) | |
286 return false; | |
287 | |
288 *rtp_timestamp_in_ticks = ConvertNtpToTimeTicks(last_received_ntp_seconds_, | |
289 last_received_ntp_fraction_) + | |
290 base::TimeDelta::FromMilliseconds(rtp_time_diff_ms); | |
291 return true; | |
292 } | |
293 | |
294 void Rtcp::SetCastReceiverEventHistorySize(size_t size) { | 299 void Rtcp::SetCastReceiverEventHistorySize(size_t size) { |
295 rtcp_receiver_->SetCastReceiverEventHistorySize(size); | 300 rtcp_receiver_->SetCastReceiverEventHistorySize(size); |
296 } | 301 } |
297 | 302 |
298 void Rtcp::SetTargetDelay(base::TimeDelta target_delay) { | 303 void Rtcp::SetTargetDelay(base::TimeDelta target_delay) { |
| 304 DCHECK(target_delay.InMilliseconds() < kMaxDelay); |
299 target_delay_ms_ = static_cast<uint16>(target_delay.InMilliseconds()); | 305 target_delay_ms_ = static_cast<uint16>(target_delay.InMilliseconds()); |
300 DCHECK(target_delay_ms_ < kMaxDelay); | |
301 } | 306 } |
302 | 307 |
303 void Rtcp::OnReceivedDelaySinceLastReport(uint32 receivers_ssrc, | 308 void Rtcp::OnReceivedDelaySinceLastReport(uint32 receivers_ssrc, |
304 uint32 last_report, | 309 uint32 last_report, |
305 uint32 delay_since_last_report) { | 310 uint32 delay_since_last_report) { |
306 RtcpSendTimeMap::iterator it = last_reports_sent_map_.find(last_report); | 311 RtcpSendTimeMap::iterator it = last_reports_sent_map_.find(last_report); |
307 if (it == last_reports_sent_map_.end()) { | 312 if (it == last_reports_sent_map_.end()) { |
308 return; // Feedback on another report. | 313 return; // Feedback on another report. |
309 } | 314 } |
310 | 315 |
(...skipping 24 matching lines...) Expand all Loading... |
335 last_reports_sent_queue_.pop(); | 340 last_reports_sent_queue_.pop(); |
336 } else { | 341 } else { |
337 break; | 342 break; |
338 } | 343 } |
339 } | 344 } |
340 } | 345 } |
341 | 346 |
342 void Rtcp::UpdateRtt(const base::TimeDelta& sender_delay, | 347 void Rtcp::UpdateRtt(const base::TimeDelta& sender_delay, |
343 const base::TimeDelta& receiver_delay) { | 348 const base::TimeDelta& receiver_delay) { |
344 base::TimeDelta rtt = sender_delay - receiver_delay; | 349 base::TimeDelta rtt = sender_delay - receiver_delay; |
| 350 // TODO(miu): Find out why this must be >= 1 ms, and remove the fudge if it's |
| 351 // bogus. |
345 rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1)); | 352 rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1)); |
346 rtt_ = rtt; | 353 rtt_ = rtt; |
347 min_rtt_ = std::min(min_rtt_, rtt); | 354 min_rtt_ = std::min(min_rtt_, rtt); |
348 max_rtt_ = std::max(max_rtt_, rtt); | 355 max_rtt_ = std::max(max_rtt_, rtt); |
349 | 356 |
| 357 // TODO(miu): Replace "average for all time" with an EWMA, or suitable |
| 358 // "average over recent past" mechanism. |
350 if (number_of_rtt_in_avg_ != 0) { | 359 if (number_of_rtt_in_avg_ != 0) { |
351 float ac = static_cast<float>(number_of_rtt_in_avg_); | 360 const double ac = static_cast<double>(number_of_rtt_in_avg_); |
352 avg_rtt_ms_ = ((ac / (ac + 1.0)) * avg_rtt_ms_) + | 361 avg_rtt_ms_ = ((ac / (ac + 1.0)) * avg_rtt_ms_) + |
353 ((1.0 / (ac + 1.0)) * rtt.InMilliseconds()); | 362 ((1.0 / (ac + 1.0)) * rtt.InMillisecondsF()); |
354 } else { | 363 } else { |
355 avg_rtt_ms_ = rtt.InMilliseconds(); | 364 avg_rtt_ms_ = rtt.InMillisecondsF(); |
356 } | 365 } |
357 number_of_rtt_in_avg_++; | 366 number_of_rtt_in_avg_++; |
358 } | 367 } |
359 | 368 |
360 bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt, | 369 bool Rtcp::Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt, |
361 base::TimeDelta* min_rtt, base::TimeDelta* max_rtt) const { | 370 base::TimeDelta* min_rtt, base::TimeDelta* max_rtt) const { |
362 DCHECK(rtt) << "Invalid argument"; | 371 DCHECK(rtt) << "Invalid argument"; |
363 DCHECK(avg_rtt) << "Invalid argument"; | 372 DCHECK(avg_rtt) << "Invalid argument"; |
364 DCHECK(min_rtt) << "Invalid argument"; | 373 DCHECK(min_rtt) << "Invalid argument"; |
365 DCHECK(max_rtt) << "Invalid argument"; | 374 DCHECK(max_rtt) << "Invalid argument"; |
366 | 375 |
367 if (number_of_rtt_in_avg_ == 0) return false; | 376 if (number_of_rtt_in_avg_ == 0) return false; |
368 | 377 |
369 *rtt = rtt_; | 378 *rtt = rtt_; |
370 *avg_rtt = base::TimeDelta::FromMilliseconds(avg_rtt_ms_); | 379 *avg_rtt = base::TimeDelta::FromMillisecondsD(avg_rtt_ms_); |
371 *min_rtt = min_rtt_; | 380 *min_rtt = min_rtt_; |
372 *max_rtt = max_rtt_; | 381 *max_rtt = max_rtt_; |
373 return true; | 382 return true; |
374 } | 383 } |
375 | 384 |
376 int Rtcp::CheckForWrapAround(uint32 new_timestamp, uint32 old_timestamp) const { | |
377 if (new_timestamp < old_timestamp) { | |
378 // This difference should be less than -2^31 if we have had a wrap around | |
379 // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is | |
380 // cast to a int32_t, it should be positive. | |
381 if (static_cast<int32>(new_timestamp - old_timestamp) > 0) { | |
382 return 1; // Forward wrap around. | |
383 } | |
384 } else if (static_cast<int32>(old_timestamp - new_timestamp) > 0) { | |
385 // This difference should be less than -2^31 if we have had a backward wrap | |
386 // around. Since it is cast to a int32, it should be positive. | |
387 return -1; | |
388 } | |
389 return 0; | |
390 } | |
391 | |
392 void Rtcp::UpdateNextTimeToSendRtcp() { | 385 void Rtcp::UpdateNextTimeToSendRtcp() { |
393 int random = base::RandInt(0, 999); | 386 int random = base::RandInt(0, 999); |
394 base::TimeDelta time_to_next = | 387 base::TimeDelta time_to_next = |
395 (rtcp_interval_ / 2) + (rtcp_interval_ * random / 1000); | 388 (rtcp_interval_ / 2) + (rtcp_interval_ * random / 1000); |
396 | 389 |
397 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 390 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
398 next_time_to_send_rtcp_ = now + time_to_next; | 391 next_time_to_send_rtcp_ = now + time_to_next; |
399 } | 392 } |
400 | 393 |
401 void Rtcp::OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log) { | 394 void Rtcp::OnReceivedReceiverLog(const RtcpReceiverLogMessage& receiver_log) { |
(...skipping 28 matching lines...) Expand all Loading... |
430 VLOG(2) << "Received log message via RTCP that we did not expect: " | 423 VLOG(2) << "Received log message via RTCP that we did not expect: " |
431 << static_cast<int>(event_it->type); | 424 << static_cast<int>(event_it->type); |
432 break; | 425 break; |
433 } | 426 } |
434 } | 427 } |
435 } | 428 } |
436 } | 429 } |
437 | 430 |
438 } // namespace cast | 431 } // namespace cast |
439 } // namespace media | 432 } // namespace media |
OLD | NEW |