| 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 11 matching lines...) Expand all Loading... |
| 22 #include "webrtc/modules/pacing/interval_budget.h" | 22 #include "webrtc/modules/pacing/interval_budget.h" |
| 23 #include "webrtc/modules/utility/include/process_thread.h" | 23 #include "webrtc/modules/utility/include/process_thread.h" |
| 24 #include "webrtc/rtc_base/checks.h" | 24 #include "webrtc/rtc_base/checks.h" |
| 25 #include "webrtc/rtc_base/logging.h" | 25 #include "webrtc/rtc_base/logging.h" |
| 26 #include "webrtc/system_wrappers/include/clock.h" | 26 #include "webrtc/system_wrappers/include/clock.h" |
| 27 #include "webrtc/system_wrappers/include/field_trial.h" | 27 #include "webrtc/system_wrappers/include/field_trial.h" |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 // Time limit in milliseconds between packet bursts. | 30 // Time limit in milliseconds between packet bursts. |
| 31 const int64_t kMinPacketLimitMs = 5; | 31 const int64_t kMinPacketLimitMs = 5; |
| 32 const int64_t kPausedPacketIntervalMs = 500; | |
| 33 | 32 |
| 34 // 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 |
| 35 // time. | 34 // time. |
| 36 const int64_t kMaxIntervalTimeMs = 30; | 35 const int64_t kMaxIntervalTimeMs = 30; |
| 37 | 36 |
| 38 } // namespace | 37 } // namespace |
| 39 | 38 |
| 40 // TODO(sprang): Move at least PacketQueue out to separate | 39 // TODO(sprang): Move at least PacketQueue out to separate |
| 41 // files, so that we can more easily test them. | 40 // files, so that we can more easily test them. |
| 42 | 41 |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 } | 232 } |
| 234 | 233 |
| 235 PacedSender::~PacedSender() {} | 234 PacedSender::~PacedSender() {} |
| 236 | 235 |
| 237 void PacedSender::CreateProbeCluster(int bitrate_bps) { | 236 void PacedSender::CreateProbeCluster(int bitrate_bps) { |
| 238 rtc::CritScope cs(&critsect_); | 237 rtc::CritScope cs(&critsect_); |
| 239 prober_->CreateProbeCluster(bitrate_bps, clock_->TimeInMilliseconds()); | 238 prober_->CreateProbeCluster(bitrate_bps, clock_->TimeInMilliseconds()); |
| 240 } | 239 } |
| 241 | 240 |
| 242 void PacedSender::Pause() { | 241 void PacedSender::Pause() { |
| 242 LOG(LS_INFO) << "PacedSender paused."; |
| 243 { | 243 { |
| 244 rtc::CritScope cs(&critsect_); | 244 rtc::CritScope cs(&critsect_); |
| 245 if (!paused_) | |
| 246 LOG(LS_INFO) << "PacedSender paused."; | |
| 247 paused_ = true; | 245 paused_ = true; |
| 248 } | 246 } |
| 249 // Tell the process thread to call our TimeUntilNextProcess() method to get | 247 // Tell the process thread to call our TimeUntilNextProcess() method to get |
| 250 // a new (longer) estimate for when to call Process(). | 248 // a new (longer) estimate for when to call Process(). |
| 251 if (process_thread_) | 249 if (process_thread_) |
| 252 process_thread_->WakeUp(this); | 250 process_thread_->WakeUp(this); |
| 253 } | 251 } |
| 254 | 252 |
| 255 void PacedSender::Resume() { | 253 void PacedSender::Resume() { |
| 254 LOG(LS_INFO) << "PacedSender resumed."; |
| 256 { | 255 { |
| 257 rtc::CritScope cs(&critsect_); | 256 rtc::CritScope cs(&critsect_); |
| 258 if (paused_) | |
| 259 LOG(LS_INFO) << "PacedSender resumed."; | |
| 260 paused_ = false; | 257 paused_ = false; |
| 261 } | 258 } |
| 262 // Tell the process thread to call our TimeUntilNextProcess() method to | 259 // Tell the process thread to call our TimeUntilNextProcess() method to |
| 263 // refresh the estimate for when to call Process(). | 260 // refresh the estimate for when to call Process(). |
| 264 if (process_thread_) | 261 if (process_thread_) |
| 265 process_thread_->WakeUp(this); | 262 process_thread_->WakeUp(this); |
| 266 } | 263 } |
| 267 | 264 |
| 268 void PacedSender::SetProbingEnabled(bool enabled) { | 265 void PacedSender::SetProbingEnabled(bool enabled) { |
| 269 RTC_CHECK_EQ(0, packet_counter_); | 266 RTC_CHECK_EQ(0, packet_counter_); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 } | 348 } |
| 352 | 349 |
| 353 int64_t PacedSender::AverageQueueTimeMs() { | 350 int64_t PacedSender::AverageQueueTimeMs() { |
| 354 rtc::CritScope cs(&critsect_); | 351 rtc::CritScope cs(&critsect_); |
| 355 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); | 352 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); |
| 356 return packets_->AverageQueueTimeMs(); | 353 return packets_->AverageQueueTimeMs(); |
| 357 } | 354 } |
| 358 | 355 |
| 359 int64_t PacedSender::TimeUntilNextProcess() { | 356 int64_t PacedSender::TimeUntilNextProcess() { |
| 360 rtc::CritScope cs(&critsect_); | 357 rtc::CritScope cs(&critsect_); |
| 361 int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_; | |
| 362 int64_t elapsed_time_ms = (elapsed_time_us + 500) / 1000; | |
| 363 // When paused we wake up every 500 ms to send a padding packet to ensure | |
| 364 // we won't get stuck in the paused state due to no feedback being received. | |
| 365 if (paused_) | 358 if (paused_) |
| 366 return std::max<int64_t>(kPausedPacketIntervalMs - elapsed_time_ms, 0); | 359 return 1000 * 60 * 60; |
| 367 | 360 |
| 368 if (prober_->IsProbing()) { | 361 if (prober_->IsProbing()) { |
| 369 int64_t ret = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds()); | 362 int64_t ret = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds()); |
| 370 if (ret > 0 || (ret == 0 && !probing_send_failure_)) | 363 if (ret > 0 || (ret == 0 && !probing_send_failure_)) |
| 371 return ret; | 364 return ret; |
| 372 } | 365 } |
| 366 int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_; |
| 367 int64_t elapsed_time_ms = (elapsed_time_us + 500) / 1000; |
| 373 return std::max<int64_t>(kMinPacketLimitMs - elapsed_time_ms, 0); | 368 return std::max<int64_t>(kMinPacketLimitMs - elapsed_time_ms, 0); |
| 374 } | 369 } |
| 375 | 370 |
| 376 void PacedSender::Process() { | 371 void PacedSender::Process() { |
| 377 int64_t now_us = clock_->TimeInMicroseconds(); | 372 int64_t now_us = clock_->TimeInMicroseconds(); |
| 378 rtc::CritScope cs(&critsect_); | 373 rtc::CritScope cs(&critsect_); |
| 379 int64_t elapsed_time_ms = (now_us - time_last_update_us_ + 500) / 1000; | 374 int64_t elapsed_time_ms = (now_us - time_last_update_us_ + 500) / 1000; |
| 375 time_last_update_us_ = now_us; |
| 380 int target_bitrate_kbps = pacing_bitrate_kbps_; | 376 int target_bitrate_kbps = pacing_bitrate_kbps_; |
| 381 | 377 if (!paused_ && elapsed_time_ms > 0) { |
| 382 if (paused_) { | |
| 383 PacedPacketInfo pacing_info; | |
| 384 time_last_update_us_ = now_us; | |
| 385 // We can not send padding unless a normal packet has first been sent. If we | |
| 386 // do, timestamps get messed up. | |
| 387 if (packet_counter_ == 0) | |
| 388 return; | |
| 389 size_t bytes_sent = SendPadding(1, pacing_info); | |
| 390 alr_detector_->OnBytesSent(bytes_sent, now_us / 1000); | |
| 391 return; | |
| 392 } | |
| 393 | |
| 394 if (elapsed_time_ms > 0) { | |
| 395 size_t queue_size_bytes = packets_->SizeInBytes(); | 378 size_t queue_size_bytes = packets_->SizeInBytes(); |
| 396 if (queue_size_bytes > 0) { | 379 if (queue_size_bytes > 0) { |
| 397 // Assuming equal size packets and input/output rate, the average packet | 380 // Assuming equal size packets and input/output rate, the average packet |
| 398 // has avg_time_left_ms left to get queue_size_bytes out of the queue, if | 381 // has avg_time_left_ms left to get queue_size_bytes out of the queue, if |
| 399 // time constraint shall be met. Determine bitrate needed for that. | 382 // time constraint shall be met. Determine bitrate needed for that. |
| 400 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); | 383 packets_->UpdateQueueTime(clock_->TimeInMilliseconds()); |
| 401 int64_t avg_time_left_ms = std::max<int64_t>( | 384 int64_t avg_time_left_ms = std::max<int64_t>( |
| 402 1, queue_time_limit - packets_->AverageQueueTimeMs()); | 385 1, queue_time_limit - packets_->AverageQueueTimeMs()); |
| 403 int min_bitrate_needed_kbps = | 386 int min_bitrate_needed_kbps = |
| 404 static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms); | 387 static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms); |
| 405 if (min_bitrate_needed_kbps > target_bitrate_kbps) | 388 if (min_bitrate_needed_kbps > target_bitrate_kbps) |
| 406 target_bitrate_kbps = min_bitrate_needed_kbps; | 389 target_bitrate_kbps = min_bitrate_needed_kbps; |
| 407 } | 390 } |
| 408 | 391 |
| 409 media_budget_->set_target_rate_kbps(target_bitrate_kbps); | 392 media_budget_->set_target_rate_kbps(target_bitrate_kbps); |
| 410 | 393 |
| 411 elapsed_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); | 394 elapsed_time_ms = std::min(kMaxIntervalTimeMs, elapsed_time_ms); |
| 412 UpdateBudgetWithElapsedTime(elapsed_time_ms); | 395 UpdateBudgetWithElapsedTime(elapsed_time_ms); |
| 413 } | 396 } |
| 414 | 397 |
| 415 time_last_update_us_ = now_us; | |
| 416 | |
| 417 bool is_probing = prober_->IsProbing(); | 398 bool is_probing = prober_->IsProbing(); |
| 418 PacedPacketInfo pacing_info; | 399 PacedPacketInfo pacing_info; |
| 419 size_t bytes_sent = 0; | 400 size_t bytes_sent = 0; |
| 420 size_t recommended_probe_size = 0; | 401 size_t recommended_probe_size = 0; |
| 421 if (is_probing) { | 402 if (is_probing) { |
| 422 pacing_info = prober_->CurrentCluster(); | 403 pacing_info = prober_->CurrentCluster(); |
| 423 recommended_probe_size = prober_->RecommendedMinProbeSize(); | 404 recommended_probe_size = prober_->RecommendedMinProbeSize(); |
| 424 } | 405 } |
| 425 while (!packets_->Empty()) { | 406 while (!packets_->Empty()) { |
| 426 // Since we need to release the lock in order to send, we first pop the | 407 // Since we need to release the lock in order to send, we first pop the |
| 427 // element from the priority queue but keep it in storage, so that we can | 408 // element from the priority queue but keep it in storage, so that we can |
| 428 // reinsert it if send fails. | 409 // reinsert it if send fails. |
| 429 const paced_sender::Packet& packet = packets_->BeginPop(); | 410 const paced_sender::Packet& packet = packets_->BeginPop(); |
| 430 | 411 |
| 431 if (SendPacket(packet, pacing_info)) { | 412 if (SendPacket(packet, pacing_info)) { |
| 432 // Send succeeded, remove it from the queue. | 413 // Send succeeded, remove it from the queue. |
| 433 if (first_sent_packet_ms_ == -1) | 414 if (first_sent_packet_ms_ == -1) |
| 434 first_sent_packet_ms_ = clock_->TimeInMilliseconds(); | 415 first_sent_packet_ms_ = clock_->TimeInMilliseconds(); |
| 435 bytes_sent += packet.bytes; | 416 bytes_sent += packet.bytes; |
| 436 packets_->FinalizePop(packet); | 417 packets_->FinalizePop(packet); |
| 437 if (is_probing && bytes_sent > recommended_probe_size) | 418 if (is_probing && bytes_sent > recommended_probe_size) |
| 438 break; | 419 break; |
| 439 } else { | 420 } else { |
| 440 // Send failed, put it back into the queue. | 421 // Send failed, put it back into the queue. |
| 441 packets_->CancelPop(packet); | 422 packets_->CancelPop(packet); |
| 442 break; | 423 break; |
| 443 } | 424 } |
| 444 } | 425 } |
| 445 | 426 |
| 446 if (packets_->Empty()) { | 427 if (packets_->Empty() && !paused_) { |
| 447 // We can not send padding unless a normal packet has first been sent. If we | 428 // We can not send padding unless a normal packet has first been sent. If we |
| 448 // do, timestamps get messed up. | 429 // do, timestamps get messed up. |
| 449 if (packet_counter_ > 0) { | 430 if (packet_counter_ > 0) { |
| 450 int padding_needed = | 431 int padding_needed = |
| 451 static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent) | 432 static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent) |
| 452 : padding_budget_->bytes_remaining()); | 433 : padding_budget_->bytes_remaining()); |
| 434 |
| 453 if (padding_needed > 0) | 435 if (padding_needed > 0) |
| 454 bytes_sent += SendPadding(padding_needed, pacing_info); | 436 bytes_sent += SendPadding(padding_needed, pacing_info); |
| 455 } | 437 } |
| 456 } | 438 } |
| 457 if (is_probing) { | 439 if (is_probing) { |
| 458 probing_send_failure_ = bytes_sent == 0; | 440 probing_send_failure_ = bytes_sent == 0; |
| 459 if (!probing_send_failure_) | 441 if (!probing_send_failure_) |
| 460 prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); | 442 prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); |
| 461 } | 443 } |
| 462 alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms); | 444 alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms); |
| 463 } | 445 } |
| 464 | 446 |
| 465 void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) { | 447 void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) { |
| 466 LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread; | 448 LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread; |
| 467 process_thread_ = process_thread; | 449 process_thread_ = process_thread; |
| 468 } | 450 } |
| 469 | 451 |
| 470 bool PacedSender::SendPacket(const paced_sender::Packet& packet, | 452 bool PacedSender::SendPacket(const paced_sender::Packet& packet, |
| 471 const PacedPacketInfo& pacing_info) { | 453 const PacedPacketInfo& pacing_info) { |
| 472 RTC_DCHECK(!paused_); | 454 if (paused_) |
| 455 return false; |
| 473 if (media_budget_->bytes_remaining() == 0 && | 456 if (media_budget_->bytes_remaining() == 0 && |
| 474 pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe) { | 457 pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe) { |
| 475 return false; | 458 return false; |
| 476 } | 459 } |
| 477 | 460 |
| 478 critsect_.Leave(); | 461 critsect_.Leave(); |
| 479 const bool success = packet_sender_->TimeToSendPacket( | 462 const bool success = packet_sender_->TimeToSendPacket( |
| 480 packet.ssrc, packet.sequence_number, packet.capture_time_ms, | 463 packet.ssrc, packet.sequence_number, packet.capture_time_ms, |
| 481 packet.retransmission, pacing_info); | 464 packet.retransmission, pacing_info); |
| 482 critsect_.Enter(); | 465 critsect_.Enter(); |
| 483 | 466 |
| 484 if (success) { | 467 if (success) { |
| 485 // TODO(holmer): High priority packets should only be accounted for if we | 468 // TODO(holmer): High priority packets should only be accounted for if we |
| 486 // are allocating bandwidth for audio. | 469 // are allocating bandwidth for audio. |
| 487 if (packet.priority != kHighPriority) { | 470 if (packet.priority != kHighPriority) { |
| 488 // Update media bytes sent. | 471 // Update media bytes sent. |
| 489 // TODO(eladalon): TimeToSendPacket() can also return |true| in some | 472 // TODO(eladalon): TimeToSendPacket() can also return |true| in some |
| 490 // situations where nothing actually ended up being sent to the network, | 473 // situations where nothing actually ended up being sent to the network, |
| 491 // and we probably don't want to update the budget in such cases. | 474 // and we probably don't want to update the budget in such cases. |
| 492 // https://bugs.chromium.org/p/webrtc/issues/detail?id=8052 | 475 // https://bugs.chromium.org/p/webrtc/issues/detail?id=8052 |
| 493 UpdateBudgetWithBytesSent(packet.bytes); | 476 UpdateBudgetWithBytesSent(packet.bytes); |
| 494 } | 477 } |
| 495 } | 478 } |
| 496 | 479 |
| 497 return success; | 480 return success; |
| 498 } | 481 } |
| 499 | 482 |
| 500 size_t PacedSender::SendPadding(size_t padding_needed, | 483 size_t PacedSender::SendPadding(size_t padding_needed, |
| 501 const PacedPacketInfo& pacing_info) { | 484 const PacedPacketInfo& pacing_info) { |
| 502 RTC_DCHECK_GT(packet_counter_, 0); | |
| 503 critsect_.Leave(); | 485 critsect_.Leave(); |
| 504 size_t bytes_sent = | 486 size_t bytes_sent = |
| 505 packet_sender_->TimeToSendPadding(padding_needed, pacing_info); | 487 packet_sender_->TimeToSendPadding(padding_needed, pacing_info); |
| 506 critsect_.Enter(); | 488 critsect_.Enter(); |
| 507 | 489 |
| 508 if (bytes_sent > 0) { | 490 if (bytes_sent > 0) { |
| 509 UpdateBudgetWithBytesSent(bytes_sent); | 491 UpdateBudgetWithBytesSent(bytes_sent); |
| 510 } | 492 } |
| 511 return bytes_sent; | 493 return bytes_sent; |
| 512 } | 494 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 525 rtc::CritScope cs(&critsect_); | 507 rtc::CritScope cs(&critsect_); |
| 526 pacing_factor_ = pacing_factor; | 508 pacing_factor_ = pacing_factor; |
| 527 } | 509 } |
| 528 | 510 |
| 529 void PacedSender::SetQueueTimeLimit(int limit_ms) { | 511 void PacedSender::SetQueueTimeLimit(int limit_ms) { |
| 530 rtc::CritScope cs(&critsect_); | 512 rtc::CritScope cs(&critsect_); |
| 531 queue_time_limit = limit_ms; | 513 queue_time_limit = limit_ms; |
| 532 } | 514 } |
| 533 | 515 |
| 534 } // namespace webrtc | 516 } // namespace webrtc |
| OLD | NEW |