OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "webrtc/modules/pacing/bitrate_prober.h" | 21 #include "webrtc/modules/pacing/bitrate_prober.h" |
22 #include "webrtc/modules/utility/include/process_thread.h" | 22 #include "webrtc/modules/utility/include/process_thread.h" |
23 #include "webrtc/rtc_base/checks.h" | 23 #include "webrtc/rtc_base/checks.h" |
24 #include "webrtc/rtc_base/logging.h" | 24 #include "webrtc/rtc_base/logging.h" |
25 #include "webrtc/system_wrappers/include/clock.h" | 25 #include "webrtc/system_wrappers/include/clock.h" |
26 #include "webrtc/system_wrappers/include/field_trial.h" | 26 #include "webrtc/system_wrappers/include/field_trial.h" |
27 | 27 |
28 namespace { | 28 namespace { |
29 // Time limit in milliseconds between packet bursts. | 29 // Time limit in milliseconds between packet bursts. |
30 const int64_t kMinPacketLimitMs = 5; | 30 const int64_t kMinPacketLimitMs = 5; |
31 const int64_t kPausedPacketIntervalMs = 500; | |
31 | 32 |
32 // Upper cap on process interval, in case process has not been called in a long | 33 // Upper cap on process interval, in case process has not been called in a long |
33 // time. | 34 // time. |
34 const int64_t kMaxIntervalTimeMs = 30; | 35 const int64_t kMaxIntervalTimeMs = 30; |
35 | 36 |
36 } // namespace | 37 } // namespace |
37 | 38 |
38 // TODO(sprang): Move at least PacketQueue and MediaBudget out to separate | 39 // TODO(sprang): Move at least PacketQueue and MediaBudget out to separate |
39 // files, so that we can more easily test them. | 40 // files, so that we can more easily test them. |
40 | 41 |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 } | 272 } |
272 | 273 |
273 PacedSender::~PacedSender() {} | 274 PacedSender::~PacedSender() {} |
274 | 275 |
275 void PacedSender::CreateProbeCluster(int bitrate_bps) { | 276 void PacedSender::CreateProbeCluster(int bitrate_bps) { |
276 rtc::CritScope cs(&critsect_); | 277 rtc::CritScope cs(&critsect_); |
277 prober_->CreateProbeCluster(bitrate_bps, clock_->TimeInMilliseconds()); | 278 prober_->CreateProbeCluster(bitrate_bps, clock_->TimeInMilliseconds()); |
278 } | 279 } |
279 | 280 |
280 void PacedSender::Pause() { | 281 void PacedSender::Pause() { |
281 LOG(LS_INFO) << "PacedSender paused."; | |
282 { | 282 { |
283 rtc::CritScope cs(&critsect_); | 283 rtc::CritScope cs(&critsect_); |
284 if (!paused_) | |
285 LOG(LS_INFO) << "PacedSender paused."; | |
284 paused_ = true; | 286 paused_ = true; |
285 } | 287 } |
286 // Tell the process thread to call our TimeUntilNextProcess() method to get | 288 // Tell the process thread to call our TimeUntilNextProcess() method to get |
287 // a new (longer) estimate for when to call Process(). | 289 // a new (longer) estimate for when to call Process(). |
288 if (process_thread_) | 290 if (process_thread_) |
289 process_thread_->WakeUp(this); | 291 process_thread_->WakeUp(this); |
290 } | 292 } |
291 | 293 |
292 void PacedSender::Resume() { | 294 void PacedSender::Resume() { |
293 LOG(LS_INFO) << "PacedSender resumed."; | |
294 { | 295 { |
295 rtc::CritScope cs(&critsect_); | 296 rtc::CritScope cs(&critsect_); |
297 if (paused_) | |
298 LOG(LS_INFO) << "PacedSender resumed."; | |
296 paused_ = false; | 299 paused_ = false; |
297 } | 300 } |
298 // Tell the process thread to call our TimeUntilNextProcess() method to | 301 // Tell the process thread to call our TimeUntilNextProcess() method to |
299 // refresh the estimate for when to call Process(). | 302 // refresh the estimate for when to call Process(). |
300 if (process_thread_) | 303 if (process_thread_) |
301 process_thread_->WakeUp(this); | 304 process_thread_->WakeUp(this); |
302 } | 305 } |
303 | 306 |
304 void PacedSender::SetProbingEnabled(bool enabled) { | 307 void PacedSender::SetProbingEnabled(bool enabled) { |
305 RTC_CHECK_EQ(0, packet_counter_); | 308 RTC_CHECK_EQ(0, packet_counter_); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
387 } | 390 } |
388 | 391 |
389 int64_t PacedSender::AverageQueueTimeMs() { | 392 int64_t PacedSender::AverageQueueTimeMs() { |
390 rtc::CritScope cs(&critsect_); | 393 rtc::CritScope cs(&critsect_); |
391 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); | 394 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); |
392 return packets_->AverageQueueTimeMs(); | 395 return packets_->AverageQueueTimeMs(); |
393 } | 396 } |
394 | 397 |
395 int64_t PacedSender::TimeUntilNextProcess() { | 398 int64_t PacedSender::TimeUntilNextProcess() { |
396 rtc::CritScope cs(&critsect_); | 399 rtc::CritScope cs(&critsect_); |
400 int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_; | |
401 int64_t elapsed_time_ms = (elapsed_time_us + 500) / 1000; | |
402 // When paused we wake up every 500 ms to send a padding packet to ensure | |
403 // we won't get stuck in the paused state due to no feedback being received. | |
397 if (paused_) | 404 if (paused_) |
398 return 1000 * 60 * 60; | 405 return std::max<int64_t>(kPausedPacketIntervalMs - elapsed_time_ms, 0); |
399 | 406 |
400 if (prober_->IsProbing()) { | 407 if (prober_->IsProbing()) { |
401 int64_t ret = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds()); | 408 int64_t ret = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds()); |
402 if (ret > 0 || (ret == 0 && !probing_send_failure_)) | 409 if (ret > 0 || (ret == 0 && !probing_send_failure_)) |
403 return ret; | 410 return ret; |
404 } | 411 } |
405 int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_; | |
406 int64_t elapsed_time_ms = (elapsed_time_us + 500) / 1000; | |
407 return std::max<int64_t>(kMinPacketLimitMs - elapsed_time_ms, 0); | 412 return std::max<int64_t>(kMinPacketLimitMs - elapsed_time_ms, 0); |
408 } | 413 } |
409 | 414 |
410 void PacedSender::Process() { | 415 void PacedSender::Process() { |
411 int64_t now_us = clock_->TimeInMicroseconds(); | 416 int64_t now_us = clock_->TimeInMicroseconds(); |
412 rtc::CritScope cs(&critsect_); | 417 rtc::CritScope cs(&critsect_); |
413 int64_t elapsed_time_ms = (now_us - time_last_update_us_ + 500) / 1000; | 418 int64_t elapsed_time_ms = (now_us - time_last_update_us_ + 500) / 1000; |
414 time_last_update_us_ = now_us; | |
415 int target_bitrate_kbps = pacing_bitrate_kbps_; | 419 int target_bitrate_kbps = pacing_bitrate_kbps_; |
416 if (!paused_ && elapsed_time_ms > 0) { | 420 |
421 if (paused_) { | |
422 PacedPacketInfo pacing_info; | |
423 size_t bytes_sent = SendPadding(1, pacing_info); | |
philipel
2017/08/02 15:35:16
Is there a way to completely stop the pacer, not j
stefan-webrtc
2017/08/04 09:50:00
We could, but the problem is that if we lose some
| |
424 alr_detector_->OnBytesSent(bytes_sent, now_us / 1000); | |
425 time_last_update_us_ = now_us; | |
426 return; | |
427 } | |
428 | |
429 if (elapsed_time_ms > 0) { | |
417 size_t queue_size_bytes = packets_->SizeInBytes(); | 430 size_t queue_size_bytes = packets_->SizeInBytes(); |
418 if (queue_size_bytes > 0) { | 431 if (queue_size_bytes > 0) { |
419 // Assuming equal size packets and input/output rate, the average packet | 432 // Assuming equal size packets and input/output rate, the average packet |
420 // has avg_time_left_ms left to get queue_size_bytes out of the queue, if | 433 // has avg_time_left_ms left to get queue_size_bytes out of the queue, if |
421 // time constraint shall be met. Determine bitrate needed for that. | 434 // time constraint shall be met. Determine bitrate needed for that. |
422 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); | 435 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); |
423 int64_t avg_time_left_ms = std::max<int64_t>( | 436 int64_t avg_time_left_ms = std::max<int64_t>( |
424 1, queue_time_limit - packets_->AverageQueueTimeMs()); | 437 1, queue_time_limit - packets_->AverageQueueTimeMs()); |
425 int min_bitrate_needed_kbps = | 438 int min_bitrate_needed_kbps = |
426 static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms); | 439 static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms); |
427 if (min_bitrate_needed_kbps > target_bitrate_kbps) | 440 if (min_bitrate_needed_kbps > target_bitrate_kbps) |
428 target_bitrate_kbps = min_bitrate_needed_kbps; | 441 target_bitrate_kbps = min_bitrate_needed_kbps; |
429 } | 442 } |
430 | 443 |
431 media_budget_->set_target_rate_kbps(target_bitrate_kbps); | 444 media_budget_->set_target_rate_kbps(target_bitrate_kbps); |
432 | 445 |
433 elapsed_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); | 446 elapsed_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); |
434 UpdateBudgetWithElapsedTime(elapsed_time_ms); | 447 UpdateBudgetWithElapsedTime(elapsed_time_ms); |
435 } | 448 } |
436 | 449 |
450 time_last_update_us_ = now_us; | |
451 | |
437 bool is_probing = prober_->IsProbing(); | 452 bool is_probing = prober_->IsProbing(); |
438 PacedPacketInfo pacing_info; | 453 PacedPacketInfo pacing_info; |
439 size_t bytes_sent = 0; | 454 size_t bytes_sent = 0; |
440 size_t recommended_probe_size = 0; | 455 size_t recommended_probe_size = 0; |
441 if (is_probing) { | 456 if (is_probing) { |
442 pacing_info = prober_->CurrentCluster(); | 457 pacing_info = prober_->CurrentCluster(); |
443 recommended_probe_size = prober_->RecommendedMinProbeSize(); | 458 recommended_probe_size = prober_->RecommendedMinProbeSize(); |
444 } | 459 } |
445 while (!packets_->Empty()) { | 460 while (!packets_->Empty()) { |
446 // Since we need to release the lock in order to send, we first pop the | 461 // Since we need to release the lock in order to send, we first pop the |
447 // element from the priority queue but keep it in storage, so that we can | 462 // element from the priority queue but keep it in storage, so that we can |
448 // reinsert it if send fails. | 463 // reinsert it if send fails. |
449 const paced_sender::Packet& packet = packets_->BeginPop(); | 464 const paced_sender::Packet& packet = packets_->BeginPop(); |
450 | 465 |
451 if (SendPacket(packet, pacing_info)) { | 466 if (SendPacket(packet, pacing_info)) { |
452 // Send succeeded, remove it from the queue. | 467 // Send succeeded, remove it from the queue. |
453 if (first_sent_packet_ms_ == -1) | 468 if (first_sent_packet_ms_ == -1) |
454 first_sent_packet_ms_ = clock_->TimeInMilliseconds(); | 469 first_sent_packet_ms_ = clock_->TimeInMilliseconds(); |
455 bytes_sent += packet.bytes; | 470 bytes_sent += packet.bytes; |
456 packets_->FinalizePop(packet); | 471 packets_->FinalizePop(packet); |
457 if (is_probing && bytes_sent > recommended_probe_size) | 472 if (is_probing && bytes_sent > recommended_probe_size) |
458 break; | 473 break; |
459 } else { | 474 } else { |
460 // Send failed, put it back into the queue. | 475 // Send failed, put it back into the queue. |
461 packets_->CancelPop(packet); | 476 packets_->CancelPop(packet); |
462 break; | 477 break; |
463 } | 478 } |
464 } | 479 } |
465 | 480 |
466 if (packets_->Empty() && !paused_) { | 481 if (packets_->Empty()) { |
philipel
2017/08/02 15:35:16
Is this correct?
I assume you want to be able to
stefan-webrtc
2017/08/04 09:50:00
Why would we do that if there are packets in the q
philipel
2017/08/04 14:13:04
Ah, you're right.
| |
467 // We can not send padding unless a normal packet has first been sent. If we | 482 int padding_needed = |
468 // do, timestamps get messed up. | 483 static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent) |
469 if (packet_counter_ > 0) { | 484 : padding_budget_->bytes_remaining()); |
470 int padding_needed = | 485 if (padding_needed > 0) |
471 static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent) | 486 bytes_sent += SendPadding(padding_needed, pacing_info); |
472 : padding_budget_->bytes_remaining()); | |
473 | |
474 if (padding_needed > 0) | |
475 bytes_sent += SendPadding(padding_needed, pacing_info); | |
476 } | |
477 } | 487 } |
478 if (is_probing) { | 488 if (is_probing) { |
479 probing_send_failure_ = bytes_sent == 0; | 489 probing_send_failure_ = bytes_sent == 0; |
480 if (!probing_send_failure_) | 490 if (!probing_send_failure_) |
481 prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); | 491 prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); |
482 } | 492 } |
483 alr_detector_->OnBytesSent(bytes_sent, now_us / 1000); | 493 alr_detector_->OnBytesSent(bytes_sent, now_us / 1000); |
484 } | 494 } |
485 | 495 |
486 void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) { | 496 void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) { |
487 LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread; | 497 LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread; |
488 process_thread_ = process_thread; | 498 process_thread_ = process_thread; |
489 } | 499 } |
490 | 500 |
491 bool PacedSender::SendPacket(const paced_sender::Packet& packet, | 501 bool PacedSender::SendPacket(const paced_sender::Packet& packet, |
492 const PacedPacketInfo& pacing_info) { | 502 const PacedPacketInfo& pacing_info) { |
493 if (paused_) | |
494 return false; | |
philipel
2017/08/02 15:35:16
Make it into an RTC_DCHECK
stefan-webrtc
2017/08/04 09:50:00
Done.
| |
495 if (media_budget_->bytes_remaining() == 0 && | 503 if (media_budget_->bytes_remaining() == 0 && |
496 pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe) { | 504 pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe) { |
497 return false; | 505 return false; |
498 } | 506 } |
499 | 507 |
500 critsect_.Leave(); | 508 critsect_.Leave(); |
501 const bool success = packet_sender_->TimeToSendPacket( | 509 const bool success = packet_sender_->TimeToSendPacket( |
502 packet.ssrc, packet.sequence_number, packet.capture_time_ms, | 510 packet.ssrc, packet.sequence_number, packet.capture_time_ms, |
503 packet.retransmission, pacing_info); | 511 packet.retransmission, pacing_info); |
504 critsect_.Enter(); | 512 critsect_.Enter(); |
505 | 513 |
506 if (success) { | 514 if (success) { |
507 // TODO(holmer): High priority packets should only be accounted for if we | 515 // TODO(holmer): High priority packets should only be accounted for if we |
508 // are allocating bandwidth for audio. | 516 // are allocating bandwidth for audio. |
509 if (packet.priority != kHighPriority) { | 517 if (packet.priority != kHighPriority) { |
510 // Update media bytes sent. | 518 // Update media bytes sent. |
511 UpdateBudgetWithBytesSent(packet.bytes); | 519 UpdateBudgetWithBytesSent(packet.bytes); |
512 } | 520 } |
513 } | 521 } |
514 | 522 |
515 return success; | 523 return success; |
516 } | 524 } |
517 | 525 |
518 size_t PacedSender::SendPadding(size_t padding_needed, | 526 size_t PacedSender::SendPadding(size_t padding_needed, |
519 const PacedPacketInfo& pacing_info) { | 527 const PacedPacketInfo& pacing_info) { |
528 // We can not send padding unless a normal packet has first been sent. If we | |
529 // do, timestamps get messed up. | |
530 if (packet_counter_ == 0) | |
philipel
2017/08/02 15:35:16
I think it's somewhat clearer to keep this check w
stefan-webrtc
2017/08/04 09:50:00
Then the code will have to be duplicated since we'
philipel
2017/08/04 14:13:04
I still think that would be preferable.
| |
531 return 0; | |
520 critsect_.Leave(); | 532 critsect_.Leave(); |
521 size_t bytes_sent = | 533 size_t bytes_sent = |
522 packet_sender_->TimeToSendPadding(padding_needed, pacing_info); | 534 packet_sender_->TimeToSendPadding(padding_needed, pacing_info); |
523 critsect_.Enter(); | 535 critsect_.Enter(); |
524 | 536 |
525 if (bytes_sent > 0) { | 537 if (bytes_sent > 0) { |
526 UpdateBudgetWithBytesSent(bytes_sent); | 538 UpdateBudgetWithBytesSent(bytes_sent); |
527 } | 539 } |
528 return bytes_sent; | 540 return bytes_sent; |
529 } | 541 } |
(...skipping 12 matching lines...) Expand all Loading... | |
542 rtc::CritScope cs(&critsect_); | 554 rtc::CritScope cs(&critsect_); |
543 pacing_factor_ = pacing_factor; | 555 pacing_factor_ = pacing_factor; |
544 } | 556 } |
545 | 557 |
546 void PacedSender::SetQueueTimeLimit(int limit_ms) { | 558 void PacedSender::SetQueueTimeLimit(int limit_ms) { |
547 rtc::CritScope cs(&critsect_); | 559 rtc::CritScope cs(&critsect_); |
548 queue_time_limit = limit_ms; | 560 queue_time_limit = limit_ms; |
549 } | 561 } |
550 | 562 |
551 } // namespace webrtc | 563 } // namespace webrtc |
OLD | NEW |