| /* |
| * 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_impl.h" |
| |
| #include <map> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "api/audio_options.h" |
| #include "api/media_stream_interface.h" |
| #include "api/rtc_error.h" |
| #include "api/rtp_sender_interface.h" |
| #include "api/units/time_delta.h" |
| #include "api/video/video_timing.h" |
| #include "api/video_codecs/scalability_mode.h" |
| #include "common_video/include/quality_limitation_reason.h" |
| #include "media/base/codec.h" |
| #include "media/base/media_channel.h" |
| #include "media/base/rtp_utils.h" |
| #include "media/base/stream_params.h" |
| #include "modules/rtp_rtcp/include/report_block_data.h" |
| #include "rtc_base/checks.h" |
| |
| namespace webrtc { |
| |
| webrtc::RTCError InvokeSetParametersCallback(SetParametersCallback& callback, |
| RTCError error) { |
| if (callback) { |
| std::move(callback)(error); |
| callback = nullptr; |
| } |
| return error; |
| } |
| |
| } // namespace webrtc |
| |
| namespace cricket { |
| using webrtc::FrameDecryptorInterface; |
| using webrtc::FrameEncryptorInterface; |
| using webrtc::FrameTransformerInterface; |
| using webrtc::PendingTaskSafetyFlag; |
| using webrtc::SafeTask; |
| using webrtc::TaskQueueBase; |
| using webrtc::VideoTrackInterface; |
| |
| VideoOptions::VideoOptions() |
| : content_hint(VideoTrackInterface::ContentHint::kNone) {} |
| VideoOptions::~VideoOptions() = default; |
| |
| MediaChannelUtil::MediaChannelUtil(TaskQueueBase* network_thread, |
| bool enable_dscp) |
| : enable_dscp_(enable_dscp), |
| network_safety_(PendingTaskSafetyFlag::CreateDetachedInactive()), |
| network_thread_(network_thread) {} |
| |
| MediaChannel::MediaChannel(Role role, |
| TaskQueueBase* network_thread, |
| bool enable_dscp) |
| : MediaChannelUtil(network_thread, enable_dscp), role_(role) {} |
| |
| MediaChannelUtil::~MediaChannelUtil() { |
| RTC_DCHECK(!network_interface_); |
| } |
| |
| void MediaChannelUtil::SetInterface(MediaChannelNetworkInterface* iface) { |
| RTC_DCHECK_RUN_ON(network_thread_); |
| iface ? network_safety_->SetAlive() : network_safety_->SetNotAlive(); |
| network_interface_ = iface; |
| UpdateDscp(); |
| } |
| |
| int MediaChannelUtil::GetRtpSendTimeExtnId() const { |
| return -1; |
| } |
| |
| void MediaChannelUtil::SetFrameEncryptor( |
| uint32_t ssrc, |
| rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) { |
| // Placeholder should be pure virtual once internal supports it. |
| } |
| |
| void MediaChannelUtil::SetFrameDecryptor( |
| uint32_t ssrc, |
| rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) { |
| // Placeholder should be pure virtual once internal supports it. |
| } |
| |
| bool MediaChannelUtil::SendPacket(rtc::CopyOnWriteBuffer* packet, |
| const rtc::PacketOptions& options) { |
| return DoSendPacket(packet, false, options); |
| } |
| |
| bool MediaChannelUtil::SendRtcp(rtc::CopyOnWriteBuffer* packet, |
| const rtc::PacketOptions& options) { |
| return DoSendPacket(packet, true, options); |
| } |
| |
| int MediaChannelUtil::SetOption(MediaChannelNetworkInterface::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 MediaChannelUtil::SetExtmapAllowMixed(bool extmap_allow_mixed) { |
| extmap_allow_mixed_ = extmap_allow_mixed; |
| } |
| |
| bool MediaChannelUtil::ExtmapAllowMixed() const { |
| return extmap_allow_mixed_; |
| } |
| |
| bool MediaChannelUtil::HasNetworkInterface() const { |
| RTC_DCHECK_RUN_ON(network_thread_); |
| return network_interface_ != nullptr; |
| } |
| |
| void MediaChannelUtil::SetEncoderToPacketizerFrameTransformer( |
| uint32_t ssrc, |
| rtc::scoped_refptr<FrameTransformerInterface> frame_transformer) {} |
| |
| void MediaChannelUtil::SetDepacketizerToDecoderFrameTransformer( |
| uint32_t ssrc, |
| rtc::scoped_refptr<FrameTransformerInterface> frame_transformer) {} |
| |
| int MediaChannelUtil::SetOptionLocked( |
| MediaChannelNetworkInterface::SocketType type, |
| rtc::Socket::Option opt, |
| int option) { |
| if (!network_interface_) |
| return -1; |
| return network_interface_->SetOption(type, opt, option); |
| } |
| |
| bool MediaChannelUtil::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 MediaChannelUtil::PreferredDscp() const { |
| RTC_DCHECK_RUN_ON(network_thread_); |
| return preferred_dscp_; |
| } |
| |
| void MediaChannelUtil::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(SafeTask( |
| 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<PendingTaskSafetyFlag> MediaChannelUtil::network_safety() { |
| return network_safety_; |
| } |
| |
| void MediaChannelUtil::UpdateDscp() { |
| rtc::DiffServCodePoint value = |
| enable_dscp_ ? preferred_dscp_ : rtc::DSCP_DEFAULT; |
| int ret = SetOptionLocked(MediaChannelNetworkInterface::ST_RTP, |
| rtc::Socket::OPT_DSCP, value); |
| if (ret == 0) |
| SetOptionLocked(MediaChannelNetworkInterface::ST_RTCP, |
| rtc::Socket::OPT_DSCP, value); |
| } |
| |
| bool MediaChannelUtil::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 MediaChannelUtil::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, |
| batchable = options.batchable, |
| last_packet_in_batch = options.last_packet_in_batch, |
| 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; |
| rtc_options.batchable = batchable; |
| rtc_options.last_packet_in_batch = last_packet_in_batch; |
| 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(SafeTask(network_safety_, std::move(send))); |
| } |
| } |
| |
| void MediaChannelUtil::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(SafeTask(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; |
| |
| VideoMediaSendInfo::VideoMediaSendInfo() = default; |
| VideoMediaSendInfo::~VideoMediaSendInfo() = default; |
| |
| VoiceMediaSendInfo::VoiceMediaSendInfo() = default; |
| VoiceMediaSendInfo::~VoiceMediaSendInfo() = default; |
| |
| VideoMediaReceiveInfo::VideoMediaReceiveInfo() = default; |
| VideoMediaReceiveInfo::~VideoMediaReceiveInfo() = default; |
| |
| VoiceMediaReceiveInfo::VoiceMediaReceiveInfo() = default; |
| VoiceMediaReceiveInfo::~VoiceMediaReceiveInfo() = default; |
| |
| AudioSendParameters::AudioSendParameters() = default; |
| AudioSendParameters::~AudioSendParameters() = default; |
| |
| std::map<std::string, std::string> AudioSendParameters::ToStringMap() const { |
| auto params = RtpSendParameters<AudioCodec>::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<std::string, std::string> VideoSendParameters::ToStringMap() const { |
| auto params = RtpSendParameters<VideoCodec>::ToStringMap(); |
| params["conference_mode"] = (conference_mode ? "yes" : "no"); |
| return params; |
| } |
| |
| cricket::MediaType VideoMediaChannel::media_type() const { |
| return cricket::MediaType::MEDIA_TYPE_VIDEO; |
| } |
| |
| void VideoMediaChannel::SetVideoCodecSwitchingEnabled(bool enabled) {} |
| |
| } // namespace cricket |