/* * Copyright (c) 2018 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 "media/base/media_channel.h" #include "media/base/rtp_utils.h" #include "rtc_base/task_utils/to_queued_task.h" namespace cricket { using webrtc::FrameDecryptorInterface; using webrtc::FrameEncryptorInterface; using webrtc::FrameTransformerInterface; using webrtc::PendingTaskSafetyFlag; using webrtc::TaskQueueBase; using webrtc::ToQueuedTask; using webrtc::VideoTrackInterface; VideoOptions::VideoOptions() : content_hint(VideoTrackInterface::ContentHint::kNone) {} VideoOptions::~VideoOptions() = default; MediaChannel::MediaChannel(const MediaConfig& config, TaskQueueBase* network_thread) : enable_dscp_(config.enable_dscp), network_safety_(PendingTaskSafetyFlag::CreateDetachedInactive()), network_thread_(network_thread) {} MediaChannel::MediaChannel(TaskQueueBase* network_thread) : enable_dscp_(false), network_safety_(PendingTaskSafetyFlag::CreateDetachedInactive()), network_thread_(network_thread) {} MediaChannel::~MediaChannel() { RTC_DCHECK(!network_interface_); } void MediaChannel::SetInterface(NetworkInterface* iface) { RTC_DCHECK_RUN_ON(network_thread_); iface ? network_safety_->SetAlive() : network_safety_->SetNotAlive(); network_interface_ = iface; UpdateDscp(); } int MediaChannel::GetRtpSendTimeExtnId() const { return -1; } void MediaChannel::SetFrameEncryptor( uint32_t ssrc, rtc::scoped_refptr frame_encryptor) { // Placeholder should be pure virtual once internal supports it. } void MediaChannel::SetFrameDecryptor( uint32_t ssrc, rtc::scoped_refptr frame_decryptor) { // Placeholder should be pure virtual once internal supports it. } void MediaChannel::SetVideoCodecSwitchingEnabled(bool enabled) {} bool MediaChannel::SendPacket(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options) { return DoSendPacket(packet, false, options); } bool MediaChannel::SendRtcp(rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options) { return DoSendPacket(packet, true, options); } int MediaChannel::SetOption(NetworkInterface::SocketType type, rtc::Socket::Option opt, int option) { RTC_DCHECK_RUN_ON(network_thread_); return SetOptionLocked(type, opt, option); } // Corresponds to the SDP attribute extmap-allow-mixed, see RFC8285. // Set to true if it's allowed to mix one- and two-byte RTP header extensions // in the same stream. The setter and getter must only be called from // worker_thread. void MediaChannel::SetExtmapAllowMixed(bool extmap_allow_mixed) { extmap_allow_mixed_ = extmap_allow_mixed; } bool MediaChannel::ExtmapAllowMixed() const { return extmap_allow_mixed_; } void MediaChannel::SetEncoderToPacketizerFrameTransformer( uint32_t ssrc, rtc::scoped_refptr frame_transformer) {} void MediaChannel::SetDepacketizerToDecoderFrameTransformer( uint32_t ssrc, rtc::scoped_refptr frame_transformer) {} int MediaChannel::SetOptionLocked(NetworkInterface::SocketType type, rtc::Socket::Option opt, int option) { if (!network_interface_) return -1; return network_interface_->SetOption(type, opt, option); } bool MediaChannel::DscpEnabled() const { return enable_dscp_; } // This is the DSCP value used for both RTP and RTCP channels if DSCP is // enabled. It can be changed at any time via `SetPreferredDscp`. rtc::DiffServCodePoint MediaChannel::PreferredDscp() const { RTC_DCHECK_RUN_ON(network_thread_); return preferred_dscp_; } void MediaChannel::SetPreferredDscp(rtc::DiffServCodePoint new_dscp) { if (!network_thread_->IsCurrent()) { // This is currently the common path as the derived channel classes // get called on the worker thread. There are still some tests though // that call directly on the network thread. network_thread_->PostTask(ToQueuedTask( network_safety_, [this, new_dscp]() { SetPreferredDscp(new_dscp); })); return; } RTC_DCHECK_RUN_ON(network_thread_); if (new_dscp == preferred_dscp_) return; preferred_dscp_ = new_dscp; UpdateDscp(); } rtc::scoped_refptr MediaChannel::network_safety() { return network_safety_; } void MediaChannel::UpdateDscp() { rtc::DiffServCodePoint value = enable_dscp_ ? preferred_dscp_ : rtc::DSCP_DEFAULT; int ret = SetOptionLocked(NetworkInterface::ST_RTP, rtc::Socket::OPT_DSCP, value); if (ret == 0) SetOptionLocked(NetworkInterface::ST_RTCP, rtc::Socket::OPT_DSCP, value); } bool MediaChannel::DoSendPacket(rtc::CopyOnWriteBuffer* packet, bool rtcp, const rtc::PacketOptions& options) { RTC_DCHECK_RUN_ON(network_thread_); if (!network_interface_) return false; return (!rtcp) ? network_interface_->SendPacket(packet, options) : network_interface_->SendRtcp(packet, options); } void MediaChannel::SendRtp(const uint8_t* data, size_t len, const webrtc::PacketOptions& options) { auto send = [this, packet_id = options.packet_id, included_in_feedback = options.included_in_feedback, included_in_allocation = options.included_in_allocation, packet = rtc::CopyOnWriteBuffer(data, len, kMaxRtpPacketLen)]() mutable { rtc::PacketOptions rtc_options; rtc_options.packet_id = packet_id; if (DscpEnabled()) { rtc_options.dscp = PreferredDscp(); } rtc_options.info_signaled_after_sent.included_in_feedback = included_in_feedback; rtc_options.info_signaled_after_sent.included_in_allocation = included_in_allocation; SendPacket(&packet, rtc_options); }; // TODO(bugs.webrtc.org/11993): ModuleRtpRtcpImpl2 and related classes (e.g. // RTCPSender) aren't aware of the network thread and may trigger calls to // this function from different threads. Update those classes to keep // network traffic on the network thread. if (network_thread_->IsCurrent()) { send(); } else { network_thread_->PostTask(ToQueuedTask(network_safety_, std::move(send))); } } void MediaChannel::SendRtcp(const uint8_t* data, size_t len) { auto send = [this, packet = rtc::CopyOnWriteBuffer( data, len, kMaxRtpPacketLen)]() mutable { rtc::PacketOptions rtc_options; if (DscpEnabled()) { rtc_options.dscp = PreferredDscp(); } SendRtcp(&packet, rtc_options); }; if (network_thread_->IsCurrent()) { send(); } else { network_thread_->PostTask(ToQueuedTask(network_safety_, std::move(send))); } } MediaSenderInfo::MediaSenderInfo() = default; MediaSenderInfo::~MediaSenderInfo() = default; MediaReceiverInfo::MediaReceiverInfo() = default; MediaReceiverInfo::~MediaReceiverInfo() = default; VoiceSenderInfo::VoiceSenderInfo() = default; VoiceSenderInfo::~VoiceSenderInfo() = default; VoiceReceiverInfo::VoiceReceiverInfo() = default; VoiceReceiverInfo::~VoiceReceiverInfo() = default; VideoSenderInfo::VideoSenderInfo() = default; VideoSenderInfo::~VideoSenderInfo() = default; VideoReceiverInfo::VideoReceiverInfo() = default; VideoReceiverInfo::~VideoReceiverInfo() = default; VoiceMediaInfo::VoiceMediaInfo() = default; VoiceMediaInfo::~VoiceMediaInfo() = default; VideoMediaInfo::VideoMediaInfo() = default; VideoMediaInfo::~VideoMediaInfo() = default; AudioSendParameters::AudioSendParameters() = default; AudioSendParameters::~AudioSendParameters() = default; std::map AudioSendParameters::ToStringMap() const { auto params = RtpSendParameters::ToStringMap(); params["options"] = options.ToString(); return params; } cricket::MediaType VoiceMediaChannel::media_type() const { return cricket::MediaType::MEDIA_TYPE_AUDIO; } VideoSendParameters::VideoSendParameters() = default; VideoSendParameters::~VideoSendParameters() = default; std::map VideoSendParameters::ToStringMap() const { auto params = RtpSendParameters::ToStringMap(); params["conference_mode"] = (conference_mode ? "yes" : "no"); return params; } cricket::MediaType VideoMediaChannel::media_type() const { return cricket::MediaType::MEDIA_TYPE_VIDEO; } } // namespace cricket