Enable End-to-End Encrypted Audio Payloads.
This change integrates the FrameDecryptorInterface and the FrameEncryptorInterface into the audio media path. If a FrameEncryptorInterface is set on an outgoing audio RTPSender then each outgoing audio payload will first pass through the provided FrameEncryptor which will have a chance to modify the payload contents for the purposes of encryption. If a FrameDecryptorInterface is set on an incoming audio RtpReceiver then each incoming audio payload will first pass through the provided FrameDecryptor which have a chance to modify the payload contents for the purpose of decryption. While AEAD is supported by the FrameDecryptor/FrameEncryptor interfaces this CL does not use it and so it is left as null. Bug: webrtc:9681 Change-Id: Ic383a9dce280528739f9d271357c2220e0a0dccf Reviewed-on: https://webrtc-review.googlesource.com/c/101702 Commit-Queue: Benjamin Wright <benwright@webrtc.org> Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org> Reviewed-by: Steve Anton <steveanton@webrtc.org> Reviewed-by: Emad Omara <emadomara@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25001}
This commit is contained in:

committed by
Commit Bot

parent
aa43b7bb2f
commit
84583f6183
17
api/BUILD.gn
17
api/BUILD.gn
@ -446,6 +446,23 @@ if (rtc_include_tests) {
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("fake_frame_crypto") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"test/fake_frame_decryptor.cc",
|
||||
"test/fake_frame_decryptor.h",
|
||||
"test/fake_frame_encryptor.cc",
|
||||
"test/fake_frame_encryptor.h",
|
||||
]
|
||||
deps = [
|
||||
":array_view",
|
||||
":libjingle_peerconnection_api",
|
||||
"..:webrtc_common",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("mock_peerconnectioninterface") {
|
||||
testonly = true
|
||||
sources = [
|
||||
|
69
api/test/fake_frame_decryptor.cc
Normal file
69
api/test/fake_frame_decryptor.cc
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 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 "api/test/fake_frame_decryptor.h"
|
||||
#include <vector>
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FakeFrameDecryptor::FakeFrameDecryptor(uint8_t fake_key,
|
||||
uint8_t expected_postfix_byte)
|
||||
: fake_key_(fake_key), expected_postfix_byte_(expected_postfix_byte) {}
|
||||
|
||||
int FakeFrameDecryptor::Decrypt(cricket::MediaType media_type,
|
||||
const std::vector<uint32_t>& csrcs,
|
||||
rtc::ArrayView<const uint8_t> additional_data,
|
||||
rtc::ArrayView<const uint8_t> encrypted_frame,
|
||||
rtc::ArrayView<uint8_t> frame,
|
||||
size_t* bytes_written) {
|
||||
if (fail_decryption_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
RTC_CHECK_EQ(frame.size() + 1, encrypted_frame.size());
|
||||
for (size_t i = 0; i < frame.size(); i++) {
|
||||
frame[i] ^= fake_key_;
|
||||
}
|
||||
|
||||
if (encrypted_frame[frame.size()] != expected_postfix_byte_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t FakeFrameDecryptor::GetMaxPlaintextByteSize(
|
||||
cricket::MediaType media_type,
|
||||
size_t encrypted_frame_size) {
|
||||
return encrypted_frame_size - 1;
|
||||
}
|
||||
|
||||
void FakeFrameDecryptor::SetFakeKey(uint8_t fake_key) {
|
||||
fake_key_ = fake_key;
|
||||
}
|
||||
|
||||
uint8_t FakeFrameDecryptor::GetFakeKey() const {
|
||||
return fake_key_;
|
||||
}
|
||||
|
||||
void FakeFrameDecryptor::SetExpectedPostfixByte(uint8_t expected_postfix_byte) {
|
||||
expected_postfix_byte_ = expected_postfix_byte;
|
||||
}
|
||||
|
||||
uint8_t FakeFrameDecryptor::GetExpectedPostfixByte() const {
|
||||
return expected_postfix_byte_;
|
||||
}
|
||||
|
||||
void FakeFrameDecryptor::SetFailDecryption(bool fail_decryption) {
|
||||
fail_decryption_ = fail_decryption;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
62
api/test/fake_frame_decryptor.h
Normal file
62
api/test/fake_frame_decryptor.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef API_TEST_FAKE_FRAME_DECRYPTOR_H_
|
||||
#define API_TEST_FAKE_FRAME_DECRYPTOR_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "api/crypto/framedecryptorinterface.h"
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// The FakeFrameDecryptor is a TEST ONLY fake implementation of the
|
||||
// FrameDecryptorInterface. It is constructed with a simple single digit key and
|
||||
// a fixed postfix byte. This is just to validate that the core code works
|
||||
// as expected.
|
||||
class FakeFrameDecryptor
|
||||
: public rtc::RefCountedObject<FrameDecryptorInterface> {
|
||||
public:
|
||||
// Provide a key (0,255) and some postfix byte (0,255) this should match the
|
||||
// byte you expect from the FakeFrameEncryptor.
|
||||
explicit FakeFrameDecryptor(uint8_t fake_key = 1,
|
||||
uint8_t expected_postfix_byte = 255);
|
||||
|
||||
// FrameDecryptorInterface implementation
|
||||
int Decrypt(cricket::MediaType media_type,
|
||||
const std::vector<uint32_t>& csrcs,
|
||||
rtc::ArrayView<const uint8_t> additional_data,
|
||||
rtc::ArrayView<const uint8_t> encrypted_frame,
|
||||
rtc::ArrayView<uint8_t> frame,
|
||||
size_t* bytes_written) override;
|
||||
|
||||
size_t GetMaxPlaintextByteSize(cricket::MediaType media_type,
|
||||
size_t encrypted_frame_size) override;
|
||||
|
||||
void SetFakeKey(uint8_t fake_key);
|
||||
|
||||
uint8_t GetFakeKey() const;
|
||||
|
||||
void SetExpectedPostfixByte(uint8_t expected_postfix_byte);
|
||||
|
||||
uint8_t GetExpectedPostfixByte() const;
|
||||
|
||||
void SetFailDecryption(bool fail_decryption);
|
||||
|
||||
private:
|
||||
uint8_t fake_key_ = 0;
|
||||
uint8_t expected_postfix_byte_ = 0;
|
||||
bool fail_decryption_ = false;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_TEST_FAKE_FRAME_DECRYPTOR_H_
|
65
api/test/fake_frame_encryptor.cc
Normal file
65
api/test/fake_frame_encryptor.cc
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 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 "api/test/fake_frame_encryptor.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
FakeFrameEncryptor::FakeFrameEncryptor(uint8_t fake_key, uint8_t postfix_byte)
|
||||
: fake_key_(fake_key), postfix_byte_(postfix_byte) {}
|
||||
|
||||
// FrameEncryptorInterface implementation
|
||||
int FakeFrameEncryptor::Encrypt(cricket::MediaType media_type,
|
||||
uint32_t ssrc,
|
||||
rtc::ArrayView<const uint8_t> additional_data,
|
||||
rtc::ArrayView<const uint8_t> frame,
|
||||
rtc::ArrayView<uint8_t> encrypted_frame,
|
||||
size_t* bytes_written) {
|
||||
// Useful if you want to test failure cases.
|
||||
if (fail_encryption_) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
RTC_CHECK_EQ(frame.size() + 1, encrypted_frame.size());
|
||||
for (size_t i = 0; i < frame.size(); i++) {
|
||||
encrypted_frame[i] ^= fake_key_;
|
||||
}
|
||||
encrypted_frame[frame.size()] = postfix_byte_;
|
||||
*bytes_written = encrypted_frame.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t FakeFrameEncryptor::GetMaxCiphertextByteSize(
|
||||
cricket::MediaType media_type,
|
||||
size_t frame_size) {
|
||||
return frame_size + 1;
|
||||
}
|
||||
|
||||
void FakeFrameEncryptor::SetFakeKey(uint8_t fake_key) {
|
||||
fake_key_ = fake_key;
|
||||
}
|
||||
|
||||
uint8_t FakeFrameEncryptor::GetFakeKey() const {
|
||||
return fake_key_;
|
||||
}
|
||||
|
||||
void FakeFrameEncryptor::SetPostfixByte(uint8_t postfix_byte) {
|
||||
postfix_byte_ = postfix_byte;
|
||||
}
|
||||
|
||||
uint8_t FakeFrameEncryptor::GetPostfixByte() const {
|
||||
return postfix_byte_;
|
||||
}
|
||||
|
||||
void FakeFrameEncryptor::SetFailEncryption(bool fail_encryption) {
|
||||
fail_encryption_ = fail_encryption;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
58
api/test/fake_frame_encryptor.h
Normal file
58
api/test/fake_frame_encryptor.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
#ifndef API_TEST_FAKE_FRAME_ENCRYPTOR_H_
|
||||
#define API_TEST_FAKE_FRAME_ENCRYPTOR_H_
|
||||
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// The FakeFrameEncryptor is a TEST ONLY fake implementation of the
|
||||
// FrameEncryptorInterface. It is constructed with a simple single digit key and
|
||||
// a fixed postfix byte. This is just to validate that the core code works
|
||||
// as expected.
|
||||
class FakeFrameEncryptor
|
||||
: public rtc::RefCountedObject<FrameEncryptorInterface> {
|
||||
public:
|
||||
// Provide a key (0,255) and some postfix byte (0,255).
|
||||
explicit FakeFrameEncryptor(uint8_t fake_key = 1, uint8_t postfix_byte = 255);
|
||||
|
||||
// FrameEncryptorInterface implementation
|
||||
int Encrypt(cricket::MediaType media_type,
|
||||
uint32_t ssrc,
|
||||
rtc::ArrayView<const uint8_t> additional_data,
|
||||
rtc::ArrayView<const uint8_t> frame,
|
||||
rtc::ArrayView<uint8_t> encrypted_frame,
|
||||
size_t* bytes_written) override;
|
||||
|
||||
size_t GetMaxCiphertextByteSize(cricket::MediaType media_type,
|
||||
size_t frame_size) override;
|
||||
|
||||
void SetFakeKey(uint8_t fake_key);
|
||||
|
||||
uint8_t GetFakeKey() const;
|
||||
|
||||
void SetPostfixByte(uint8_t expected_postfix_byte);
|
||||
|
||||
uint8_t GetPostfixByte() const;
|
||||
|
||||
void SetFailEncryption(bool fail_encryption);
|
||||
|
||||
private:
|
||||
uint8_t fake_key_ = 0;
|
||||
uint8_t postfix_byte_ = 0;
|
||||
bool fail_encryption_ = false;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // API_TEST_FAKE_FRAME_ENCRYPTOR_H_
|
@ -76,7 +76,7 @@ std::unique_ptr<voe::ChannelReceiveProxy> CreateChannelAndProxy(
|
||||
nullptr /* RtcpRttStats */, event_log, config.rtp.remote_ssrc,
|
||||
config.jitter_buffer_max_packets,
|
||||
config.jitter_buffer_fast_accelerate, config.decoder_factory,
|
||||
config.codec_pair_id));
|
||||
config.codec_pair_id, config.frame_decryptor));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -50,10 +50,12 @@ std::unique_ptr<voe::ChannelSendProxy> CreateChannelAndProxy(
|
||||
rtc::TaskQueue* worker_queue,
|
||||
ProcessThread* module_process_thread,
|
||||
RtcpRttStats* rtcp_rtt_stats,
|
||||
RtcEventLog* event_log) {
|
||||
RtcEventLog* event_log,
|
||||
FrameEncryptorInterface* frame_encryptor) {
|
||||
return absl::make_unique<voe::ChannelSendProxy>(
|
||||
absl::make_unique<voe::ChannelSend>(worker_queue, module_process_thread,
|
||||
rtcp_rtt_stats, event_log));
|
||||
rtcp_rtt_stats, event_log,
|
||||
frame_encryptor));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -103,7 +105,8 @@ AudioSendStream::AudioSendStream(
|
||||
CreateChannelAndProxy(worker_queue,
|
||||
module_process_thread,
|
||||
rtcp_rtt_stats,
|
||||
event_log)) {}
|
||||
event_log,
|
||||
config.frame_encryptor)) {}
|
||||
|
||||
AudioSendStream::AudioSendStream(
|
||||
const webrtc::AudioSendStream::Config& config,
|
||||
@ -227,6 +230,11 @@ void AudioSendStream::ConfigureStream(
|
||||
stream->timed_send_transport_adapter_.get());
|
||||
}
|
||||
|
||||
// Enable the frame encryptor if a new frame encryptor has been provided.
|
||||
if (first_time || new_config.frame_encryptor != old_config.frame_encryptor) {
|
||||
channel_proxy->SetFrameEncryptor(new_config.frame_encryptor);
|
||||
}
|
||||
|
||||
const ExtensionIds old_ids = FindExtensionIds(old_config.rtp.extensions);
|
||||
const ExtensionIds new_ids = FindExtensionIds(new_config.rtp.extensions);
|
||||
// Audio level indication
|
||||
|
@ -196,6 +196,7 @@ struct ConfigHelper {
|
||||
EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kSsrc)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetRTCP_CNAME(StrEq(kCName))).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetNACKStatus(true, 10)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_, SetFrameEncryptor(nullptr)).Times(1);
|
||||
EXPECT_CALL(*channel_proxy_,
|
||||
SetSendAudioLevelIndicationStatus(true, kAudioLevelId))
|
||||
.Times(1);
|
||||
|
@ -229,7 +229,8 @@ ChannelReceive::ChannelReceive(
|
||||
size_t jitter_buffer_max_packets,
|
||||
bool jitter_buffer_fast_playout,
|
||||
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
|
||||
absl::optional<AudioCodecPairId> codec_pair_id)
|
||||
absl::optional<AudioCodecPairId> codec_pair_id,
|
||||
FrameDecryptorInterface* frame_decryptor)
|
||||
: event_log_(rtc_event_log),
|
||||
rtp_receive_statistics_(
|
||||
ReceiveStatistics::Create(Clock::GetRealTimeClock())),
|
||||
@ -245,7 +246,8 @@ ChannelReceive::ChannelReceive(
|
||||
_audioDeviceModulePtr(audio_device_module),
|
||||
_transportPtr(NULL),
|
||||
_outputGain(1.0f),
|
||||
associated_send_channel_(nullptr) {
|
||||
associated_send_channel_(nullptr),
|
||||
frame_decryptor_(frame_decryptor) {
|
||||
RTC_DCHECK(module_process_thread);
|
||||
RTC_DCHECK(audio_device_module);
|
||||
AudioCodingModule::Config acm_config;
|
||||
@ -425,7 +427,38 @@ bool ChannelReceive::ReceivePacket(const uint8_t* packet,
|
||||
WebRtcRTPHeader webrtc_rtp_header = {};
|
||||
webrtc_rtp_header.header = header;
|
||||
|
||||
const size_t payload_data_length = payload_length - header.paddingLength;
|
||||
size_t payload_data_length = payload_length - header.paddingLength;
|
||||
|
||||
// E2EE Custom Audio Frame Decryption (This is optional).
|
||||
// Keep this buffer around for the lifetime of the OnReceivedPayloadData call.
|
||||
rtc::Buffer decrypted_audio_payload;
|
||||
if (frame_decryptor_ != nullptr) {
|
||||
size_t max_plaintext_size = frame_decryptor_->GetMaxPlaintextByteSize(
|
||||
cricket::MEDIA_TYPE_AUDIO, payload_length);
|
||||
decrypted_audio_payload.SetSize(max_plaintext_size);
|
||||
|
||||
size_t bytes_written = 0;
|
||||
std::vector<uint32_t> csrcs(header.arrOfCSRCs,
|
||||
header.arrOfCSRCs + header.numCSRCs);
|
||||
int decrypt_status = frame_decryptor_->Decrypt(
|
||||
cricket::MEDIA_TYPE_AUDIO, csrcs,
|
||||
/*additional_data=*/nullptr,
|
||||
rtc::ArrayView<const uint8_t>(payload, payload_data_length),
|
||||
decrypted_audio_payload, &bytes_written);
|
||||
|
||||
// In this case just interpret the failure as a silent frame.
|
||||
if (decrypt_status != 0) {
|
||||
bytes_written = 0;
|
||||
}
|
||||
|
||||
// Resize the decrypted audio payload to the number of bytes actually
|
||||
// written.
|
||||
decrypted_audio_payload.SetSize(bytes_written);
|
||||
// Update the final payload.
|
||||
payload = decrypted_audio_payload.data();
|
||||
payload_data_length = decrypted_audio_payload.size();
|
||||
}
|
||||
|
||||
if (payload_data_length == 0) {
|
||||
webrtc_rtp_header.frameType = kEmptyFrame;
|
||||
return OnReceivedPayloadData(nullptr, 0, &webrtc_rtp_header);
|
||||
|
@ -42,6 +42,7 @@ class TimestampWrapAroundHandler;
|
||||
namespace webrtc {
|
||||
|
||||
class AudioDeviceModule;
|
||||
class FrameDecryptorInterface;
|
||||
class PacketRouter;
|
||||
class ProcessThread;
|
||||
class RateLimiter;
|
||||
@ -112,7 +113,8 @@ class ChannelReceive : public RtpData, public Transport {
|
||||
size_t jitter_buffer_max_packets,
|
||||
bool jitter_buffer_fast_playout,
|
||||
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
|
||||
absl::optional<AudioCodecPairId> codec_pair_id);
|
||||
absl::optional<AudioCodecPairId> codec_pair_id,
|
||||
FrameDecryptorInterface* frame_decryptor);
|
||||
virtual ~ChannelReceive();
|
||||
|
||||
void SetSink(AudioSinkInterface* sink);
|
||||
@ -263,6 +265,9 @@ class ChannelReceive : public RtpData, public Transport {
|
||||
PacketRouter* packet_router_ = nullptr;
|
||||
|
||||
rtc::ThreadChecker construction_thread_;
|
||||
|
||||
// E2EE Audio Frame Decryption
|
||||
FrameDecryptorInterface* frame_decryptor_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace voe
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "audio/utility/audio_frame_operations.h"
|
||||
#include "call/rtp_transport_controller_send_interface.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
|
||||
@ -260,6 +261,35 @@ int32_t ChannelSend::SendData(FrameType frameType,
|
||||
_rtpRtcpModule->SetAudioLevel(rms_level_.Average());
|
||||
}
|
||||
|
||||
// E2EE Custom Audio Frame Encryption (This is optional).
|
||||
// Keep this buffer around for the lifetime of the send call.
|
||||
rtc::Buffer encrypted_audio_payload;
|
||||
if (frame_encryptor_ != nullptr) {
|
||||
// TODO(benwright@webrtc.org) - Allocate enough to always encrypt inline.
|
||||
// Allocate a buffer to hold the maximum possible encrypted payload.
|
||||
size_t max_ciphertext_size = frame_encryptor_->GetMaxCiphertextByteSize(
|
||||
cricket::MEDIA_TYPE_AUDIO, payloadSize);
|
||||
encrypted_audio_payload.SetSize(max_ciphertext_size);
|
||||
|
||||
// Encrypt the audio payload into the buffer.
|
||||
size_t bytes_written = 0;
|
||||
int encrypt_status = frame_encryptor_->Encrypt(
|
||||
cricket::MEDIA_TYPE_AUDIO, _rtpRtcpModule->SSRC(),
|
||||
/*additional_data=*/nullptr,
|
||||
rtc::ArrayView<const uint8_t>(payloadData, payloadSize),
|
||||
encrypted_audio_payload, &bytes_written);
|
||||
if (encrypt_status != 0) {
|
||||
RTC_DLOG(LS_ERROR) << "Channel::SendData() failed encrypt audio payload: "
|
||||
<< encrypt_status;
|
||||
return -1;
|
||||
}
|
||||
// Resize the buffer to the exact number of bytes actually used.
|
||||
encrypted_audio_payload.SetSize(bytes_written);
|
||||
// Rewrite the payloadData and size to the new encrypted payload.
|
||||
payloadData = encrypted_audio_payload.data();
|
||||
payloadSize = encrypted_audio_payload.size();
|
||||
}
|
||||
|
||||
// Push data from ACM to RTP/RTCP-module to deliver audio frame for
|
||||
// packetization.
|
||||
// This call will trigger Transport::SendPacket() from the RTP/RTCP module.
|
||||
@ -322,7 +352,8 @@ int ChannelSend::PreferredSampleRate() const {
|
||||
ChannelSend::ChannelSend(rtc::TaskQueue* encoder_queue,
|
||||
ProcessThread* module_process_thread,
|
||||
RtcpRttStats* rtcp_rtt_stats,
|
||||
RtcEventLog* rtc_event_log)
|
||||
RtcEventLog* rtc_event_log,
|
||||
FrameEncryptorInterface* frame_encryptor)
|
||||
: event_log_(rtc_event_log),
|
||||
_timeStamp(0), // This is just an offset, RTP module will add it's own
|
||||
// random offset
|
||||
@ -342,7 +373,8 @@ ChannelSend::ChannelSend(rtc::TaskQueue* encoder_queue,
|
||||
kMaxRetransmissionWindowMs)),
|
||||
use_twcc_plr_for_ana_(
|
||||
webrtc::field_trial::FindFullName("UseTwccPlrForAna") == "Enabled"),
|
||||
encoder_queue_(encoder_queue) {
|
||||
encoder_queue_(encoder_queue),
|
||||
frame_encryptor_(frame_encryptor) {
|
||||
RTC_DCHECK(module_process_thread);
|
||||
RTC_DCHECK(encoder_queue);
|
||||
audio_coding_.reset(AudioCodingModule::Create(AudioCodingModule::Config()));
|
||||
@ -949,5 +981,16 @@ int64_t ChannelSend::GetRTT() const {
|
||||
return rtt;
|
||||
}
|
||||
|
||||
void ChannelSend::SetFrameEncryptor(FrameEncryptorInterface* frame_encryptor) {
|
||||
rtc::CritScope cs(&encoder_queue_lock_);
|
||||
if (encoder_queue_is_active_) {
|
||||
encoder_queue_->PostTask([this, frame_encryptor]() {
|
||||
this->frame_encryptor_ = frame_encryptor;
|
||||
});
|
||||
} else {
|
||||
frame_encryptor_ = frame_encryptor;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace voe
|
||||
} // namespace webrtc
|
||||
|
@ -37,6 +37,7 @@ class TimestampWrapAroundHandler;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
class PacketRouter;
|
||||
class ProcessThread;
|
||||
class RateLimiter;
|
||||
@ -118,7 +119,8 @@ class ChannelSend
|
||||
ChannelSend(rtc::TaskQueue* encoder_queue,
|
||||
ProcessThread* module_process_thread,
|
||||
RtcpRttStats* rtcp_rtt_stats,
|
||||
RtcEventLog* rtc_event_log);
|
||||
RtcEventLog* rtc_event_log,
|
||||
FrameEncryptorInterface* frame_encryptor);
|
||||
|
||||
virtual ~ChannelSend();
|
||||
|
||||
@ -222,6 +224,9 @@ class ChannelSend
|
||||
|
||||
int64_t GetRTT() const;
|
||||
|
||||
// E2EE Custom Audio Frame Encryption
|
||||
void SetFrameEncryptor(FrameEncryptorInterface* frame_encryptor);
|
||||
|
||||
private:
|
||||
class ProcessAndEncodeAudioTask;
|
||||
|
||||
@ -290,6 +295,9 @@ class ChannelSend
|
||||
rtc::CriticalSection encoder_queue_lock_;
|
||||
bool encoder_queue_is_active_ RTC_GUARDED_BY(encoder_queue_lock_) = false;
|
||||
rtc::TaskQueue* encoder_queue_ = nullptr;
|
||||
|
||||
// E2EE Audio Frame Encryption
|
||||
FrameEncryptorInterface* frame_encryptor_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace voe
|
||||
|
@ -197,5 +197,11 @@ ChannelSend* ChannelSendProxy::GetChannel() const {
|
||||
return channel_.get();
|
||||
}
|
||||
|
||||
void ChannelSendProxy::SetFrameEncryptor(
|
||||
FrameEncryptorInterface* frame_encryptor) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
channel_->SetFrameEncryptor(frame_encryptor);
|
||||
}
|
||||
|
||||
} // namespace voe
|
||||
} // namespace webrtc
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FrameEncryptorInterface;
|
||||
class RtcpBandwidthObserver;
|
||||
class RtpRtcp;
|
||||
class RtpTransportControllerSendInterface;
|
||||
@ -84,6 +85,9 @@ class ChannelSendProxy {
|
||||
// Needed by ChannelReceiveProxy::AssociateSendChannel.
|
||||
virtual ChannelSend* GetChannel() const;
|
||||
|
||||
// E2EE Custom Audio Frame Encryption (Optional)
|
||||
virtual void SetFrameEncryptor(FrameEncryptorInterface* frame_encryptor);
|
||||
|
||||
private:
|
||||
// Thread checkers document and lock usage of some methods on voe::Channel to
|
||||
// specific threads we know about. The goal is to eventually split up
|
||||
|
@ -105,6 +105,8 @@ class MockChannelSendProxy : public voe::ChannelSendProxy {
|
||||
void(float recoverable_packet_loss_rate));
|
||||
MOCK_METHOD0(StartSend, void());
|
||||
MOCK_METHOD0(StopSend, void());
|
||||
MOCK_METHOD1(SetFrameEncryptor,
|
||||
void(FrameEncryptorInterface* frame_encryptor));
|
||||
};
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
class AudioSinkInterface;
|
||||
class FrameDecryptorInterface;
|
||||
|
||||
class AudioReceiveStream {
|
||||
public:
|
||||
@ -120,6 +121,11 @@ class AudioReceiveStream {
|
||||
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory;
|
||||
|
||||
absl::optional<AudioCodecPairId> codec_pair_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;
|
||||
};
|
||||
|
||||
// Reconfigure the stream according to the Configuration.
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "api/audio_codecs/audio_encoder_factory.h"
|
||||
#include "api/audio_codecs/audio_format.h"
|
||||
#include "api/call/transport.h"
|
||||
#include "api/crypto/frameencryptorinterface.h"
|
||||
#include "api/rtpparameters.h"
|
||||
#include "call/rtp_config.h"
|
||||
#include "modules/audio_processing/include/audio_processing_statistics.h"
|
||||
@ -128,6 +129,11 @@ class AudioSendStream {
|
||||
|
||||
// Track ID as specified during track creation.
|
||||
std::string track_id;
|
||||
|
||||
// An optional custom frame encryptor that allows the entire frame to be
|
||||
// encryptor in whatever way the caller choses. This is not required by
|
||||
// default.
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor;
|
||||
};
|
||||
|
||||
virtual ~AudioSendStream() = default;
|
||||
|
@ -15,6 +15,13 @@ namespace cricket {
|
||||
VideoOptions::VideoOptions() = default;
|
||||
VideoOptions::~VideoOptions() = default;
|
||||
|
||||
MediaChannel::MediaChannel(const MediaConfig& config)
|
||||
: enable_dscp_(config.enable_dscp), network_interface_(NULL) {}
|
||||
|
||||
MediaChannel::MediaChannel() : enable_dscp_(false), network_interface_(NULL) {}
|
||||
|
||||
MediaChannel::~MediaChannel() {}
|
||||
|
||||
void MediaChannel::SetInterface(NetworkInterface* iface) {
|
||||
rtc::CritScope cs(&network_interface_crit_);
|
||||
network_interface_ = iface;
|
||||
@ -30,13 +37,15 @@ rtc::DiffServCodePoint MediaChannel::PreferredDscp() const {
|
||||
}
|
||||
|
||||
void MediaChannel::SetFrameEncryptor(
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor) {
|
||||
frame_encryptor_ = frame_encryptor;
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
|
||||
// Placeholder should be pure virtual once internal supports it.
|
||||
}
|
||||
|
||||
void MediaChannel::SetFrameDecryptor(
|
||||
webrtc::FrameDecryptorInterface* frame_decryptor) {
|
||||
frame_decryptor_ = frame_decryptor;
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor) {
|
||||
// Placeholder should be pure virtual once internal supports it.
|
||||
}
|
||||
|
||||
MediaSenderInfo::MediaSenderInfo() = default;
|
||||
|
@ -179,10 +179,9 @@ class MediaChannel : public sigslot::has_slots<> {
|
||||
virtual ~NetworkInterface() {}
|
||||
};
|
||||
|
||||
explicit MediaChannel(const MediaConfig& config)
|
||||
: enable_dscp_(config.enable_dscp), network_interface_(NULL) {}
|
||||
MediaChannel() : enable_dscp_(false), network_interface_(NULL) {}
|
||||
~MediaChannel() override {}
|
||||
explicit MediaChannel(const MediaConfig& config);
|
||||
MediaChannel();
|
||||
~MediaChannel() override;
|
||||
|
||||
// Sets the abstract interface class for sending RTP/RTCP data.
|
||||
virtual void SetInterface(NetworkInterface* iface);
|
||||
@ -219,13 +218,17 @@ class MediaChannel : public sigslot::has_slots<> {
|
||||
// Set the frame encryptor to use on all outgoing frames. This is optional.
|
||||
// This pointers lifetime is managed by the set of RtpSender it is attached
|
||||
// to.
|
||||
// TODO(benwright) make pure virtual once internal supports it.
|
||||
virtual void SetFrameEncryptor(
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor);
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor);
|
||||
// Set the frame decryptor to use on all incoming frames. This is optional.
|
||||
// This pointers lifetimes is managed by the set of RtpReceivers it is
|
||||
// attached to.
|
||||
// TODO(benwright) make pure virtual once internal supports it.
|
||||
virtual void SetFrameDecryptor(
|
||||
webrtc::FrameDecryptorInterface* frame_decryptor);
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor);
|
||||
|
||||
// Base method to send packet using NetworkInterface.
|
||||
bool SendPacket(rtc::CopyOnWriteBuffer* packet,
|
||||
@ -281,10 +284,6 @@ class MediaChannel : public sigslot::has_slots<> {
|
||||
// of network_interface_ object.
|
||||
rtc::CriticalSection network_interface_crit_;
|
||||
NetworkInterface* network_interface_;
|
||||
|
||||
protected:
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor_ = nullptr;
|
||||
webrtc::FrameDecryptorInterface* frame_decryptor_ = nullptr;
|
||||
};
|
||||
|
||||
// The stats information is structured as follows:
|
||||
|
@ -719,7 +719,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
webrtc::Call* call,
|
||||
webrtc::Transport* send_transport,
|
||||
const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
|
||||
const absl::optional<webrtc::AudioCodecPairId> codec_pair_id)
|
||||
const absl::optional<webrtc::AudioCodecPairId> codec_pair_id,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor)
|
||||
: call_(call),
|
||||
config_(send_transport),
|
||||
send_side_bwe_with_overhead_(
|
||||
@ -736,6 +737,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
config_.encoder_factory = encoder_factory;
|
||||
config_.codec_pair_id = codec_pair_id;
|
||||
config_.track_id = track_id;
|
||||
config_.frame_encryptor = frame_encryptor;
|
||||
rtp_parameters_.encodings[0].ssrc = ssrc;
|
||||
rtp_parameters_.rtcp.cname = c_name;
|
||||
rtp_parameters_.header_extensions = extensions;
|
||||
@ -775,6 +777,13 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
|
||||
ReconfigureAudioSendStream();
|
||||
}
|
||||
|
||||
void SetFrameEncryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
config_.frame_encryptor = frame_encryptor;
|
||||
ReconfigureAudioSendStream();
|
||||
}
|
||||
|
||||
void SetAudioNetworkAdaptorConfig(
|
||||
const absl::optional<std::string>& audio_network_adaptor_config) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
@ -1072,7 +1081,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
|
||||
const std::map<int, webrtc::SdpAudioFormat>& decoder_map,
|
||||
absl::optional<webrtc::AudioCodecPairId> codec_pair_id,
|
||||
size_t jitter_buffer_max_packets,
|
||||
bool jitter_buffer_fast_accelerate)
|
||||
bool jitter_buffer_fast_accelerate,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor)
|
||||
: call_(call), config_() {
|
||||
RTC_DCHECK(call);
|
||||
config_.rtp.remote_ssrc = remote_ssrc;
|
||||
@ -1089,6 +1099,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
|
||||
config_.decoder_factory = decoder_factory;
|
||||
config_.decoder_map = decoder_map;
|
||||
config_.codec_pair_id = codec_pair_id;
|
||||
config_.frame_decryptor = frame_decryptor;
|
||||
RecreateAudioReceiveStream();
|
||||
}
|
||||
|
||||
@ -1097,6 +1108,13 @@ class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
|
||||
call_->DestroyAudioReceiveStream(stream_);
|
||||
}
|
||||
|
||||
void SetFrameDecryptor(
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
config_.frame_decryptor = frame_decryptor;
|
||||
RecreateAudioReceiveStream();
|
||||
}
|
||||
|
||||
void SetLocalSsrc(uint32_t local_ssrc) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
config_.rtp.local_ssrc = local_ssrc;
|
||||
@ -1745,7 +1763,7 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
|
||||
WebRtcAudioSendStream* stream = new WebRtcAudioSendStream(
|
||||
ssrc, mid_, sp.cname, sp.id, send_codec_spec_, send_rtp_extensions_,
|
||||
max_send_bitrate_bps_, audio_network_adaptor_config, call_, this,
|
||||
engine()->encoder_factory_, codec_pair_id_);
|
||||
engine()->encoder_factory_, codec_pair_id_, nullptr);
|
||||
send_streams_.insert(std::make_pair(ssrc, stream));
|
||||
|
||||
// At this point the stream's local SSRC has been updated. If it is the first
|
||||
@ -1831,7 +1849,8 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
|
||||
recv_nack_enabled_, sp.stream_ids(), recv_rtp_extensions_,
|
||||
call_, this, engine()->decoder_factory_, decoder_map_,
|
||||
codec_pair_id_, engine()->audio_jitter_buffer_max_packets_,
|
||||
engine()->audio_jitter_buffer_fast_accelerate_)));
|
||||
engine()->audio_jitter_buffer_fast_accelerate_,
|
||||
unsignaled_frame_decryptor_)));
|
||||
recv_streams_[ssrc]->SetPlayout(playout_);
|
||||
|
||||
return true;
|
||||
@ -1912,6 +1931,30 @@ bool WebRtcVoiceMediaChannel::CanInsertDtmf() {
|
||||
return dtmf_payload_type_.has_value() && send_;
|
||||
}
|
||||
|
||||
void WebRtcVoiceMediaChannel::SetFrameDecryptor(
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
auto matching_stream = recv_streams_.find(ssrc);
|
||||
if (matching_stream != recv_streams_.end()) {
|
||||
matching_stream->second->SetFrameDecryptor(frame_decryptor);
|
||||
}
|
||||
// Handle unsignaled frame decryptors.
|
||||
if (ssrc == 0) {
|
||||
unsignaled_frame_decryptor_ = frame_decryptor;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcVoiceMediaChannel::SetFrameEncryptor(
|
||||
uint32_t ssrc,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
|
||||
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
|
||||
auto matching_stream = send_streams_.find(ssrc);
|
||||
if (matching_stream != send_streams_.end()) {
|
||||
matching_stream->second->SetFrameEncryptor(frame_encryptor);
|
||||
}
|
||||
}
|
||||
|
||||
bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc,
|
||||
int event,
|
||||
int duration) {
|
||||
|
@ -170,6 +170,21 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
bool RemoveSendStream(uint32_t ssrc) override;
|
||||
bool AddRecvStream(const StreamParams& sp) override;
|
||||
bool RemoveRecvStream(uint32_t ssrc) override;
|
||||
|
||||
// E2EE Frame API
|
||||
// Set a frame decryptor to a particular ssrc that will intercept all
|
||||
// incoming audio payloads 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 audio payloads 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;
|
||||
|
||||
// SSRC=0 will apply the new volume to current and future unsignaled streams.
|
||||
bool SetOutputVolume(uint32_t ssrc, double volume) override;
|
||||
|
||||
@ -287,6 +302,10 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
|
||||
const webrtc::AudioCodecPairId codec_pair_id_ =
|
||||
webrtc::AudioCodecPairId::Create();
|
||||
|
||||
// Unsignaled streams have an option to have a frame decryptor set on them.
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface>
|
||||
unsignaled_frame_decryptor_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcVoiceMediaChannel);
|
||||
};
|
||||
} // namespace cricket
|
||||
|
@ -492,6 +492,7 @@ if (rtc_include_tests) {
|
||||
deps = [
|
||||
":peerconnection",
|
||||
":rtc_pc_base",
|
||||
"../api:fake_frame_crypto",
|
||||
"../api:libjingle_peerconnection_api",
|
||||
"../api:mock_rtp",
|
||||
"../api/units:time_delta",
|
||||
|
@ -43,13 +43,17 @@ std::vector<rtc::scoped_refptr<MediaStreamInterface>> CreateStreamsFromIds(
|
||||
return streams;
|
||||
}
|
||||
|
||||
void AttachFrameDecryptorToMediaChannel(
|
||||
// Attempt to attach the frame decryptor to the current media channel on the
|
||||
// correct worker thread only if both the media channel exists and a ssrc has
|
||||
// been allocated to the stream.
|
||||
void MaybeAttachFrameDecryptorToMediaChannel(
|
||||
const absl::optional<uint32_t>& ssrc,
|
||||
rtc::Thread* worker_thread,
|
||||
webrtc::FrameDecryptorInterface* frame_decryptor,
|
||||
rtc::scoped_refptr<webrtc::FrameDecryptorInterface> frame_decryptor,
|
||||
cricket::MediaChannel* media_channel) {
|
||||
if (media_channel) {
|
||||
if (media_channel && ssrc.has_value()) {
|
||||
return worker_thread->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel->SetFrameDecryptor(frame_decryptor);
|
||||
media_channel->SetFrameDecryptor(*ssrc, frame_decryptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -152,8 +156,9 @@ bool AudioRtpReceiver::SetParameters(const RtpParameters& parameters) {
|
||||
void AudioRtpReceiver::SetFrameDecryptor(
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) {
|
||||
frame_decryptor_ = std::move(frame_decryptor);
|
||||
AttachFrameDecryptorToMediaChannel(worker_thread_, frame_decryptor_.get(),
|
||||
media_channel_);
|
||||
// Attach the frame decryptor to the media channel if it exists.
|
||||
MaybeAttachFrameDecryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_decryptor_, media_channel_);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<FrameDecryptorInterface>
|
||||
@ -246,6 +251,9 @@ void AudioRtpReceiver::Reconfigure() {
|
||||
if (!SetOutputVolume(track_->enabled() ? cached_volume_ : 0)) {
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
// Reattach the frame decryptor if we were reconfigured.
|
||||
MaybeAttachFrameDecryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_decryptor_, media_channel_);
|
||||
}
|
||||
|
||||
void AudioRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) {
|
||||
@ -259,8 +267,6 @@ void AudioRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) {
|
||||
void AudioRtpReceiver::SetVoiceMediaChannel(
|
||||
cricket::VoiceMediaChannel* voice_media_channel) {
|
||||
media_channel_ = voice_media_channel;
|
||||
AttachFrameDecryptorToMediaChannel(worker_thread_, frame_decryptor_.get(),
|
||||
media_channel_);
|
||||
}
|
||||
|
||||
void AudioRtpReceiver::NotifyFirstPacketReceived() {
|
||||
@ -341,8 +347,9 @@ bool VideoRtpReceiver::SetParameters(const RtpParameters& parameters) {
|
||||
void VideoRtpReceiver::SetFrameDecryptor(
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> frame_decryptor) {
|
||||
frame_decryptor_ = std::move(frame_decryptor);
|
||||
AttachFrameDecryptorToMediaChannel(worker_thread_, frame_decryptor_.get(),
|
||||
media_channel_);
|
||||
// Attach the new frame decryptor the media channel if it exists yet.
|
||||
MaybeAttachFrameDecryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_decryptor_, media_channel_);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<FrameDecryptorInterface>
|
||||
@ -379,6 +386,9 @@ void VideoRtpReceiver::SetupMediaChannel(uint32_t ssrc) {
|
||||
}
|
||||
ssrc_ = ssrc;
|
||||
SetSink(source_->sink());
|
||||
// Attach any existing frame decryptor to the media channel.
|
||||
MaybeAttachFrameDecryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_decryptor_, media_channel_);
|
||||
}
|
||||
|
||||
void VideoRtpReceiver::set_stream_ids(std::vector<std::string> stream_ids) {
|
||||
@ -429,8 +439,6 @@ void VideoRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) {
|
||||
void VideoRtpReceiver::SetVideoMediaChannel(
|
||||
cricket::VideoMediaChannel* video_media_channel) {
|
||||
media_channel_ = video_media_channel;
|
||||
AttachFrameDecryptorToMediaChannel(worker_thread_, frame_decryptor_.get(),
|
||||
media_channel_);
|
||||
}
|
||||
|
||||
void VideoRtpReceiver::NotifyFirstPacketReceived() {
|
||||
|
@ -31,20 +31,6 @@ int GenerateUniqueId() {
|
||||
return ++g_unique_id;
|
||||
}
|
||||
|
||||
// Attaches the frame encryptor to the media channel through an invoke on a
|
||||
// worker thread. This set must be done on the corresponding worker thread that
|
||||
// the media channel was created on.
|
||||
void AttachFrameEncryptorToMediaChannel(
|
||||
rtc::Thread* worker_thread,
|
||||
webrtc::FrameEncryptorInterface* frame_encryptor,
|
||||
cricket::MediaChannel* media_channel) {
|
||||
if (media_channel) {
|
||||
return worker_thread->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel->SetFrameEncryptor(frame_encryptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an true if any RtpEncodingParameters member that isn't implemented
|
||||
// contains a value.
|
||||
bool UnimplementedRtpEncodingParameterHasValue(
|
||||
@ -78,6 +64,21 @@ bool PerSenderRtpEncodingParameterHasValue(
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to attach the frame decryptor to the current media channel on the
|
||||
// correct worker thread only if both the media channel exists and a ssrc has
|
||||
// been allocated to the stream.
|
||||
void MaybeAttachFrameEncryptorToMediaChannel(
|
||||
const absl::optional<uint32_t> ssrc,
|
||||
rtc::Thread* worker_thread,
|
||||
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor,
|
||||
cricket::MediaChannel* media_channel) {
|
||||
if (media_channel && ssrc.has_value()) {
|
||||
return worker_thread->Invoke<void>(RTC_FROM_HERE, [&] {
|
||||
media_channel->SetFrameEncryptor(*ssrc, frame_encryptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Returns true if any RtpParameters member that isn't implemented contains a
|
||||
@ -304,8 +305,8 @@ rtc::scoped_refptr<DtmfSenderInterface> AudioRtpSender::GetDtmfSender() const {
|
||||
void AudioRtpSender::SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
|
||||
frame_encryptor_ = std::move(frame_encryptor);
|
||||
AttachFrameEncryptorToMediaChannel(worker_thread_, frame_encryptor_.get(),
|
||||
media_channel_);
|
||||
MaybeAttachFrameEncryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_encryptor_, media_channel_);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> AudioRtpSender::GetFrameEncryptor()
|
||||
@ -354,6 +355,9 @@ void AudioRtpSender::SetSsrc(uint32_t ssrc) {
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
// Each time there is an ssrc update.
|
||||
MaybeAttachFrameEncryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_encryptor_, media_channel_);
|
||||
}
|
||||
|
||||
void AudioRtpSender::Stop() {
|
||||
@ -379,8 +383,6 @@ void AudioRtpSender::Stop() {
|
||||
void AudioRtpSender::SetVoiceMediaChannel(
|
||||
cricket::VoiceMediaChannel* voice_media_channel) {
|
||||
media_channel_ = voice_media_channel;
|
||||
AttachFrameEncryptorToMediaChannel(worker_thread_, frame_encryptor_.get(),
|
||||
media_channel_);
|
||||
}
|
||||
|
||||
void AudioRtpSender::SetAudioSend() {
|
||||
@ -555,8 +557,8 @@ rtc::scoped_refptr<DtmfSenderInterface> VideoRtpSender::GetDtmfSender() const {
|
||||
void VideoRtpSender::SetFrameEncryptor(
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
|
||||
frame_encryptor_ = std::move(frame_encryptor);
|
||||
AttachFrameEncryptorToMediaChannel(worker_thread_, frame_encryptor_.get(),
|
||||
media_channel_);
|
||||
MaybeAttachFrameEncryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_encryptor_, media_channel_);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> VideoRtpSender::GetFrameEncryptor()
|
||||
@ -599,6 +601,8 @@ void VideoRtpSender::SetSsrc(uint32_t ssrc) {
|
||||
init_parameters_.encodings.clear();
|
||||
});
|
||||
}
|
||||
MaybeAttachFrameEncryptorToMediaChannel(ssrc_, worker_thread_,
|
||||
frame_encryptor_, media_channel_);
|
||||
}
|
||||
|
||||
void VideoRtpSender::Stop() {
|
||||
@ -620,8 +624,6 @@ void VideoRtpSender::Stop() {
|
||||
void VideoRtpSender::SetVideoMediaChannel(
|
||||
cricket::VideoMediaChannel* video_media_channel) {
|
||||
media_channel_ = video_media_channel;
|
||||
AttachFrameEncryptorToMediaChannel(worker_thread_, frame_encryptor_.get(),
|
||||
media_channel_);
|
||||
}
|
||||
|
||||
void VideoRtpSender::SetVideoSend() {
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <utility>
|
||||
|
||||
#include "api/rtpparameters.h"
|
||||
#include "api/test/fake_frame_decryptor.h"
|
||||
#include "api/test/fake_frame_encryptor.h"
|
||||
#include "media/base/fakemediaengine.h"
|
||||
#include "media/base/rtpdataengine.h"
|
||||
#include "media/base/testutils.h"
|
||||
@ -1411,4 +1413,26 @@ TEST_F(RtpSenderReceiverTest, TestOnDestroyedSignal) {
|
||||
EXPECT_TRUE(audio_sender_destroyed_signal_fired_);
|
||||
}
|
||||
|
||||
// Validate that the default FrameEncryptor setting is nullptr.
|
||||
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetFrameEncryptor) {
|
||||
CreateAudioRtpSender();
|
||||
rtc::scoped_refptr<FrameEncryptorInterface> fake_frame_encryptor(
|
||||
new FakeFrameEncryptor());
|
||||
EXPECT_EQ(nullptr, audio_rtp_sender_->GetFrameEncryptor());
|
||||
audio_rtp_sender_->SetFrameEncryptor(fake_frame_encryptor);
|
||||
EXPECT_EQ(fake_frame_encryptor.get(),
|
||||
audio_rtp_sender_->GetFrameEncryptor().get());
|
||||
}
|
||||
|
||||
// Validate that the default FrameEncryptor setting is nullptr.
|
||||
TEST_F(RtpSenderReceiverTest, AudioReceiverCanSetFrameDecryptor) {
|
||||
CreateAudioRtpReceiver();
|
||||
rtc::scoped_refptr<FrameDecryptorInterface> fake_frame_decryptor(
|
||||
new FakeFrameDecryptor());
|
||||
EXPECT_EQ(nullptr, audio_rtp_receiver_->GetFrameDecryptor());
|
||||
audio_rtp_receiver_->SetFrameDecryptor(fake_frame_decryptor);
|
||||
EXPECT_EQ(fake_frame_decryptor.get(),
|
||||
audio_rtp_receiver_->GetFrameDecryptor().get());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
Reference in New Issue
Block a user