Enable End-to-End Encrypted Video Frames.
This change integrates the FrameDecryptorInterface and the FrameEncryptorInterface into the video send and receive path. If a FrameEncryptorInterface is set on an outgoing video RTPSender then each outgoing video frame will first pass through the provided FrameEncryptor which will have a chance to modify the payload contents for the purposes of encryption. In addition to this the new GenericFrameDescriptor will be added as additional data. If a FrameDecryptorInterface is set on an incoming video RtpReceiver then each incoming video payload will first pass through the provided FrameDecryptor which have a chance to modify the payload contents for the purpose of decryption. Bug: webrtc:9795 Change-Id: I9f743ce0cb63df0cf070f6144be7ada078b4e5d2 Reviewed-on: https://webrtc-review.googlesource.com/c/103920 Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Åsa Persson <asapersson@webrtc.org> Commit-Queue: Benjamin Wright <benwright@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25258}
This commit is contained in:

committed by
Commit Bot

parent
6714bf9f18
commit
192eeec14d
@ -89,14 +89,16 @@ RtpVideoSenderInterface* RtpTransportControllerSend::CreateRtpVideoSender(
|
||||
Transport* send_transport,
|
||||
const RtpSenderObservers& observers,
|
||||
RtcEventLog* event_log,
|
||||
std::unique_ptr<FecController> fec_controller) {
|
||||
std::unique_ptr<FecController> fec_controller,
|
||||
const RtpSenderFrameEncryptionConfig& frame_encryption_config) {
|
||||
video_rtp_senders_.push_back(absl::make_unique<RtpVideoSender>(
|
||||
ssrcs, suspended_ssrcs, states, rtp_config, rtcp_config, send_transport,
|
||||
observers,
|
||||
// TODO(holmer): Remove this circular dependency by injecting
|
||||
// the parts of RtpTransportControllerSendInterface that are really used.
|
||||
this, event_log, &retransmission_rate_limiter_,
|
||||
std::move(fec_controller)));
|
||||
this, event_log, &retransmission_rate_limiter_, std::move(fec_controller),
|
||||
frame_encryption_config.frame_encryptor,
|
||||
frame_encryption_config.crypto_options));
|
||||
return video_rtp_senders_.back().get();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,9 @@
|
||||
#include "rtc_base/task_queue.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Clock;
|
||||
class FrameEncryptorInterface;
|
||||
class RtcEventLog;
|
||||
|
||||
// TODO(nisse): When we get the underlying transports here, we should
|
||||
@ -56,7 +58,8 @@ class RtpTransportControllerSend final
|
||||
Transport* send_transport,
|
||||
const RtpSenderObservers& observers,
|
||||
RtcEventLog* event_log,
|
||||
std::unique_ptr<FecController> fec_controller) override;
|
||||
std::unique_ptr<FecController> fec_controller,
|
||||
const RtpSenderFrameEncryptionConfig& frame_encryption_config) override;
|
||||
void DestroyRtpVideoSender(
|
||||
RtpVideoSenderInterface* rtp_video_sender) override;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/bitrate_constraints.h"
|
||||
#include "api/crypto/cryptooptions.h"
|
||||
#include "api/fec_controller.h"
|
||||
#include "api/transport/bitrate_settings.h"
|
||||
#include "call/rtp_config.h"
|
||||
@ -35,6 +36,7 @@ namespace webrtc {
|
||||
|
||||
class CallStats;
|
||||
class CallStatsObserver;
|
||||
class FrameEncryptorInterface;
|
||||
class TargetTransferRateObserver;
|
||||
class Transport;
|
||||
class Module;
|
||||
@ -62,6 +64,11 @@ struct RtpSenderObservers {
|
||||
SendPacketObserver* send_packet_observer;
|
||||
};
|
||||
|
||||
struct RtpSenderFrameEncryptionConfig {
|
||||
FrameEncryptorInterface* frame_encryptor = nullptr;
|
||||
CryptoOptions crypto_options;
|
||||
};
|
||||
|
||||
// An RtpTransportController should own everything related to the RTP
|
||||
// transport to/from a remote endpoint. We should have separate
|
||||
// interfaces for send and receive side, even if they are implemented
|
||||
@ -101,7 +108,8 @@ class RtpTransportControllerSendInterface {
|
||||
Transport* send_transport,
|
||||
const RtpSenderObservers& observers,
|
||||
RtcEventLog* event_log,
|
||||
std::unique_ptr<FecController> fec_controller) = 0;
|
||||
std::unique_ptr<FecController> fec_controller,
|
||||
const RtpSenderFrameEncryptionConfig& frame_encryption_config) = 0;
|
||||
virtual void DestroyRtpVideoSender(
|
||||
RtpVideoSenderInterface* rtp_video_sender) = 0;
|
||||
|
||||
|
@ -56,8 +56,11 @@ std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules(
|
||||
RtcEventLog* event_log,
|
||||
RateLimiter* retransmission_rate_limiter,
|
||||
OverheadObserver* overhead_observer,
|
||||
RtpKeepAliveConfig keepalive_config) {
|
||||
RtpKeepAliveConfig keepalive_config,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
const CryptoOptions& crypto_options) {
|
||||
RTC_DCHECK_GT(ssrcs.size(), 0);
|
||||
|
||||
RtpRtcp::Configuration configuration;
|
||||
configuration.audio = false;
|
||||
configuration.receiver_only = false;
|
||||
@ -83,6 +86,10 @@ std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules(
|
||||
rtcp_config.video_report_interval_ms;
|
||||
configuration.rtcp_interval_config.audio_interval_ms =
|
||||
rtcp_config.audio_report_interval_ms;
|
||||
configuration.frame_encryptor = frame_encryptor;
|
||||
configuration.require_frame_encryption =
|
||||
crypto_options.sframe.require_frame_encryption;
|
||||
|
||||
std::vector<std::unique_ptr<RtpRtcp>> modules;
|
||||
const std::vector<uint32_t>& flexfec_protected_ssrcs = protected_media_ssrcs;
|
||||
for (uint32_t ssrc : ssrcs) {
|
||||
@ -183,7 +190,9 @@ RtpVideoSender::RtpVideoSender(
|
||||
RtpTransportControllerSendInterface* transport,
|
||||
RtcEventLog* event_log,
|
||||
RateLimiter* retransmission_limiter,
|
||||
std::unique_ptr<FecController> fec_controller)
|
||||
std::unique_ptr<FecController> fec_controller,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
const CryptoOptions& crypto_options)
|
||||
: send_side_bwe_with_overhead_(
|
||||
webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
|
||||
active_(false),
|
||||
@ -209,7 +218,9 @@ RtpVideoSender::RtpVideoSender(
|
||||
event_log,
|
||||
retransmission_limiter,
|
||||
this,
|
||||
transport->keepalive_config())),
|
||||
transport->keepalive_config(),
|
||||
frame_encryptor,
|
||||
crypto_options)),
|
||||
rtp_config_(rtp_config),
|
||||
transport_(transport),
|
||||
transport_overhead_bytes_per_packet_(0),
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
class RTPFragmentationHeader;
|
||||
class RtpRtcp;
|
||||
class RtpTransportControllerSendInterface;
|
||||
@ -59,7 +60,9 @@ class RtpVideoSender : public RtpVideoSenderInterface,
|
||||
RtpTransportControllerSendInterface* transport,
|
||||
RtcEventLog* event_log,
|
||||
RateLimiter* retransmission_limiter, // move inside RtpTransport
|
||||
std::unique_ptr<FecController> fec_controller);
|
||||
std::unique_ptr<FecController> fec_controller,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
const CryptoOptions& crypto_options); // move inside RtpTransport
|
||||
~RtpVideoSender() override;
|
||||
|
||||
// RegisterProcessThread register |module_process_thread| with those objects
|
||||
|
@ -107,7 +107,8 @@ class RtpVideoSenderTestFixture {
|
||||
&stats_proxy_, &stats_proxy_, &stats_proxy_,
|
||||
&stats_proxy_, &stats_proxy_, &send_delay_stats_),
|
||||
&transport_controller_, &event_log_, &retransmission_rate_limiter_,
|
||||
absl::make_unique<FecControllerDefault>(&clock_));
|
||||
absl::make_unique<FecControllerDefault>(&clock_), nullptr,
|
||||
CryptoOptions{});
|
||||
}
|
||||
|
||||
RtpVideoSender* router() { return router_.get(); }
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include "api/bitrate_constraints.h"
|
||||
#include "api/crypto/cryptooptions.h"
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "call/rtp_transport_controller_send_interface.h"
|
||||
#include "modules/congestion_controller/include/network_changed_observer.h"
|
||||
#include "modules/pacing/packet_router.h"
|
||||
@ -30,7 +32,7 @@ namespace webrtc {
|
||||
class MockRtpTransportControllerSend
|
||||
: public RtpTransportControllerSendInterface {
|
||||
public:
|
||||
MOCK_METHOD9(
|
||||
MOCK_METHOD10(
|
||||
CreateRtpVideoSender,
|
||||
RtpVideoSenderInterface*(const std::vector<uint32_t>&,
|
||||
std::map<uint32_t, RtpState>,
|
||||
@ -40,7 +42,8 @@ class MockRtpTransportControllerSend
|
||||
Transport*,
|
||||
const RtpSenderObservers&,
|
||||
RtcEventLog*,
|
||||
std::unique_ptr<FecController>));
|
||||
std::unique_ptr<FecController>,
|
||||
const RtpSenderFrameEncryptionConfig&));
|
||||
MOCK_METHOD1(DestroyRtpVideoSender, void(RtpVideoSenderInterface*));
|
||||
MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*());
|
||||
MOCK_METHOD0(packet_router, PacketRouter*());
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "api/call/transport.h"
|
||||
#include "api/crypto/cryptooptions.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/rtpparameters.h"
|
||||
#include "api/rtpreceiverinterface.h"
|
||||
@ -30,6 +31,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameDecryptorInterface;
|
||||
class RtpPacketSinkInterface;
|
||||
class VideoDecoderFactory;
|
||||
|
||||
@ -214,6 +216,14 @@ class VideoReceiveStream {
|
||||
// TODO(nisse): Used with VideoDecoderFactory::LegacyCreateVideoDecoder.
|
||||
// Delete when that method is retired.
|
||||
std::string stream_id;
|
||||
|
||||
// An optional custom frame decryptor that allows the entire frame to be
|
||||
// decrypted in whatever way the caller choses. This is not required by
|
||||
// default.
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor;
|
||||
|
||||
// Per PeerConnection cryptography options.
|
||||
CryptoOptions crypto_options;
|
||||
};
|
||||
|
||||
// Starts stream activity.
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "call/video_send_stream.h"
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "api/call/transport.h"
|
||||
#include "api/crypto/cryptooptions.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "api/video/video_sink_interface.h"
|
||||
#include "api/video/video_source_interface.h"
|
||||
@ -29,6 +30,8 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
|
||||
class VideoSendStream {
|
||||
public:
|
||||
struct StreamStats {
|
||||
@ -137,6 +140,14 @@ class VideoSendStream {
|
||||
// Track ID as specified during track creation.
|
||||
std::string track_id;
|
||||
|
||||
// An optional custom frame encryptor that allows the entire frame to be
|
||||
// encrypted in whatever way the caller chooses. This is not required by
|
||||
// default.
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor;
|
||||
|
||||
// Per PeerConnection cryptography options.
|
||||
CryptoOptions crypto_options;
|
||||
|
||||
private:
|
||||
// Access to the copy constructor is private to force use of the Copy()
|
||||
// method for those exceptional cases where we do use it.
|
||||
|
@ -525,7 +525,8 @@ WebRtcVideoChannel::WebRtcVideoChannel(
|
||||
default_send_options_(options),
|
||||
last_stats_log_ms_(-1),
|
||||
discard_unknown_ssrc_packets_(webrtc::field_trial::IsEnabled(
|
||||
"WebRTC-Video-DiscardPacketsWithUnknownSsrc")) {
|
||||
"WebRTC-Video-DiscardPacketsWithUnknownSsrc")),
|
||||
crypto_options_(crypto_options) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
|
||||
@ -1037,6 +1038,7 @@ bool WebRtcVideoChannel::AddSendStream(const StreamParams& sp) {
|
||||
config.encoder_settings.experiment_cpu_load_estimator =
|
||||
video_config_.experiment_cpu_load_estimator;
|
||||
config.encoder_settings.encoder_factory = encoder_factory_;
|
||||
config.crypto_options = crypto_options_;
|
||||
|
||||
WebRtcVideoSendStream* stream = new WebRtcVideoSendStream(
|
||||
call_, sp, std::move(config), default_send_options_,
|
||||
@ -1153,6 +1155,7 @@ bool WebRtcVideoChannel::AddRecvStream(const StreamParams& sp,
|
||||
webrtc::FlexfecReceiveStream::Config flexfec_config(this);
|
||||
ConfigureReceiverRtp(&config, &flexfec_config, sp);
|
||||
|
||||
config.crypto_options = crypto_options_;
|
||||
// TODO(nisse): Rename config variable to avoid negation.
|
||||
config.disable_prerenderer_smoothing =
|
||||
!video_config_.enable_prerenderer_smoothing;
|
||||
@ -1457,6 +1460,28 @@ void WebRtcVideoChannel::SetInterface(
|
||||
kVideoRtpBufferSize);
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::SetFrameDecryptor(
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor) {
|
||||
rtc::CritScope stream_lock(&stream_crit_);
|
||||
auto matching_stream = receive_streams_.find(ssrc);
|
||||
if (matching_stream != receive_streams_.end()) {
|
||||
matching_stream->second->SetFrameDecryptor(frame_decryptor);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::SetFrameEncryptor(
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
|
||||
rtc::CritScope stream_lock(&stream_crit_);
|
||||
auto matching_stream = send_streams_.find(ssrc);
|
||||
if (matching_stream != send_streams_.end()) {
|
||||
matching_stream->second->SetFrameEncryptor(frame_encryptor);
|
||||
} else {
|
||||
RTC_LOG(LS_ERROR) << "No stream found to attach frame encryptor";
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<uint32_t> WebRtcVideoChannel::GetDefaultReceiveStreamSsrc() {
|
||||
rtc::CritScope stream_lock(&stream_crit_);
|
||||
absl::optional<uint32_t> ssrc;
|
||||
@ -1821,6 +1846,15 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetRtpParameters() const {
|
||||
return rtp_parameters_;
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::WebRtcVideoSendStream::SetFrameEncryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
parameters_.config.frame_encryptor = frame_encryptor;
|
||||
if (stream_) {
|
||||
RecreateWebRtcStream();
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::WebRtcVideoSendStream::UpdateSendState() {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
if (sending_) {
|
||||
@ -2394,6 +2428,14 @@ bool WebRtcVideoChannel::WebRtcVideoReceiveStream::IsDefaultStream() const {
|
||||
return default_stream_;
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFrameDecryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor) {
|
||||
config_.frame_decryptor = frame_decryptor;
|
||||
if (stream_) {
|
||||
RecreateWebRtcVideoStream();
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetSink(
|
||||
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
|
||||
rtc::CritScope crit(&sink_lock_);
|
||||
|
@ -159,6 +159,20 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||
void SetInterface(NetworkInterface* iface,
|
||||
webrtc::MediaTransportInterface* media_transport) override;
|
||||
|
||||
// E2E Encrypted Video Frame API
|
||||
// Set a frame decryptor to a particular ssrc that will intercept all
|
||||
// incoming video frames and attempt to decrypt them before forwarding the
|
||||
// result.
|
||||
void SetFrameDecryptor(uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface>
|
||||
frame_decryptor) override;
|
||||
// Set a frame encryptor to a particular ssrc that will intercept all
|
||||
// outgoing video frames and attempt to encrypt them and forward the result
|
||||
// to the packetizer.
|
||||
void SetFrameEncryptor(uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface>
|
||||
frame_encryptor) override;
|
||||
|
||||
// Implemented for VideoMediaChannelTest.
|
||||
bool sending() const { return sending_; }
|
||||
|
||||
@ -261,6 +275,9 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters);
|
||||
webrtc::RtpParameters GetRtpParameters() const;
|
||||
|
||||
void SetFrameEncryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor);
|
||||
|
||||
// Implements rtc::VideoSourceInterface<webrtc::VideoFrame>.
|
||||
// WebRtcVideoSendStream acts as a source to the webrtc::VideoSendStream
|
||||
// in |stream_|. This is done to proxy VideoSinkWants from the encoder to
|
||||
@ -375,6 +392,9 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||
void OnFrame(const webrtc::VideoFrame& frame) override;
|
||||
bool IsDefaultStream() const;
|
||||
|
||||
void SetFrameDecryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor);
|
||||
|
||||
void SetSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink);
|
||||
|
||||
VideoReceiverInfo GetVideoReceiverInfo(bool log_stats);
|
||||
@ -488,6 +508,9 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
|
||||
// before the unsignaled receive stream is created when the first packet is
|
||||
// received.
|
||||
StreamParams unsignaled_stream_params_;
|
||||
// Per peer connection crypto options that last for the lifetime of the peer
|
||||
// connection.
|
||||
const webrtc::CryptoOptions crypto_options_;
|
||||
};
|
||||
|
||||
class EncoderStreamFactory
|
||||
|
@ -28,6 +28,7 @@
|
||||
namespace webrtc {
|
||||
|
||||
// Forward declarations.
|
||||
class FrameEncryptorInterface;
|
||||
class OverheadObserver;
|
||||
class RateLimiter;
|
||||
class ReceiveStatisticsProvider;
|
||||
@ -97,6 +98,11 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
|
||||
// Update network2 instead of pacer_exit field of video timing extension.
|
||||
bool populate_network2_timestamp = false;
|
||||
|
||||
// E2EE Custom Video Frame Encryption
|
||||
FrameEncryptorInterface* frame_encryptor = nullptr;
|
||||
// Require all outgoing frames to be encrypted with a FrameEncryptor.
|
||||
bool require_frame_encryption = false;
|
||||
|
||||
private:
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);
|
||||
};
|
||||
|
@ -99,7 +99,8 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
||||
configuration.send_packet_observer,
|
||||
configuration.retransmission_rate_limiter,
|
||||
configuration.overhead_observer,
|
||||
configuration.populate_network2_timestamp));
|
||||
configuration.populate_network2_timestamp,
|
||||
configuration.frame_encryptor, configuration.require_frame_encryption));
|
||||
// Make sure rtcp sender use same timestamp offset as rtp sender.
|
||||
rtcp_sender_.SetTimestampOffset(rtp_sender_->TimestampOffset());
|
||||
|
||||
|
@ -119,14 +119,21 @@ RTPSender::RTPSender(
|
||||
SendPacketObserver* send_packet_observer,
|
||||
RateLimiter* retransmission_rate_limiter,
|
||||
OverheadObserver* overhead_observer,
|
||||
bool populate_network2_timestamp)
|
||||
bool populate_network2_timestamp,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
bool require_frame_encryption)
|
||||
: clock_(clock),
|
||||
// TODO(holmer): Remove this conversion?
|
||||
clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
|
||||
random_(clock_->TimeInMicroseconds()),
|
||||
audio_configured_(audio),
|
||||
audio_(audio ? new RTPSenderAudio(clock, this) : nullptr),
|
||||
video_(audio ? nullptr : new RTPSenderVideo(clock, this, flexfec_sender)),
|
||||
video_(audio ? nullptr
|
||||
: new RTPSenderVideo(clock,
|
||||
this,
|
||||
flexfec_sender,
|
||||
frame_encryptor,
|
||||
require_frame_encryption)),
|
||||
paced_sender_(paced_sender),
|
||||
transport_sequence_number_allocator_(sequence_number_allocator),
|
||||
transport_feedback_observer_(transport_feedback_observer),
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
class OverheadObserver;
|
||||
class RateLimiter;
|
||||
class RtcEventLog;
|
||||
@ -62,7 +63,9 @@ class RTPSender {
|
||||
SendPacketObserver* send_packet_observer,
|
||||
RateLimiter* nack_rate_limiter,
|
||||
OverheadObserver* overhead_observer,
|
||||
bool populate_network2_timestamp);
|
||||
bool populate_network2_timestamp,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
bool require_frame_encryption);
|
||||
|
||||
~RTPSender();
|
||||
|
||||
|
@ -184,7 +184,8 @@ class RtpSenderTest : public ::testing::TestWithParam<bool> {
|
||||
false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
|
||||
nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, populate_network2));
|
||||
&retransmission_rate_limiter_, nullptr, populate_network2, nullptr,
|
||||
false));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetTimestampOffset(0);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
@ -276,7 +277,7 @@ class TestRtpSenderVideo : public RTPSenderVideo {
|
||||
TestRtpSenderVideo(Clock* clock,
|
||||
RTPSender* rtp_sender,
|
||||
FlexfecSender* flexfec_sender)
|
||||
: RTPSenderVideo(clock, rtp_sender, flexfec_sender) {}
|
||||
: RTPSenderVideo(clock, rtp_sender, flexfec_sender, nullptr, false) {}
|
||||
~TestRtpSenderVideo() override {}
|
||||
|
||||
StorageType GetStorageType(const RTPVideoHeader& header,
|
||||
@ -382,7 +383,7 @@ TEST_P(RtpSenderTest, AssignSequenceNumberAllowsPaddingOnAudio) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
kEnableAudio, &fake_clock_, &transport, &mock_paced_sender_, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
|
||||
nullptr, &retransmission_rate_limiter_, nullptr, false));
|
||||
nullptr, &retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetTimestampOffset(0);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
@ -428,7 +429,8 @@ TEST_P(RtpSenderTestWithoutPacer,
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
|
||||
&feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
|
||||
nullptr, &retransmission_rate_limiter_, &mock_overhead_observer, false));
|
||||
nullptr, &retransmission_rate_limiter_, &mock_overhead_observer, false,
|
||||
nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionTransportSequenceNumber,
|
||||
@ -455,7 +457,8 @@ TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
|
||||
&feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
|
||||
&send_packet_observer_, &retransmission_rate_limiter_, nullptr, false));
|
||||
&send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
|
||||
nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
kRtpExtensionTransportSequenceNumber,
|
||||
@ -486,7 +489,8 @@ TEST_P(RtpSenderTestWithoutPacer, PacketOptionsNoRetransmission) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
|
||||
&feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
|
||||
&send_packet_observer_, &retransmission_rate_limiter_, nullptr, false));
|
||||
&send_packet_observer_, &retransmission_rate_limiter_, nullptr, false,
|
||||
nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
SendGenericPayload();
|
||||
@ -537,10 +541,10 @@ TEST_P(RtpSenderTestWithoutPacer, DoesnSetIncludedInAllocationByDefault) {
|
||||
|
||||
TEST_P(RtpSenderTestWithoutPacer, OnSendSideDelayUpdated) {
|
||||
testing::StrictMock<MockSendSideDelayObserver> send_side_delay_observer_;
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, &send_side_delay_observer_,
|
||||
&mock_rtc_event_log_, nullptr, nullptr, nullptr, false));
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &send_side_delay_observer_, &mock_rtc_event_log_,
|
||||
nullptr, nullptr, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
const uint8_t kPayloadType = 127;
|
||||
@ -618,7 +622,7 @@ TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
|
||||
&seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
@ -978,7 +982,7 @@ TEST_P(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
|
||||
nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_,
|
||||
nullptr, false));
|
||||
nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
|
||||
@ -1004,7 +1008,7 @@ TEST_P(RtpSenderTest, SendRedundantPayloads) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
|
||||
@ -1128,7 +1132,7 @@ TEST_P(RtpSenderTest, SendFlexfecPackets) {
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
|
||||
&seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kMediaSsrc);
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
@ -1188,7 +1192,7 @@ TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
|
||||
&seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kMediaSsrc);
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetStorePacketsStatus(true, 10);
|
||||
@ -1283,11 +1287,11 @@ TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
|
||||
nullptr /* rtp_state */, &fake_clock_);
|
||||
|
||||
// Reset |rtp_sender_| to use FlexFEC.
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport_, nullptr, &flexfec_sender,
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, &flexfec_sender,
|
||||
&seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kMediaSsrc);
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
|
||||
@ -1351,7 +1355,7 @@ TEST_P(RtpSenderTest, FecOverheadRate) {
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
|
||||
&seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
|
||||
&mock_rtc_event_log_, &send_packet_observer_,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kMediaSsrc);
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
|
||||
@ -1403,7 +1407,7 @@ TEST_P(RtpSenderTest, FrameCountCallbacks) {
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr,
|
||||
nullptr, nullptr, &callback, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
|
||||
const uint8_t payload_type = 127;
|
||||
@ -1463,10 +1467,10 @@ TEST_P(RtpSenderTest, BitrateCallbacks) {
|
||||
uint32_t total_bitrate_;
|
||||
uint32_t retransmit_bitrate_;
|
||||
} callback;
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
|
||||
nullptr, &callback, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false));
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
|
||||
&callback, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
// Simulate kNumPackets sent with kPacketInterval ms intervals, with the
|
||||
@ -1523,10 +1527,10 @@ class RtpSenderAudioTest : public RtpSenderTest {
|
||||
|
||||
void SetUp() override {
|
||||
payload_ = kAudioPayload;
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(true, &fake_clock_, &transport_, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, &retransmission_rate_limiter_, nullptr, false));
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
true, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
}
|
||||
@ -2189,10 +2193,11 @@ TEST_P(RtpSenderVideoTest,
|
||||
|
||||
TEST_P(RtpSenderTest, OnOverheadChanged) {
|
||||
MockOverheadObserver mock_overhead_observer;
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, &mock_overhead_observer, false));
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, &mock_overhead_observer,
|
||||
false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
// RTP overhead is 12B.
|
||||
@ -2210,10 +2215,11 @@ TEST_P(RtpSenderTest, OnOverheadChanged) {
|
||||
|
||||
TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
|
||||
MockOverheadObserver mock_overhead_observer;
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, &mock_overhead_observer, false));
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
&retransmission_rate_limiter_, &mock_overhead_observer,
|
||||
false, nullptr, false));
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
||||
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
|
||||
@ -2223,10 +2229,10 @@ TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
|
||||
|
||||
TEST_P(RtpSenderTest, SendsKeepAlive) {
|
||||
MockTransport transport;
|
||||
rtp_sender_.reset(
|
||||
new RTPSender(false, &fake_clock_, &transport, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
|
||||
nullptr, &retransmission_rate_limiter_, nullptr, false));
|
||||
rtp_sender_.reset(new RTPSender(
|
||||
false, &fake_clock_, &transport, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
|
||||
&retransmission_rate_limiter_, nullptr, false, nullptr, false));
|
||||
rtp_sender_->SetSequenceNumber(kSeqNum);
|
||||
rtp_sender_->SetTimestampOffset(0);
|
||||
rtp_sender_->SetSSRC(kSsrc);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||
#include "modules/rtp_rtcp/source/byte_io.h"
|
||||
#include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
|
||||
@ -120,7 +121,9 @@ bool MinimizeDescriptor(const RTPVideoHeader& full, RTPVideoHeader* minimized) {
|
||||
|
||||
RTPSenderVideo::RTPSenderVideo(Clock* clock,
|
||||
RTPSender* rtp_sender,
|
||||
FlexfecSender* flexfec_sender)
|
||||
FlexfecSender* flexfec_sender,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
bool require_frame_encryption)
|
||||
: rtp_sender_(rtp_sender),
|
||||
clock_(clock),
|
||||
video_type_(kVideoCodecGeneric),
|
||||
@ -133,7 +136,9 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock,
|
||||
delta_fec_params_{0, 1, kFecMaskRandom},
|
||||
key_fec_params_{0, 1, kFecMaskRandom},
|
||||
fec_bitrate_(1000, RateStatistics::kBpsScale),
|
||||
video_bitrate_(1000, RateStatistics::kBpsScale) {}
|
||||
video_bitrate_(1000, RateStatistics::kBpsScale),
|
||||
frame_encryptor_(frame_encryptor),
|
||||
require_frame_encryption_(require_frame_encryption) {}
|
||||
|
||||
RTPSenderVideo::~RTPSenderVideo() {}
|
||||
|
||||
@ -433,10 +438,43 @@ bool RTPSenderVideo::SendVideo(enum VideoCodecType video_type,
|
||||
|
||||
RTPVideoHeader minimized_video_header;
|
||||
const RTPVideoHeader* packetize_video_header = video_header;
|
||||
if (first_packet->HasExtension<RtpGenericFrameDescriptorExtension>() &&
|
||||
MinimizeDescriptor(*video_header, &minimized_video_header)) {
|
||||
rtc::ArrayView<const uint8_t> generic_descriptor_raw =
|
||||
first_packet->GetRawExtension<RtpGenericFrameDescriptorExtension>();
|
||||
if (!generic_descriptor_raw.empty()) {
|
||||
if (MinimizeDescriptor(*video_header, &minimized_video_header)) {
|
||||
packetize_video_header = &minimized_video_header;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(benwright@webrtc.org) - Allocate enough to always encrypt inline.
|
||||
rtc::Buffer encrypted_video_payload;
|
||||
if (frame_encryptor_ != nullptr) {
|
||||
if (generic_descriptor_raw.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t max_ciphertext_size =
|
||||
frame_encryptor_->GetMaxCiphertextByteSize(cricket::MEDIA_TYPE_VIDEO,
|
||||
payload_size);
|
||||
encrypted_video_payload.SetSize(max_ciphertext_size);
|
||||
|
||||
size_t bytes_written = 0;
|
||||
if (frame_encryptor_->Encrypt(
|
||||
cricket::MEDIA_TYPE_VIDEO, first_packet->Ssrc(),
|
||||
/*additional_data=*/nullptr,
|
||||
rtc::MakeArrayView(payload_data, payload_size),
|
||||
encrypted_video_payload, &bytes_written) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
encrypted_video_payload.SetSize(bytes_written);
|
||||
payload_data = encrypted_video_payload.data();
|
||||
payload_size = encrypted_video_payload.size();
|
||||
} else if (require_frame_encryption_) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "No FrameEncryptor is attached to this video sending stream but "
|
||||
<< "one is required since require_frame_encryptor is set";
|
||||
}
|
||||
|
||||
std::unique_ptr<RtpPacketizer> packetizer = RtpPacketizer::Create(
|
||||
video_type, rtc::MakeArrayView(payload_data, payload_size), limits,
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
class RtpPacketizer;
|
||||
class RtpPacketToSend;
|
||||
|
||||
@ -38,7 +40,9 @@ class RTPSenderVideo {
|
||||
|
||||
RTPSenderVideo(Clock* clock,
|
||||
RTPSender* rtpSender,
|
||||
FlexfecSender* flexfec_sender);
|
||||
FlexfecSender* flexfec_sender,
|
||||
FrameEncryptorInterface* frame_encryptor,
|
||||
bool require_frame_encryption);
|
||||
virtual ~RTPSenderVideo();
|
||||
|
||||
virtual enum VideoCodecType VideoCodecType() const;
|
||||
@ -158,6 +162,13 @@ class RTPSenderVideo {
|
||||
RTC_GUARDED_BY(stats_crit_);
|
||||
|
||||
OneTimeEvent first_frame_sent_;
|
||||
|
||||
// E2EE Custom Video Frame Encryptor (optional)
|
||||
FrameEncryptorInterface* const frame_encryptor_ = nullptr;
|
||||
// If set to true will require all outgoing frames to pass through an
|
||||
// initialized frame_encryptor_ before being sent out of the network.
|
||||
// Otherwise these payloads will be dropped.
|
||||
bool require_frame_encryption_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -60,11 +60,21 @@ class VCMEncodedFrame : protected EncodedImage {
|
||||
* Get pointer to frame buffer
|
||||
*/
|
||||
const uint8_t* Buffer() const { return _buffer; }
|
||||
/**
|
||||
* Get pointer to frame buffer that can be mutated.
|
||||
*/
|
||||
uint8_t* MutableBuffer() { return _buffer; }
|
||||
/**
|
||||
* Get frame length
|
||||
*/
|
||||
size_t Length() const { return _length; }
|
||||
|
||||
/**
|
||||
* Set frame length
|
||||
*/
|
||||
void SetLength(size_t length) {
|
||||
RTC_DCHECK(length <= _size);
|
||||
_length = length;
|
||||
}
|
||||
/**
|
||||
* Frame RTP timestamp (90kHz)
|
||||
*/
|
||||
|
@ -95,7 +95,8 @@ RtpVideoStreamReceiver::RtpVideoStreamReceiver(
|
||||
ProcessThread* process_thread,
|
||||
NackSender* nack_sender,
|
||||
KeyFrameRequestSender* keyframe_request_sender,
|
||||
video_coding::OnCompleteFrameCallback* complete_frame_callback)
|
||||
video_coding::OnCompleteFrameCallback* complete_frame_callback,
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor)
|
||||
: clock_(Clock::GetRealTimeClock()),
|
||||
config_(*config),
|
||||
packet_router_(packet_router),
|
||||
@ -113,7 +114,8 @@ RtpVideoStreamReceiver::RtpVideoStreamReceiver(
|
||||
packet_router)),
|
||||
complete_frame_callback_(complete_frame_callback),
|
||||
keyframe_request_sender_(keyframe_request_sender),
|
||||
has_received_frame_(false) {
|
||||
has_received_frame_(false),
|
||||
frame_decryptor_(frame_decryptor) {
|
||||
constexpr bool remb_candidate = true;
|
||||
packet_router_->AddReceiveRtpModule(rtp_rtcp_.get(), remb_candidate);
|
||||
rtp_receive_statistics_->RegisterRtpStatisticsCallback(receive_stats_proxy);
|
||||
@ -363,6 +365,45 @@ int32_t RtpVideoStreamReceiver::ResendPackets(const uint16_t* sequence_numbers,
|
||||
|
||||
void RtpVideoStreamReceiver::OnReceivedFrame(
|
||||
std::unique_ptr<video_coding::RtpFrameObject> frame) {
|
||||
// Optionally attempt to decrypt the raw video frame if it was provided.
|
||||
if (frame_decryptor_ != nullptr) {
|
||||
// When using encryption we expect the frame to have the generic descriptor.
|
||||
absl::optional<RtpGenericFrameDescriptor> descriptor =
|
||||
frame->GetGenericFrameDescriptor();
|
||||
if (!descriptor) {
|
||||
RTC_LOG(LS_ERROR) << "No generic frame descriptor found dropping frame.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the bitstream of the encrypted video frame.
|
||||
rtc::ArrayView<const uint8_t> encrypted_frame_bitstream(frame->Buffer(),
|
||||
frame->size());
|
||||
// Retrieve the maximum possible size of the decrypted payload.
|
||||
const size_t max_plaintext_byte_size =
|
||||
frame_decryptor_->GetMaxPlaintextByteSize(cricket::MEDIA_TYPE_VIDEO,
|
||||
frame->size());
|
||||
RTC_CHECK(max_plaintext_byte_size <= frame->size());
|
||||
// Place the decrypted frame inline into the existing frame.
|
||||
rtc::ArrayView<uint8_t> inline_decrypted_bitstream(frame->MutableBuffer(),
|
||||
max_plaintext_byte_size);
|
||||
|
||||
// Attempt to decrypt the video frame.
|
||||
size_t bytes_written = 0;
|
||||
if (frame_decryptor_->Decrypt(
|
||||
cricket::MEDIA_TYPE_VIDEO, /*csrcs=*/{},
|
||||
/*additional_data=*/nullptr, encrypted_frame_bitstream,
|
||||
inline_decrypted_bitstream, &bytes_written) != 0) {
|
||||
return;
|
||||
}
|
||||
RTC_CHECK(bytes_written <= max_plaintext_byte_size);
|
||||
// Update the frame to contain just the written bytes.
|
||||
frame->SetLength(bytes_written);
|
||||
} else if (config_.crypto_options.sframe.require_frame_encryption) {
|
||||
RTC_LOG(LS_WARNING) << "Frame decryption required but not attached to this "
|
||||
"stream. Dropping frame.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!has_received_frame_) {
|
||||
has_received_frame_ = true;
|
||||
if (frame->FrameType() != kVideoFrameKey)
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
#include "api/crypto/framedecryptorinterface.h"
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
#include "call/rtp_packet_sink_interface.h"
|
||||
#include "call/syncable.h"
|
||||
@ -67,7 +68,8 @@ class RtpVideoStreamReceiver : public RecoveredPacketReceiver,
|
||||
ProcessThread* process_thread,
|
||||
NackSender* nack_sender,
|
||||
KeyFrameRequestSender* keyframe_request_sender,
|
||||
video_coding::OnCompleteFrameCallback* complete_frame_callback);
|
||||
video_coding::OnCompleteFrameCallback* complete_frame_callback,
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor);
|
||||
~RtpVideoStreamReceiver() override;
|
||||
|
||||
void AddReceiveCodec(const VideoCodec& video_codec,
|
||||
@ -203,6 +205,9 @@ class RtpVideoStreamReceiver : public RecoveredPacketReceiver,
|
||||
RTC_GUARDED_BY(rtp_sources_lock_);
|
||||
absl::optional<int64_t> last_received_rtp_system_time_ms_
|
||||
RTC_GUARDED_BY(rtp_sources_lock_);
|
||||
|
||||
// E2EE Video Frame Decryptor (Optional)
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -133,7 +133,7 @@ class RtpVideoStreamReceiverTest : public testing::Test {
|
||||
&mock_transport_, nullptr, &packet_router_, &config_,
|
||||
rtp_receive_statistics_.get(), nullptr, process_thread_.get(),
|
||||
&mock_nack_sender_, &mock_key_frame_request_sender_,
|
||||
&mock_on_complete_frame_callback_);
|
||||
&mock_on_complete_frame_callback_, nullptr);
|
||||
}
|
||||
|
||||
WebRtcRTPHeader GetDefaultPacket() {
|
||||
|
@ -141,7 +141,8 @@ VideoReceiveStream::VideoReceiveStream(
|
||||
process_thread_,
|
||||
this, // NackSender
|
||||
this, // KeyFrameRequestSender
|
||||
this), // OnCompleteFrameCallback
|
||||
this, // OnCompleteFrameCallback
|
||||
config_.frame_decryptor),
|
||||
rtp_stream_sync_(this) {
|
||||
RTC_LOG(LS_INFO) << "VideoReceiveStream: " << config_.ToString();
|
||||
|
||||
|
@ -111,6 +111,14 @@ int CalculateMaxPadBitrateBps(const std::vector<VideoStream>& streams,
|
||||
return pad_up_to_bitrate_bps;
|
||||
}
|
||||
|
||||
RtpSenderFrameEncryptionConfig CreateFrameEncryptionConfig(
|
||||
const VideoSendStream::Config* config) {
|
||||
RtpSenderFrameEncryptionConfig frame_encryption_config;
|
||||
frame_encryption_config.frame_encryptor = config->frame_encryptor;
|
||||
frame_encryption_config.crypto_options = config->crypto_options;
|
||||
return frame_encryption_config;
|
||||
}
|
||||
|
||||
RtpSenderObservers CreateObservers(CallStats* call_stats,
|
||||
EncoderRtcpFeedback* encoder_feedback,
|
||||
SendStatisticsProxy* stats_proxy,
|
||||
@ -238,8 +246,8 @@ VideoSendStreamImpl::VideoSendStreamImpl(
|
||||
config_->rtp.ssrcs,
|
||||
video_stream_encoder),
|
||||
bandwidth_observer_(transport->GetBandwidthObserver()),
|
||||
rtp_video_sender_(
|
||||
transport_->CreateRtpVideoSender(config_->rtp.ssrcs,
|
||||
rtp_video_sender_(transport_->CreateRtpVideoSender(
|
||||
config_->rtp.ssrcs,
|
||||
suspended_ssrcs,
|
||||
suspended_payload_states,
|
||||
config_->rtp,
|
||||
@ -250,7 +258,8 @@ VideoSendStreamImpl::VideoSendStreamImpl(
|
||||
stats_proxy_,
|
||||
send_delay_stats),
|
||||
event_log,
|
||||
std::move(fec_controller))),
|
||||
std::move(fec_controller),
|
||||
CreateFrameEncryptionConfig(config_))),
|
||||
weak_ptr_factory_(this) {
|
||||
RTC_DCHECK_RUN_ON(worker_queue_);
|
||||
RTC_LOG(LS_INFO) << "VideoSendStreamInternal: " << config_->ToString();
|
||||
|
@ -91,7 +91,7 @@ class VideoSendStreamImplTest : public ::testing::Test {
|
||||
EXPECT_CALL(transport_controller_, packet_router())
|
||||
.WillRepeatedly(Return(&packet_router_));
|
||||
EXPECT_CALL(transport_controller_,
|
||||
CreateRtpVideoSender(_, _, _, _, _, _, _, _, _))
|
||||
CreateRtpVideoSender(_, _, _, _, _, _, _, _, _, _))
|
||||
.WillRepeatedly(Return(&rtp_video_sender_));
|
||||
EXPECT_CALL(rtp_video_sender_, SetActive(_))
|
||||
.WillRepeatedly(testing::Invoke(
|
||||
|
Reference in New Issue
Block a user