| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/video_engine/vie_channel_group.h" |
| |
| #include "webrtc/base/checks.h" |
| #include "webrtc/base/thread_annotations.h" |
| #include "webrtc/common.h" |
| #include "webrtc/experiments.h" |
| #include "webrtc/modules/pacing/include/paced_sender.h" |
| #include "webrtc/modules/pacing/include/packet_router.h" |
| #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" |
| #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h" |
| #include "webrtc/modules/utility/interface/process_thread.h" |
| #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" |
| #include "webrtc/system_wrappers/interface/logging.h" |
| #include "webrtc/video_engine/call_stats.h" |
| #include "webrtc/video_engine/encoder_state_feedback.h" |
| #include "webrtc/video_engine/payload_router.h" |
| #include "webrtc/video_engine/vie_channel.h" |
| #include "webrtc/video_engine/vie_encoder.h" |
| #include "webrtc/video_engine/vie_remb.h" |
| #include "webrtc/voice_engine/include/voe_video_sync.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| static const uint32_t kTimeOffsetSwitchThreshold = 30; |
| |
| class WrappingBitrateEstimator : public RemoteBitrateEstimator { |
| public: |
| WrappingBitrateEstimator(RemoteBitrateObserver* observer, |
| Clock* clock, |
| const Config& config) |
| : observer_(observer), |
| clock_(clock), |
| crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), |
| min_bitrate_bps_(config.Get<RemoteBitrateEstimatorMinRate>().min_rate), |
| rbe_(RemoteBitrateEstimatorFactory().Create(observer_, |
| clock_, |
| kAimdControl, |
| min_bitrate_bps_)), |
| using_absolute_send_time_(false), |
| packets_since_absolute_send_time_(0) { |
| } |
| |
| virtual ~WrappingBitrateEstimator() {} |
| |
| void IncomingPacket(int64_t arrival_time_ms, |
| size_t payload_size, |
| const RTPHeader& header) override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| PickEstimatorFromHeader(header); |
| rbe_->IncomingPacket(arrival_time_ms, payload_size, header); |
| } |
| |
| int32_t Process() override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| return rbe_->Process(); |
| } |
| |
| int64_t TimeUntilNextProcess() override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| return rbe_->TimeUntilNextProcess(); |
| } |
| |
| void OnRttUpdate(int64_t rtt) override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| rbe_->OnRttUpdate(rtt); |
| } |
| |
| void RemoveStream(unsigned int ssrc) override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| rbe_->RemoveStream(ssrc); |
| } |
| |
| bool LatestEstimate(std::vector<unsigned int>* ssrcs, |
| unsigned int* bitrate_bps) const override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| return rbe_->LatestEstimate(ssrcs, bitrate_bps); |
| } |
| |
| bool GetStats(ReceiveBandwidthEstimatorStats* output) const override { |
| CriticalSectionScoped cs(crit_sect_.get()); |
| return rbe_->GetStats(output); |
| } |
| |
| private: |
| void PickEstimatorFromHeader(const RTPHeader& header) |
| EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) { |
| if (header.extension.hasAbsoluteSendTime) { |
| // If we see AST in header, switch RBE strategy immediately. |
| if (!using_absolute_send_time_) { |
| LOG(LS_INFO) << |
| "WrappingBitrateEstimator: Switching to absolute send time RBE."; |
| using_absolute_send_time_ = true; |
| PickEstimator(); |
| } |
| packets_since_absolute_send_time_ = 0; |
| } else { |
| // When we don't see AST, wait for a few packets before going back to TOF. |
| if (using_absolute_send_time_) { |
| ++packets_since_absolute_send_time_; |
| if (packets_since_absolute_send_time_ >= kTimeOffsetSwitchThreshold) { |
| LOG(LS_INFO) << "WrappingBitrateEstimator: Switching to transmission " |
| << "time offset RBE."; |
| using_absolute_send_time_ = false; |
| PickEstimator(); |
| } |
| } |
| } |
| } |
| |
| // Instantiate RBE for Time Offset or Absolute Send Time extensions. |
| void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) { |
| if (using_absolute_send_time_) { |
| rbe_.reset(AbsoluteSendTimeRemoteBitrateEstimatorFactory().Create( |
| observer_, clock_, kAimdControl, min_bitrate_bps_)); |
| } else { |
| rbe_.reset(RemoteBitrateEstimatorFactory().Create( |
| observer_, clock_, kAimdControl, min_bitrate_bps_)); |
| } |
| } |
| |
| RemoteBitrateObserver* observer_; |
| Clock* clock_; |
| rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; |
| const uint32_t min_bitrate_bps_; |
| rtc::scoped_ptr<RemoteBitrateEstimator> rbe_; |
| bool using_absolute_send_time_; |
| uint32_t packets_since_absolute_send_time_; |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator); |
| }; |
| } // namespace |
| |
| ChannelGroup::ChannelGroup(ProcessThread* process_thread, const Config* config) |
| : remb_(new VieRemb()), |
| bitrate_allocator_(new BitrateAllocator()), |
| call_stats_(new CallStats()), |
| encoder_state_feedback_(new EncoderStateFeedback()), |
| packet_router_(new PacketRouter()), |
| pacer_(new PacedSender(Clock::GetRealTimeClock(), |
| packet_router_.get(), |
| BitrateController::kDefaultStartBitrateKbps, |
| PacedSender::kDefaultPaceMultiplier * |
| BitrateController::kDefaultStartBitrateKbps, |
| 0)), |
| encoder_map_cs_(CriticalSectionWrapper::CreateCriticalSection()), |
| config_(config), |
| own_config_(), |
| process_thread_(process_thread), |
| pacer_thread_(ProcessThread::Create()), |
| // Constructed last as this object calls the provided callback on |
| // construction. |
| bitrate_controller_( |
| BitrateController::CreateBitrateController(Clock::GetRealTimeClock(), |
| this)) { |
| if (!config) { |
| own_config_.reset(new Config); |
| config_ = own_config_.get(); |
| } |
| DCHECK(config_); // Must have a valid config pointer here. |
| |
| remote_bitrate_estimator_.reset( |
| new WrappingBitrateEstimator(remb_.get(), |
| Clock::GetRealTimeClock(), |
| *config_)); |
| |
| call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get()); |
| |
| pacer_thread_->RegisterModule(pacer_.get()); |
| pacer_thread_->Start(); |
| |
| process_thread->RegisterModule(remote_bitrate_estimator_.get()); |
| process_thread->RegisterModule(call_stats_.get()); |
| process_thread->RegisterModule(bitrate_controller_.get()); |
| } |
| |
| ChannelGroup::~ChannelGroup() { |
| pacer_thread_->Stop(); |
| pacer_thread_->DeRegisterModule(pacer_.get()); |
| process_thread_->DeRegisterModule(bitrate_controller_.get()); |
| process_thread_->DeRegisterModule(call_stats_.get()); |
| process_thread_->DeRegisterModule(remote_bitrate_estimator_.get()); |
| call_stats_->DeregisterStatsObserver(remote_bitrate_estimator_.get()); |
| DCHECK(channels_.empty()); |
| DCHECK(channel_map_.empty()); |
| DCHECK(!remb_->InUse()); |
| DCHECK(vie_encoder_map_.empty()); |
| } |
| |
| bool ChannelGroup::CreateSendChannel(int channel_id, |
| int engine_id, |
| int number_of_cores, |
| bool disable_default_encoder) { |
| rtc::scoped_ptr<ViEEncoder> vie_encoder(new ViEEncoder( |
| channel_id, number_of_cores, *config_, *process_thread_, pacer_.get(), |
| bitrate_allocator_.get(), bitrate_controller_.get(), false)); |
| if (!vie_encoder->Init()) { |
| return false; |
| } |
| ViEEncoder* encoder = vie_encoder.get(); |
| if (!CreateChannel(channel_id, engine_id, number_of_cores, |
| vie_encoder.release(), true, disable_default_encoder)) { |
| return false; |
| } |
| ViEChannel* channel = channel_map_[channel_id]; |
| // Connect the encoder with the send packet router, to enable sending. |
| encoder->StartThreadsAndSetSharedMembers(channel->send_payload_router(), |
| channel->vcm_protection_callback()); |
| |
| // Register the ViEEncoder to get key frame requests for this channel. |
| unsigned int ssrc = 0; |
| int stream_idx = 0; |
| channel->GetLocalSSRC(stream_idx, &ssrc); |
| encoder_state_feedback_->AddEncoder(ssrc, encoder); |
| std::list<unsigned int> ssrcs; |
| ssrcs.push_back(ssrc); |
| encoder->SetSsrcs(ssrcs); |
| return true; |
| } |
| |
| bool ChannelGroup::CreateReceiveChannel(int channel_id, |
| int engine_id, |
| int base_channel_id, |
| int number_of_cores, |
| bool disable_default_encoder) { |
| ViEEncoder* encoder = GetEncoder(base_channel_id); |
| return CreateChannel(channel_id, engine_id, number_of_cores, encoder, false, |
| disable_default_encoder); |
| } |
| |
| bool ChannelGroup::CreateChannel(int channel_id, |
| int engine_id, |
| int number_of_cores, |
| ViEEncoder* vie_encoder, |
| bool sender, |
| bool disable_default_encoder) { |
| DCHECK(vie_encoder); |
| |
| rtc::scoped_ptr<ViEChannel> channel(new ViEChannel( |
| channel_id, engine_id, number_of_cores, *config_, *process_thread_, |
| encoder_state_feedback_->GetRtcpIntraFrameObserver(), |
| bitrate_controller_->CreateRtcpBandwidthObserver(), |
| remote_bitrate_estimator_.get(), call_stats_->rtcp_rtt_stats(), |
| pacer_.get(), packet_router_.get(), sender, disable_default_encoder)); |
| if (channel->Init() != 0) { |
| return false; |
| } |
| if (!disable_default_encoder) { |
| VideoCodec encoder; |
| if (vie_encoder->GetEncoder(&encoder) != 0) { |
| return false; |
| } |
| if (sender && channel->SetSendCodec(encoder) != 0) { |
| return false; |
| } |
| } |
| |
| // Register the channel to receive stats updates. |
| call_stats_->RegisterStatsObserver(channel->GetStatsObserver()); |
| |
| // Store the channel, add it to the channel group and save the vie_encoder. |
| channel_map_[channel_id] = channel.release(); |
| { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| vie_encoder_map_[channel_id] = vie_encoder; |
| } |
| |
| return true; |
| } |
| |
| void ChannelGroup::DeleteChannel(int channel_id) { |
| ViEChannel* vie_channel = PopChannel(channel_id); |
| |
| ViEEncoder* vie_encoder = GetEncoder(channel_id); |
| DCHECK(vie_encoder != NULL); |
| |
| call_stats_->DeregisterStatsObserver(vie_channel->GetStatsObserver()); |
| SetChannelRembStatus(channel_id, false, false, vie_channel); |
| |
| // If we're owning the encoder, remove the feedback and stop all encoding |
| // threads and processing. This must be done before deleting the channel. |
| if (vie_encoder->channel_id() == channel_id) { |
| encoder_state_feedback_->RemoveEncoder(vie_encoder); |
| vie_encoder->StopThreadsAndRemoveSharedMembers(); |
| } |
| |
| unsigned int remote_ssrc = 0; |
| vie_channel->GetRemoteSSRC(&remote_ssrc); |
| RemoveChannel(channel_id); |
| remote_bitrate_estimator_->RemoveStream(remote_ssrc); |
| |
| // Check if other channels are using the same encoder. |
| if (OtherChannelsUsingEncoder(channel_id)) { |
| vie_encoder = NULL; |
| } else { |
| // Delete later when we've released the critsect. |
| } |
| |
| // We can't erase the item before we've checked for other channels using |
| // same ViEEncoder. |
| PopEncoder(channel_id); |
| |
| delete vie_channel; |
| // Leave the write critsect before deleting the objects. |
| // Deleting a channel can cause other objects, such as renderers, to be |
| // deleted, which might take time. |
| // If statment just to show that this object is not always deleted. |
| if (vie_encoder) { |
| LOG(LS_VERBOSE) << "ViEEncoder deleted for channel " << channel_id; |
| delete vie_encoder; |
| } |
| |
| LOG(LS_VERBOSE) << "Channel deleted " << channel_id; |
| } |
| |
| void ChannelGroup::AddChannel(int channel_id) { |
| channels_.insert(channel_id); |
| } |
| |
| void ChannelGroup::RemoveChannel(int channel_id) { |
| channels_.erase(channel_id); |
| } |
| |
| bool ChannelGroup::HasChannel(int channel_id) const { |
| return channels_.find(channel_id) != channels_.end(); |
| } |
| |
| bool ChannelGroup::Empty() const { |
| return channels_.empty(); |
| } |
| |
| ViEChannel* ChannelGroup::GetChannel(int channel_id) const { |
| ChannelMap::const_iterator it = channel_map_.find(channel_id); |
| if (it == channel_map_.end()) { |
| LOG(LS_ERROR) << "Channel doesn't exist " << channel_id; |
| return NULL; |
| } |
| return it->second; |
| } |
| |
| ViEEncoder* ChannelGroup::GetEncoder(int channel_id) const { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| EncoderMap::const_iterator it = vie_encoder_map_.find(channel_id); |
| if (it == vie_encoder_map_.end()) { |
| return NULL; |
| } |
| return it->second; |
| } |
| |
| ViEChannel* ChannelGroup::PopChannel(int channel_id) { |
| ChannelMap::iterator c_it = channel_map_.find(channel_id); |
| DCHECK(c_it != channel_map_.end()); |
| ViEChannel* channel = c_it->second; |
| channel_map_.erase(c_it); |
| |
| return channel; |
| } |
| |
| ViEEncoder* ChannelGroup::PopEncoder(int channel_id) { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| EncoderMap::iterator e_it = vie_encoder_map_.find(channel_id); |
| DCHECK(e_it != vie_encoder_map_.end()); |
| ViEEncoder* encoder = e_it->second; |
| vie_encoder_map_.erase(e_it); |
| |
| return encoder; |
| } |
| |
| std::vector<int> ChannelGroup::GetChannelIds() const { |
| std::vector<int> ids; |
| for (auto channel : channel_map_) |
| ids.push_back(channel.first); |
| return ids; |
| } |
| |
| bool ChannelGroup::OtherChannelsUsingEncoder(int channel_id) const { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| EncoderMap::const_iterator orig_it = vie_encoder_map_.find(channel_id); |
| if (orig_it == vie_encoder_map_.end()) { |
| // No ViEEncoder for this channel. |
| return false; |
| } |
| |
| // Loop through all other channels to see if anyone points at the same |
| // ViEEncoder. |
| for (EncoderMap::const_iterator comp_it = vie_encoder_map_.begin(); |
| comp_it != vie_encoder_map_.end(); ++comp_it) { |
| // Make sure we're not comparing the same channel with itself. |
| if (comp_it->first != channel_id) { |
| if (comp_it->second == orig_it->second) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void ChannelGroup::SetSyncInterface(VoEVideoSync* sync_interface) { |
| for (auto channel : channel_map_) { |
| channel.second->SetVoiceChannel(-1, sync_interface); |
| } |
| } |
| |
| void ChannelGroup::GetChannelsUsingEncoder(int channel_id, |
| ChannelList* channels) const { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| EncoderMap::const_iterator orig_it = vie_encoder_map_.find(channel_id); |
| |
| for (ChannelMap::const_iterator c_it = channel_map_.begin(); |
| c_it != channel_map_.end(); ++c_it) { |
| EncoderMap::const_iterator comp_it = vie_encoder_map_.find(c_it->first); |
| DCHECK(comp_it != vie_encoder_map_.end()); |
| if (comp_it->second == orig_it->second) { |
| channels->push_back(c_it->second); |
| } |
| } |
| } |
| |
| BitrateController* ChannelGroup::GetBitrateController() const { |
| return bitrate_controller_.get(); |
| } |
| |
| RemoteBitrateEstimator* ChannelGroup::GetRemoteBitrateEstimator() const { |
| return remote_bitrate_estimator_.get(); |
| } |
| |
| CallStats* ChannelGroup::GetCallStats() const { |
| return call_stats_.get(); |
| } |
| |
| EncoderStateFeedback* ChannelGroup::GetEncoderStateFeedback() const { |
| return encoder_state_feedback_.get(); |
| } |
| |
| int64_t ChannelGroup::GetPacerQueuingDelayMs() const { |
| return pacer_->QueueInMs(); |
| } |
| |
| void ChannelGroup::SetChannelRembStatus(int channel_id, |
| bool sender, |
| bool receiver, |
| ViEChannel* channel) { |
| // Update the channel state. |
| channel->EnableRemb(sender || receiver); |
| // Update the REMB instance with necessary RTP modules. |
| RtpRtcp* rtp_module = channel->rtp_rtcp(); |
| if (sender) { |
| remb_->AddRembSender(rtp_module); |
| } else { |
| remb_->RemoveRembSender(rtp_module); |
| } |
| if (receiver) { |
| remb_->AddReceiveChannel(rtp_module); |
| } else { |
| remb_->RemoveReceiveChannel(rtp_module); |
| } |
| } |
| |
| void ChannelGroup::OnNetworkChanged(uint32_t target_bitrate_bps, |
| uint8_t fraction_loss, |
| int64_t rtt) { |
| bitrate_allocator_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt); |
| int pad_up_to_bitrate_bps = 0; |
| { |
| CriticalSectionScoped lock(encoder_map_cs_.get()); |
| for (const auto& encoder : vie_encoder_map_) { |
| pad_up_to_bitrate_bps += |
| encoder.second->GetPaddingNeededBps(target_bitrate_bps); |
| } |
| } |
| pacer_->UpdateBitrate( |
| target_bitrate_bps / 1000, |
| PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000, |
| pad_up_to_bitrate_bps / 1000); |
| } |
| } // namespace webrtc |