Create the SrtpTransportInterface.

Create the SrtpTransportInterface, a subclass of RtpTransportInterface, which
allows the user to set the send and receive keys. The functionalities are
implemented inside the RtpTransportAdapters on top of BaseChannel.

BUG=webrtc:7013

Review-Url: https://codereview.webrtc.org/2714813004
Cr-Commit-Position: refs/heads/master@{#17023}
This commit is contained in:
zhihuang 2017-03-03 14:39:06 -08:00 committed by Commit bot
parent 716e726ef0
commit d3501adf17
18 changed files with 758 additions and 118 deletions

View File

@ -94,6 +94,7 @@ rtc_source_set("ortc_api") {
"ortc/packettransportinterface.h",
"ortc/rtptransportcontrollerinterface.h",
"ortc/rtptransportinterface.h",
"ortc/srtptransportinterface.h",
"ortc/udptransportinterface.h",
]

View File

@ -23,6 +23,7 @@
#include "webrtc/api/ortc/packettransportinterface.h"
#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/api/ortc/udptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"
@ -126,6 +127,14 @@ class OrtcFactoryInterface {
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) = 0;
// Creates an SrtpTransport which is an RTP transport that uses SRTP.
virtual RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
CreateSrtpTransport(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) = 0;
// Returns the capabilities of an RTP sender of type |kind|. These
// capabilities can be used to determine what RtpParameters to use to create
// an RtpSender.

View File

@ -18,8 +18,8 @@
#ifndef WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
#define WEBRTC_API_ORTC_ORTCRTPSENDERINTERFACE_H_
#include "webrtc/api/mediatypes.h"
#include "webrtc/api/mediastreaminterface.h"
#include "webrtc/api/mediatypes.h"
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"

View File

@ -0,0 +1,48 @@
/*
* Copyright 2017 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 WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
#define WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/media/base/cryptoparams.h"
namespace webrtc {
// The subclass of the RtpTransport which uses SRTP. The keying information
// is explicitly passed in from the application.
//
// If using SDP and SDES (RFC4568) for signaling, then after applying the
// answer, the negotiated keying information from the offer and answer would be
// set and the SRTP would be active.
//
// Note that Edge's implementation of ORTC provides a similar API point, called
// RTCSrtpSdesTransport:
// https://msdn.microsoft.com/en-us/library/mt502527(v=vs.85).aspx
class SrtpTransportInterface : public RtpTransportInterface {
public:
virtual ~SrtpTransportInterface() {}
// There are some limitations of the current implementation:
// 1. Send and receive keys must use the same crypto suite.
// 2. The keys can't be changed after initially set.
// 3. The keys must be set before creating a sender/receiver using the SRTP
// transport.
// Set the SRTP keying material for sending RTP and RTCP.
virtual RTCError SetSrtpSendKey(const cricket::CryptoParams& params) = 0;
// Set the SRTP keying material for receiving RTP and RTCP.
virtual RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) = 0;
};
} // namespace webrtc
#endif // WEBRTC_API_ORTC_SRTPTRANSPORTINTERFACE_H_

View File

@ -16,8 +16,8 @@
#include <vector>
#include "webrtc/api/mediatypes.h"
#include "webrtc/config.h"
#include "webrtc/base/optional.h"
#include "webrtc/config.h"
namespace webrtc {

View File

@ -58,6 +58,7 @@ if (rtc_include_tests) {
"rtpparametersconversion_unittest.cc",
"rtptransport_unittest.cc",
"rtptransportcontroller_unittest.cc",
"srtptransport_unittest.cc",
"testrtpparameters.cc",
"testrtpparameters.h",
]

View File

@ -11,11 +11,11 @@
#include "webrtc/ortc/ortcfactory.h"
#include <sstream>
#include <vector>
#include <utility> // For std::move.
#include <vector>
#include "webrtc/api/proxy.h"
#include "webrtc/api/mediastreamtrackproxy.h"
#include "webrtc/api/proxy.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/videosourceproxy.h"
#include "webrtc/base/asyncpacketsocket.h"
@ -33,9 +33,9 @@
#include "webrtc/ortc/rtptransportcontrolleradapter.h"
#include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/base/udptransport.h"
#include "webrtc/pc/audiotrack.h"
#include "webrtc/pc/channelmanager.h"
#include "webrtc/pc/localaudiosource.h"
#include "webrtc/pc/audiotrack.h"
#include "webrtc/pc/videocapturertracksource.h"
#include "webrtc/pc/videotrack.h"
@ -78,6 +78,14 @@ PROXY_METHOD4(RTCErrorOr<std::unique_ptr<RtpTransportInterface>>,
PacketTransportInterface*,
PacketTransportInterface*,
RtpTransportControllerInterface*)
PROXY_METHOD4(RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>,
CreateSrtpTransport,
const RtcpParameters&,
PacketTransportInterface*,
PacketTransportInterface*,
RtpTransportControllerInterface*)
PROXY_CONSTMETHOD1(RtpCapabilities,
GetRtpSenderCapabilities,
cricket::MediaType)
@ -250,6 +258,43 @@ OrtcFactory::CreateRtpTransport(
}
}
RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
OrtcFactory::CreateSrtpTransport(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) {
RTC_DCHECK_RUN_ON(signaling_thread_);
RtcpParameters copied_parameters = rtcp_parameters;
if (copied_parameters.cname.empty()) {
copied_parameters.cname = default_cname_;
}
if (transport_controller) {
return transport_controller->GetInternal()->CreateProxiedSrtpTransport(
copied_parameters, rtp, rtcp);
} else {
// If |transport_controller| is null, create one automatically, which the
// returned SrtpTransport will own.
auto controller_result = CreateRtpTransportController();
if (!controller_result.ok()) {
return controller_result.MoveError();
}
auto controller = controller_result.MoveValue();
auto transport_result =
controller->GetInternal()->CreateProxiedSrtpTransport(copied_parameters,
rtp, rtcp);
// If SrtpTransport was successfully created, transfer ownership of
// |rtp_transport_controller|. Otherwise it will go out of scope and be
// deleted automatically.
if (transport_result.ok()) {
transport_result.value()
->GetInternal()
->TakeOwnershipOfRtpTransportController(std::move(controller));
}
return transport_result;
}
}
RtpCapabilities OrtcFactory::GetRtpSenderCapabilities(
cricket::MediaType kind) const {
RTC_DCHECK_RUN_ON(signaling_thread_);

View File

@ -49,6 +49,12 @@ class OrtcFactory : public OrtcFactoryInterface {
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) override;
RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpTransport(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerInterface* transport_controller) override;
RtpCapabilities GetRtpSenderCapabilities(
cricket::MediaType kind) const override;

View File

@ -25,13 +25,38 @@
namespace {
const int kDefaultTimeout = 10000; // 10 seconds.
const int kDefaultTimeout = 10000; // 10 seconds.
const int kReceivingDuration = 1000; // 1 second.
// Default number of audio/video frames to wait for before considering a test a
// success.
const int kDefaultNumFrames = 3;
const rtc::IPAddress kIPv4LocalHostAddress =
rtc::IPAddress(0x7F000001); // 127.0.0.1
static const char kTestKeyParams1[] =
"inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVz";
static const char kTestKeyParams2[] =
"inline:PS1uQCVeeCFCanVmcjkpaywjNWhcYD0mXXtxaVBR";
static const char kTestKeyParams3[] =
"inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVa";
static const char kTestKeyParams4[] =
"inline:WVNfX19zZW1jdGwgKskgewkyMjA7fQp9CnVubGVb";
static const cricket::CryptoParams kTestCryptoParams1(1,
"AES_CM_128_HMAC_SHA1_80",
kTestKeyParams1,
"");
static const cricket::CryptoParams kTestCryptoParams2(1,
"AES_CM_128_HMAC_SHA1_80",
kTestKeyParams2,
"");
static const cricket::CryptoParams kTestCryptoParams3(1,
"AES_CM_128_HMAC_SHA1_80",
kTestKeyParams3,
"");
static const cricket::CryptoParams kTestCryptoParams4(1,
"AES_CM_128_HMAC_SHA1_80",
kTestKeyParams4,
"");
} // namespace
namespace webrtc {
@ -71,6 +96,9 @@ class OrtcFactoryIntegrationTest : public testing::Test {
typedef std::pair<std::unique_ptr<RtpTransportInterface>,
std::unique_ptr<RtpTransportInterface>>
RtpTransportPair;
typedef std::pair<std::unique_ptr<SrtpTransportInterface>,
std::unique_ptr<SrtpTransportInterface>>
SrtpTransportPair;
typedef std::pair<std::unique_ptr<RtpTransportControllerInterface>,
std::unique_ptr<RtpTransportControllerInterface>>
RtpTransportControllerPair;
@ -115,6 +143,20 @@ class OrtcFactoryIntegrationTest : public testing::Test {
return {transport_result1.MoveValue(), transport_result2.MoveValue()};
}
SrtpTransportPair CreateSrtpTransportPair(
const RtcpParameters& rtcp_parameters,
const UdpTransportPair& rtp_udp_transports,
const UdpTransportPair& rtcp_udp_transports,
const RtpTransportControllerPair& transport_controllers) {
auto transport_result1 = ortc_factory1_->CreateSrtpTransport(
rtcp_parameters, rtp_udp_transports.first.get(),
rtcp_udp_transports.first.get(), transport_controllers.first.get());
auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
rtcp_parameters, rtp_udp_transports.second.get(),
rtcp_udp_transports.second.get(), transport_controllers.second.get());
return {transport_result1.MoveValue(), transport_result2.MoveValue()};
}
// For convenience when |rtcp_udp_transports| and |transport_controllers|
// aren't needed.
RtpTransportPair CreateRtpTransportPair(
@ -125,6 +167,38 @@ class OrtcFactoryIntegrationTest : public testing::Test {
RtpTransportControllerPair());
}
SrtpTransportPair CreateSrtpTransportPairAndSetKeys(
const RtcpParameters& rtcp_parameters,
const UdpTransportPair& rtp_udp_transports) {
SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
RtpTransportControllerPair());
EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
EXPECT_TRUE(
srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
EXPECT_TRUE(
srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2).ok());
EXPECT_TRUE(
srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1).ok());
return srtp_transports;
}
SrtpTransportPair CreateSrtpTransportPairAndSetMismatchingKeys(
const RtcpParameters& rtcp_parameters,
const UdpTransportPair& rtp_udp_transports) {
SrtpTransportPair srtp_transports = CreateSrtpTransportPair(
rtcp_parameters, rtp_udp_transports, UdpTransportPair(),
RtpTransportControllerPair());
EXPECT_TRUE(srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1).ok());
EXPECT_TRUE(
srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2).ok());
EXPECT_TRUE(
srtp_transports.second->SetSrtpSendKey(kTestCryptoParams1).ok());
EXPECT_TRUE(
srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams2).ok());
return srtp_transports;
}
// Ends up using fake audio capture module, which was passed into OrtcFactory
// on creation.
rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateLocalAudioTrack(
@ -152,6 +226,110 @@ class OrtcFactoryIntegrationTest : public testing::Test {
ortc_factory->CreateVideoTrack(id, source));
}
// Helper function used to test two way RTP senders and receivers with basic
// configurations.
// If |expect_success| is true, waits for kDefaultTimeout for
// kDefaultNumFrames frames to be received by all RtpReceivers.
// If |expect_success| is false, simply waits for |kReceivingDuration|, and
// stores the number of received frames in |received_audio_frame1_| etc.
void BasicTwoWayRtpSendersAndReceiversTest(RtpTransportPair srtp_transports,
bool expect_success) {
received_audio_frames1_ = 0;
received_audio_frames2_ = 0;
rendered_video_frames1_ = 0;
rendered_video_frames2_ = 0;
// Create all the senders and receivers (four per endpoint).
auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, srtp_transports.first.get());
auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, srtp_transports.first.get());
ASSERT_TRUE(audio_sender_result1.ok());
ASSERT_TRUE(video_sender_result1.ok());
ASSERT_TRUE(audio_receiver_result1.ok());
ASSERT_TRUE(video_receiver_result1.ok());
auto audio_sender1 = audio_sender_result1.MoveValue();
auto video_sender1 = video_sender_result1.MoveValue();
auto audio_receiver1 = audio_receiver_result1.MoveValue();
auto video_receiver1 = video_receiver_result1.MoveValue();
auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, srtp_transports.second.get());
auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, srtp_transports.second.get());
ASSERT_TRUE(audio_sender_result2.ok());
ASSERT_TRUE(video_sender_result2.ok());
ASSERT_TRUE(audio_receiver_result2.ok());
ASSERT_TRUE(video_receiver_result2.ok());
auto audio_sender2 = audio_sender_result2.MoveValue();
auto video_sender2 = video_sender_result2.MoveValue();
auto audio_receiver2 = audio_receiver_result2.MoveValue();
auto video_receiver2 = video_receiver_result2.MoveValue();
// Add fake tracks.
RTCError error = audio_sender1->SetTrack(
CreateLocalAudioTrack("audio", ortc_factory1_.get()));
EXPECT_TRUE(error.ok());
error = video_sender1->SetTrack(
CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
EXPECT_TRUE(error.ok());
error = audio_sender2->SetTrack(
CreateLocalAudioTrack("audio", ortc_factory2_.get()));
EXPECT_TRUE(error.ok());
error = video_sender2->SetTrack(
CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
EXPECT_TRUE(error.ok());
// "sent_X_parameters1" are the parameters that endpoint 1 sends with and
// endpoint 2 receives with.
RtpParameters sent_opus_parameters1 =
MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
RtpParameters sent_vp8_parameters1 =
MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
RtpParameters sent_opus_parameters2 =
MakeMinimalOpusParametersWithSsrc(0x13333337);
RtpParameters sent_vp8_parameters2 =
MakeMinimalVp8ParametersWithSsrc(0x12345678);
// Configure the senders' and receivers' parameters.
EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
FakeVideoTrackRenderer fake_video_renderer1(
static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
FakeVideoTrackRenderer fake_video_renderer2(
static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
if (expect_success) {
EXPECT_TRUE_WAIT(
fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
fake_audio_capture_module2_->frames_received() >
kDefaultNumFrames &&
fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames,
kDefaultTimeout);
} else {
WAIT(false, kReceivingDuration);
rendered_video_frames1_ = fake_video_renderer1.num_rendered_frames();
rendered_video_frames2_ = fake_video_renderer2.num_rendered_frames();
received_audio_frames1_ = fake_audio_capture_module1_->frames_received();
received_audio_frames2_ = fake_audio_capture_module2_->frames_received();
}
}
rtc::PhysicalSocketServer physical_socket_server_;
rtc::VirtualSocketServer virtual_socket_server_;
rtc::Thread network_thread_;
@ -162,6 +340,10 @@ class OrtcFactoryIntegrationTest : public testing::Test {
std::unique_ptr<OrtcFactoryInterface> ortc_factory2_;
// Actually owned by video tracks.
std::vector<cricket::FakeVideoCapturer*> fake_video_capturers_;
int received_audio_frames1_ = 0;
int received_audio_frames2_ = 0;
int rendered_video_frames1_ = 0;
int rendered_video_frames2_ = 0;
};
// Very basic end-to-end test with a single pair of audio RTP sender and
@ -285,102 +467,75 @@ TEST_F(OrtcFactoryIntegrationTest,
auto udp_transports = CreateAndConnectUdpTransportPair();
auto rtp_transports =
CreateRtpTransportPair(MakeRtcpMuxParameters(), udp_transports);
bool expect_success = true;
BasicTwoWayRtpSendersAndReceiversTest(std::move(rtp_transports),
expect_success);
}
// Create all the senders and receivers (four per endpoint).
auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, rtp_transports.first.get());
auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, rtp_transports.first.get());
ASSERT_TRUE(audio_sender_result1.ok());
ASSERT_TRUE(video_sender_result1.ok());
ASSERT_TRUE(audio_receiver_result1.ok());
ASSERT_TRUE(video_receiver_result1.ok());
auto audio_sender1 = audio_sender_result1.MoveValue();
auto video_sender1 = video_sender_result1.MoveValue();
auto audio_receiver1 = audio_receiver_result1.MoveValue();
auto video_receiver1 = video_receiver_result1.MoveValue();
TEST_F(OrtcFactoryIntegrationTest,
BasicTwoWayAudioVideoSrtpSendersAndReceivers) {
auto udp_transports = CreateAndConnectUdpTransportPair();
auto srtp_transports = CreateSrtpTransportPairAndSetKeys(
MakeRtcpMuxParameters(), udp_transports);
bool expect_success = true;
BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
expect_success);
}
auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, rtp_transports.second.get());
auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, rtp_transports.second.get());
ASSERT_TRUE(audio_sender_result2.ok());
ASSERT_TRUE(video_sender_result2.ok());
ASSERT_TRUE(audio_receiver_result2.ok());
ASSERT_TRUE(video_receiver_result2.ok());
auto audio_sender2 = audio_sender_result2.MoveValue();
auto video_sender2 = video_sender_result2.MoveValue();
auto audio_receiver2 = audio_receiver_result2.MoveValue();
auto video_receiver2 = video_receiver_result2.MoveValue();
// Tests that the packets cannot be decoded if the keys are mismatched.
TEST_F(OrtcFactoryIntegrationTest, SrtpSendersAndReceiversWithMismatchingKeys) {
auto udp_transports = CreateAndConnectUdpTransportPair();
auto srtp_transports = CreateSrtpTransportPairAndSetMismatchingKeys(
MakeRtcpMuxParameters(), udp_transports);
bool expect_success = false;
BasicTwoWayRtpSendersAndReceiversTest(std::move(srtp_transports),
expect_success);
// No frames are expected to be decoded.
EXPECT_TRUE(received_audio_frames1_ == 0 && received_audio_frames2_ == 0 &&
rendered_video_frames1_ == 0 && rendered_video_frames2_ == 0);
}
// Add fake tracks.
RTCError error = audio_sender1->SetTrack(
CreateLocalAudioTrack("audio", ortc_factory1_.get()));
EXPECT_TRUE(error.ok());
error = video_sender1->SetTrack(
CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory1_.get()));
EXPECT_TRUE(error.ok());
error = audio_sender2->SetTrack(
CreateLocalAudioTrack("audio", ortc_factory2_.get()));
EXPECT_TRUE(error.ok());
error = video_sender2->SetTrack(
CreateLocalVideoTrackAndFakeCapturer("video", ortc_factory2_.get()));
EXPECT_TRUE(error.ok());
// Tests that the frames cannot be decoded if only one side uses SRTP.
TEST_F(OrtcFactoryIntegrationTest, OneSideSrtpSenderAndReceiver) {
auto rtcp_parameters = MakeRtcpMuxParameters();
auto udp_transports = CreateAndConnectUdpTransportPair();
auto rtcp_udp_transports = UdpTransportPair();
auto transport_controllers = RtpTransportControllerPair();
auto transport_result1 = ortc_factory1_->CreateRtpTransport(
rtcp_parameters, udp_transports.first.get(),
rtcp_udp_transports.first.get(), transport_controllers.first.get());
auto transport_result2 = ortc_factory2_->CreateSrtpTransport(
rtcp_parameters, udp_transports.second.get(),
rtcp_udp_transports.second.get(), transport_controllers.second.get());
// "sent_X_parameters1" are the parameters that endpoint 1 sends with and
// endpoint 2 receives with.
RtpParameters sent_opus_parameters1 =
MakeMinimalOpusParametersWithSsrc(0xdeadbeef);
RtpParameters sent_vp8_parameters1 =
MakeMinimalVp8ParametersWithSsrc(0xbaadfeed);
RtpParameters sent_opus_parameters2 =
MakeMinimalOpusParametersWithSsrc(0x13333337);
RtpParameters sent_vp8_parameters2 =
MakeMinimalVp8ParametersWithSsrc(0x12345678);
auto rtp_transport = transport_result1.MoveValue();
auto srtp_transport = transport_result2.MoveValue();
EXPECT_TRUE(srtp_transport->SetSrtpSendKey(kTestCryptoParams1).ok());
EXPECT_TRUE(srtp_transport->SetSrtpReceiveKey(kTestCryptoParams2).ok());
bool expect_success = false;
BasicTwoWayRtpSendersAndReceiversTest(
{std::move(rtp_transport), std::move(srtp_transport)}, expect_success);
// Configure the senders' and receivers' parameters.
EXPECT_TRUE(audio_receiver1->Receive(sent_opus_parameters2).ok());
EXPECT_TRUE(video_receiver1->Receive(sent_vp8_parameters2).ok());
EXPECT_TRUE(audio_receiver2->Receive(sent_opus_parameters1).ok());
EXPECT_TRUE(video_receiver2->Receive(sent_vp8_parameters1).ok());
EXPECT_TRUE(audio_sender1->Send(sent_opus_parameters1).ok());
EXPECT_TRUE(video_sender1->Send(sent_vp8_parameters1).ok());
EXPECT_TRUE(audio_sender2->Send(sent_opus_parameters2).ok());
EXPECT_TRUE(video_sender2->Send(sent_vp8_parameters2).ok());
FakeVideoTrackRenderer fake_video_renderer1(
static_cast<VideoTrackInterface*>(video_receiver1->GetTrack().get()));
FakeVideoTrackRenderer fake_video_renderer2(
static_cast<VideoTrackInterface*>(video_receiver2->GetTrack().get()));
// Senders and receivers are connected and configured; audio and video frames
// should be able to flow at this point.
EXPECT_TRUE_WAIT(
fake_audio_capture_module1_->frames_received() > kDefaultNumFrames &&
fake_video_renderer1.num_rendered_frames() > kDefaultNumFrames &&
fake_audio_capture_module2_->frames_received() > kDefaultNumFrames &&
fake_video_renderer2.num_rendered_frames() > kDefaultNumFrames,
kDefaultTimeout);
// The SRTP side is not expected to decode any audio or video frames.
// The RTP side is not expected to decode any video frames while it is
// possible that the encrypted audio frames can be accidentally decoded which
// is why received_audio_frames1_ is not validated.
EXPECT_TRUE(received_audio_frames2_ == 0 && rendered_video_frames1_ == 0 &&
rendered_video_frames2_ == 0);
}
// End-to-end test with two pairs of RTP senders and receivers, for audio and
// video. Unlike the test above, this attempts to make the parameters as
// complex as possible.
// complex as possible. The senders and receivers use the SRTP transport with
// different keys.
//
// Uses non-muxed RTCP, with separate audio/video transports, and a full set of
// parameters, as would normally be used in a PeerConnection.
//
// TODO(deadbeef): Update this test as more audio/video features become
// supported.
TEST_F(OrtcFactoryIntegrationTest, FullTwoWayAudioVideoRtpSendersAndReceivers) {
TEST_F(OrtcFactoryIntegrationTest,
FullTwoWayAudioVideoSrtpSendersAndReceivers) {
// We want four pairs of UDP transports for this test, for audio/video and
// RTP/RTCP.
auto audio_rtp_udp_transports = CreateAndConnectUdpTransportPair();
@ -394,26 +549,37 @@ TEST_F(OrtcFactoryIntegrationTest, FullTwoWayAudioVideoRtpSendersAndReceivers) {
RtcpParameters audio_rtcp_parameters;
audio_rtcp_parameters.mux = false;
auto audio_rtp_transports =
CreateRtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
audio_rtcp_udp_transports, transport_controllers);
auto audio_srtp_transports =
CreateSrtpTransportPair(audio_rtcp_parameters, audio_rtp_udp_transports,
audio_rtcp_udp_transports, transport_controllers);
RtcpParameters video_rtcp_parameters;
video_rtcp_parameters.mux = false;
video_rtcp_parameters.reduced_size = true;
auto video_rtp_transports =
CreateRtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
video_rtcp_udp_transports, transport_controllers);
auto video_srtp_transports =
CreateSrtpTransportPair(video_rtcp_parameters, video_rtp_udp_transports,
video_rtcp_udp_transports, transport_controllers);
// Set keys for SRTP transports.
audio_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams1);
audio_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams2);
video_srtp_transports.first->SetSrtpSendKey(kTestCryptoParams3);
video_srtp_transports.first->SetSrtpReceiveKey(kTestCryptoParams4);
audio_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams2);
audio_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams1);
video_srtp_transports.second->SetSrtpSendKey(kTestCryptoParams4);
video_srtp_transports.second->SetSrtpReceiveKey(kTestCryptoParams3);
// Create all the senders and receivers (four per endpoint).
auto audio_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
auto video_sender_result1 = ortc_factory1_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
auto audio_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.first.get());
cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.first.get());
auto video_receiver_result1 = ortc_factory1_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.first.get());
cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.first.get());
ASSERT_TRUE(audio_sender_result1.ok());
ASSERT_TRUE(video_sender_result1.ok());
ASSERT_TRUE(audio_receiver_result1.ok());
@ -424,13 +590,13 @@ TEST_F(OrtcFactoryIntegrationTest, FullTwoWayAudioVideoRtpSendersAndReceivers) {
auto video_receiver1 = video_receiver_result1.MoveValue();
auto audio_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
auto video_sender_result2 = ortc_factory2_->CreateRtpSender(
cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
auto audio_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, audio_rtp_transports.second.get());
cricket::MEDIA_TYPE_AUDIO, audio_srtp_transports.second.get());
auto video_receiver_result2 = ortc_factory2_->CreateRtpReceiver(
cricket::MEDIA_TYPE_VIDEO, video_rtp_transports.second.get());
cricket::MEDIA_TYPE_VIDEO, video_srtp_transports.second.get());
ASSERT_TRUE(audio_sender_result2.ok());
ASSERT_TRUE(video_sender_result2.ok());
ASSERT_TRUE(audio_receiver_result2.ok());

View File

@ -82,6 +82,24 @@ TEST_F(OrtcFactoryTest, CreateRtpTransportWithAndWithoutMux) {
EXPECT_TRUE(result.ok());
}
// Simple test for the successful cases of CreateSrtpTransport.
TEST_F(OrtcFactoryTest, CreateSrtpTransport) {
rtc::FakePacketTransport rtp("rtp");
rtc::FakePacketTransport rtcp("rtcp");
// With muxed RTCP.
RtcpParameters rtcp_parameters;
rtcp_parameters.mux = true;
auto result = ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp,
nullptr, nullptr);
EXPECT_TRUE(result.ok());
result.MoveValue().reset();
// With non-muxed RTCP.
rtcp_parameters.mux = false;
result =
ortc_factory_->CreateSrtpTransport(rtcp_parameters, &rtp, &rtcp, nullptr);
EXPECT_TRUE(result.ok());
}
// If no CNAME is provided, one should be generated and returned by
// GetRtpParameters.
TEST_F(OrtcFactoryTest, CreateRtpTransportGeneratesCname) {

View File

@ -12,9 +12,9 @@
#include "webrtc/base/gunit.h"
#include "webrtc/media/base/fakemediaengine.h"
#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/ortc/ortcfactory.h"
#include "webrtc/ortc/testrtpparameters.h"
#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/pc/test/fakevideotracksource.h"
namespace webrtc {

View File

@ -12,9 +12,9 @@
#include "webrtc/base/gunit.h"
#include "webrtc/media/base/fakemediaengine.h"
#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/ortc/ortcfactory.h"
#include "webrtc/ortc/testrtpparameters.h"
#include "webrtc/p2p/base/fakepackettransport.h"
#include "webrtc/pc/test/fakevideotracksource.h"
namespace webrtc {

View File

@ -17,8 +17,8 @@
#include "webrtc/api/rtcerror.h"
#include "webrtc/api/rtpparameters.h"
#include "webrtc/base/optional.h"
#include "webrtc/pc/mediasession.h"
#include "webrtc/media/base/codec.h"
#include "webrtc/pc/mediasession.h"
namespace webrtc {

View File

@ -32,6 +32,20 @@ RtpTransportAdapter* GetInternal() override {
}
END_PROXY_MAP()
BEGIN_OWNED_PROXY_MAP(SrtpTransport)
PROXY_SIGNALING_THREAD_DESTRUCTOR()
PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtpPacketTransport)
PROXY_CONSTMETHOD0(PacketTransportInterface*, GetRtcpPacketTransport)
PROXY_METHOD1(RTCError, SetRtcpParameters, const RtcpParameters&)
PROXY_CONSTMETHOD0(RtcpParameters, GetRtcpParameters)
PROXY_METHOD1(RTCError, SetSrtpSendKey, const cricket::CryptoParams&)
PROXY_METHOD1(RTCError, SetSrtpReceiveKey, const cricket::CryptoParams&)
protected:
RtpTransportAdapter* GetInternal() override {
return internal();
}
END_PROXY_MAP()
// static
RTCErrorOr<std::unique_ptr<RtpTransportInterface>>
RtpTransportAdapter::CreateProxied(
@ -64,7 +78,43 @@ RtpTransportAdapter::CreateProxied(
rtp_transport_controller->signaling_thread(),
rtp_transport_controller->worker_thread(),
std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
rtcp_parameters, rtp, rtcp, rtp_transport_controller)));
rtcp_parameters, rtp, rtcp, rtp_transport_controller,
/*is_srtp_transport*/ false)));
}
RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
RtpTransportAdapter::CreateSrtpProxied(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller) {
if (!rtp) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
"Must provide an RTP packet transport.");
}
if (!rtcp_parameters.mux && !rtcp) {
LOG_AND_RETURN_ERROR(
RTCErrorType::INVALID_PARAMETER,
"Must provide an RTCP packet transport when RTCP muxing is not used.");
}
if (rtcp_parameters.mux && rtcp) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
"Creating an RtpTransport with RTCP muxing enabled, "
"with a separate RTCP packet transport?");
}
if (!rtp_transport_controller) {
// Since OrtcFactory::CreateRtpTransport creates an RtpTransportController
// automatically when one isn't passed in, this should never be reached.
RTC_NOTREACHED();
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
"Must provide an RTP transport controller.");
}
return SrtpTransportProxyWithInternal<RtpTransportAdapter>::Create(
rtp_transport_controller->signaling_thread(),
rtp_transport_controller->worker_thread(),
std::unique_ptr<RtpTransportAdapter>(new RtpTransportAdapter(
rtcp_parameters, rtp, rtcp, rtp_transport_controller,
/*is_srtp_transport*/ true)));
}
void RtpTransportAdapter::TakeOwnershipOfRtpTransportController(
@ -78,11 +128,13 @@ RtpTransportAdapter::RtpTransportAdapter(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller)
RtpTransportControllerAdapter* rtp_transport_controller,
bool is_srtp_transport)
: rtp_packet_transport_(rtp),
rtcp_packet_transport_(rtcp),
rtp_transport_controller_(rtp_transport_controller),
rtcp_parameters_(rtcp_parameters) {
rtcp_parameters_(rtcp_parameters),
is_srtp_transport_(is_srtp_transport) {
RTC_DCHECK(rtp_transport_controller);
// CNAME should have been filled by OrtcFactory if empty.
RTC_DCHECK(!rtcp_parameters_.cname.empty());
@ -126,4 +178,36 @@ RTCError RtpTransportAdapter::SetRtcpParameters(
return RTCError::OK();
}
RTCError RtpTransportAdapter::SetSrtpSendKey(
const cricket::CryptoParams& params) {
if (send_key_) {
LOG_AND_RETURN_ERROR(
webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
"Setting the SRTP send key twice is currently unsupported.");
}
if (receive_key_ && receive_key_->cipher_suite != params.cipher_suite) {
LOG_AND_RETURN_ERROR(
webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
"The send key and receive key must have the same cipher suite.");
}
send_key_ = rtc::Optional<cricket::CryptoParams>(params);
return RTCError::OK();
}
RTCError RtpTransportAdapter::SetSrtpReceiveKey(
const cricket::CryptoParams& params) {
if (receive_key_) {
LOG_AND_RETURN_ERROR(
webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
"Setting the SRTP receive key twice is currently unsupported.");
}
if (send_key_ && send_key_->cipher_suite != params.cipher_suite) {
LOG_AND_RETURN_ERROR(
webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
"The send key and receive key must have the same cipher suite.");
}
receive_key_ = rtc::Optional<cricket::CryptoParams>(params);
return RTCError::OK();
}
} // namespace webrtc

View File

@ -14,7 +14,7 @@
#include <memory>
#include <vector>
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/api/rtcerror.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/sigslot.h"
@ -24,13 +24,14 @@
namespace webrtc {
// Implementation of RtpTransportInterface to be used with RtpSenderAdapter,
// RtpReceiverAdapter, and RtpTransportControllerAdapter classes.
// Implementation of SrtpTransportInterface to be used with RtpSenderAdapter,
// RtpReceiverAdapter, and RtpTransportControllerAdapter classes. This class
// is used to implement both a secure and insecure RTP transport.
//
// TODO(deadbeef): When BaseChannel is split apart into separate
// "RtpTransport"/"RtpTransceiver"/"RtpSender"/"RtpReceiver" objects, this
// adapter object can be removed.
class RtpTransportAdapter : public RtpTransportInterface {
class RtpTransportAdapter : public SrtpTransportInterface {
public:
// |rtp| can't be null. |rtcp| can if RTCP muxing is used immediately (meaning
// |rtcp_parameters.mux| is also true).
@ -39,6 +40,13 @@ class RtpTransportAdapter : public RtpTransportInterface {
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller);
static RTCErrorOr<std::unique_ptr<SrtpTransportInterface>> CreateSrtpProxied(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller);
~RtpTransportAdapter() override;
// RtpTransportInterface implementation.
@ -47,6 +55,10 @@ class RtpTransportAdapter : public RtpTransportInterface {
RTCError SetRtcpParameters(const RtcpParameters& parameters) override;
RtcpParameters GetRtcpParameters() const override { return rtcp_parameters_; }
// SRTP specific implementation.
RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override;
RTCError SetSrtpReceiveKey(const cricket::CryptoParams& params) override;
// Methods used internally by OrtcFactory.
RtpTransportControllerAdapter* rtp_transport_controller() {
return rtp_transport_controller_;
@ -58,6 +70,14 @@ class RtpTransportAdapter : public RtpTransportInterface {
// returning this transport from GetTransports().
sigslot::signal1<RtpTransportAdapter*> SignalDestroyed;
// Used by the RtpTransportControllerAdapter to tell if an rtp sender or
// receiver can be created.
bool is_srtp_transport() { return is_srtp_transport_; }
// Used by the RtpTransportControllerAdapter to set keys for senders and
// receivers.
rtc::Optional<cricket::CryptoParams> send_key() { return send_key_; }
rtc::Optional<cricket::CryptoParams> receive_key() { return receive_key_; }
protected:
RtpTransportAdapter* GetInternal() override { return this; }
@ -65,7 +85,8 @@ class RtpTransportAdapter : public RtpTransportInterface {
RtpTransportAdapter(const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp,
RtpTransportControllerAdapter* rtp_transport_controller);
RtpTransportControllerAdapter* rtp_transport_controller,
bool is_srtp_transport);
PacketTransportInterface* rtp_packet_transport_;
PacketTransportInterface* rtcp_packet_transport_;
@ -75,6 +96,11 @@ class RtpTransportAdapter : public RtpTransportInterface {
owned_rtp_transport_controller_;
RtcpParameters rtcp_parameters_;
// SRTP specific members.
rtc::Optional<cricket::CryptoParams> send_key_;
rtc::Optional<cricket::CryptoParams> receive_key_;
bool is_srtp_transport_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpTransportAdapter);
};

View File

@ -11,8 +11,8 @@
#include "webrtc/ortc/rtptransportcontrolleradapter.h"
#include <algorithm> // For "remove", "find".
#include <sstream>
#include <set>
#include <sstream>
#include <unordered_map>
#include <utility> // For std::move.
@ -138,6 +138,21 @@ RtpTransportControllerAdapter::CreateProxiedRtpTransport(
return result;
}
RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
RtpTransportControllerAdapter::CreateProxiedSrtpTransport(
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp) {
auto result =
RtpTransportAdapter::CreateSrtpProxied(rtcp_parameters, rtp, rtcp, this);
if (result.ok()) {
transport_proxies_.push_back(result.value().get());
transport_proxies_.back()->GetInternal()->SignalDestroyed.connect(
this, &RtpTransportControllerAdapter::OnRtpTransportDestroyed);
}
return result;
}
RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
RtpTransportControllerAdapter::CreateProxiedRtpSender(
cricket::MediaType kind,
@ -605,6 +620,11 @@ RTCError RtpTransportControllerAdapter::AttachAudioSender(
"RtpSender and RtpReceiver is not currently "
"supported.");
}
RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
&remote_audio_description_);
if (!err.ok()) {
return err;
}
// If setting new transport, extract its RTCP parameters and create voice
// channel.
if (!inner_audio_transport_) {
@ -635,6 +655,11 @@ RTCError RtpTransportControllerAdapter::AttachVideoSender(
"RtpSender and RtpReceiver is not currently "
"supported.");
}
RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
&remote_video_description_);
if (!err.ok()) {
return err;
}
// If setting new transport, extract its RTCP parameters and create video
// channel.
if (!inner_video_transport_) {
@ -665,6 +690,11 @@ RTCError RtpTransportControllerAdapter::AttachAudioReceiver(
"RtpReceiver and RtpReceiver is not currently "
"supported.");
}
RTCError err = MaybeSetCryptos(inner_transport, &local_audio_description_,
&remote_audio_description_);
if (!err.ok()) {
return err;
}
// If setting new transport, extract its RTCP parameters and create voice
// channel.
if (!inner_audio_transport_) {
@ -695,6 +725,11 @@ RTCError RtpTransportControllerAdapter::AttachVideoReceiver(
"RtpReceiver and RtpReceiver is not currently "
"supported.");
}
RTCError err = MaybeSetCryptos(inner_transport, &local_video_description_,
&remote_video_description_);
if (!err.ok()) {
return err;
}
// If setting new transport, extract its RTCP parameters and create video
// channel.
if (!inner_video_transport_) {
@ -896,4 +931,25 @@ RtpTransportControllerAdapter::MakeSendStreamParamsVec(
return result;
}
RTCError RtpTransportControllerAdapter::MaybeSetCryptos(
RtpTransportInterface* rtp_transport,
cricket::MediaContentDescription* local_description,
cricket::MediaContentDescription* remote_description) {
if (rtp_transport->GetInternal()->is_srtp_transport()) {
if (!rtp_transport->GetInternal()->send_key() ||
!rtp_transport->GetInternal()->receive_key()) {
LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER,
"The SRTP send key or receive key is not set.")
}
std::vector<cricket::CryptoParams> cryptos;
cryptos.push_back(*(rtp_transport->GetInternal()->receive_key()));
local_description->set_cryptos(cryptos);
cryptos.clear();
cryptos.push_back(*(rtp_transport->GetInternal()->send_key()));
remote_description->set_cryptos(cryptos);
}
return RTCError::OK();
}
} // namespace webrtc

View File

@ -16,18 +16,18 @@
#include <string>
#include <vector>
#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
#include "webrtc/api/ortc/srtptransportinterface.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/sigslot.h"
#include "webrtc/base/thread.h"
#include "webrtc/call/call.h"
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
#include "webrtc/api/ortc/ortcrtpreceiverinterface.h"
#include "webrtc/api/ortc/ortcrtpsenderinterface.h"
#include "webrtc/api/ortc/rtptransportcontrollerinterface.h"
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/media/base/mediachannel.h" // For MediaConfig.
#include "webrtc/pc/channelmanager.h"
#include "webrtc/pc/mediacontroller.h"
#include "webrtc/media/base/mediachannel.h" // For MediaConfig.
namespace webrtc {
@ -81,6 +81,12 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface,
const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp);
RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
CreateProxiedSrtpTransport(const RtcpParameters& rtcp_parameters,
PacketTransportInterface* rtp,
PacketTransportInterface* rtcp);
// |transport_proxy| needs to be a proxy to a transport because the
// application may call GetTransport() on the returned sender or receiver,
// and expects it to return a thread-safe transport proxy.
@ -170,6 +176,13 @@ class RtpTransportControllerAdapter : public RtpTransportControllerInterface,
const std::string& cname,
const cricket::MediaContentDescription& description) const;
// If the |rtp_transport| is a SrtpTransport, set the cryptos of the
// audio/video content descriptions.
RTCError MaybeSetCryptos(
RtpTransportInterface* rtp_transport,
cricket::MediaContentDescription* local_description,
cricket::MediaContentDescription* remote_description);
rtc::Thread* signaling_thread_;
rtc::Thread* worker_thread_;
// |transport_proxies_| and |inner_audio_transport_|/|inner_audio_transport_|

View File

@ -0,0 +1,167 @@
/*
* Copyright 2017 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 <memory>
#include "webrtc/base/gunit.h"
#include "webrtc/media/base/fakemediaengine.h"
#include "webrtc/ortc/ortcfactory.h"
#include "webrtc/ortc/testrtpparameters.h"
#include "webrtc/p2p/base/fakepackettransport.h"
namespace webrtc {
static const char kTestSha1KeyParams1[] =
"inline:WVNfX19zZW1jdGwgKCkgewkyMjA7fQp9CnVubGVz";
static const char kTestSha1KeyParams2[] =
"inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR";
static const char kTestGcmKeyParams3[] =
"inline:e166KFlKzJsGW0d5apX+rrI05vxbrvMJEzFI14aTDCa63IRTlLK4iH66uOI=";
static const cricket::CryptoParams kTestSha1CryptoParams1(
1,
"AES_CM_128_HMAC_SHA1_80",
kTestSha1KeyParams1,
"");
static const cricket::CryptoParams kTestSha1CryptoParams2(
1,
"AES_CM_128_HMAC_SHA1_80",
kTestSha1KeyParams2,
"");
static const cricket::CryptoParams kTestGcmCryptoParams3(1,
"AEAD_AES_256_GCM",
kTestGcmKeyParams3,
"");
// This test uses fake packet transports and a fake media engine, in order to
// test the SrtpTransport at only an API level. Any end-to-end test should go in
// ortcfactory_integrationtest.cc instead.
class SrtpTransportTest : public testing::Test {
public:
SrtpTransportTest() {
fake_media_engine_ = new cricket::FakeMediaEngine();
// Note: This doesn't need to use fake network classes, since it uses
// FakePacketTransports.
auto result = OrtcFactory::Create(
nullptr, nullptr, nullptr, nullptr, nullptr,
std::unique_ptr<cricket::MediaEngineInterface>(fake_media_engine_));
ortc_factory_ = result.MoveValue();
rtp_transport_controller_ =
ortc_factory_->CreateRtpTransportController().MoveValue();
fake_packet_transport_.reset(new rtc::FakePacketTransport("fake"));
auto srtp_transport_result = ortc_factory_->CreateSrtpTransport(
rtcp_parameters_, fake_packet_transport_.get(), nullptr,
rtp_transport_controller_.get());
srtp_transport_ = srtp_transport_result.MoveValue();
}
protected:
// Owned by |ortc_factory_|.
cricket::FakeMediaEngine* fake_media_engine_;
std::unique_ptr<OrtcFactoryInterface> ortc_factory_;
std::unique_ptr<RtpTransportControllerInterface> rtp_transport_controller_;
std::unique_ptr<SrtpTransportInterface> srtp_transport_;
RtcpParameters rtcp_parameters_;
std::unique_ptr<rtc::FakePacketTransport> fake_packet_transport_;
};
// Tests that setting the SRTP send/receive key succeeds.
TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKey) {
EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
srtp_transport_.get());
EXPECT_TRUE(sender_result.ok());
auto receiver_result = ortc_factory_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
EXPECT_TRUE(receiver_result.ok());
}
// Tests that setting the SRTP send/receive key twice is not supported.
TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyTwice) {
EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams2).type());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams1).type());
// Ensure that the senders and receivers can be created despite the previous
// errors.
auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
srtp_transport_.get());
EXPECT_TRUE(sender_result.ok());
auto receiver_result = ortc_factory_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
EXPECT_TRUE(receiver_result.ok());
}
// Test that the SRTP send key and receive key must have the same cipher suite.
TEST_F(SrtpTransportTest, SetSrtpSendAndReceiveKeyDifferentCipherSuite) {
EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_OPERATION,
srtp_transport_->SetSrtpReceiveKey(kTestGcmCryptoParams3).type());
EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
// Ensure that the senders and receivers can be created despite the previous
// error.
auto sender_result = ortc_factory_->CreateRtpSender(cricket::MEDIA_TYPE_AUDIO,
srtp_transport_.get());
EXPECT_TRUE(sender_result.ok());
auto receiver_result = ortc_factory_->CreateRtpReceiver(
cricket::MEDIA_TYPE_AUDIO, srtp_transport_.get());
EXPECT_TRUE(receiver_result.ok());
}
class SrtpTransportTestWithMediaType
: public SrtpTransportTest,
public ::testing::WithParamInterface<cricket::MediaType> {};
// Tests that the senders cannot be created before setting the keys.
TEST_P(SrtpTransportTestWithMediaType, CreateSenderBeforeSettingKeys) {
auto sender_result =
ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
sender_result =
ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER, sender_result.error().type());
EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
// Ensure that after the keys are set, a sender can be created, despite the
// previous errors.
sender_result =
ortc_factory_->CreateRtpSender(GetParam(), srtp_transport_.get());
EXPECT_TRUE(sender_result.ok());
}
// Tests that the receivers cannot be created before setting the keys.
TEST_P(SrtpTransportTestWithMediaType, CreateReceiverBeforeSettingKeys) {
auto receiver_result =
ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
receiver_result.error().type());
EXPECT_TRUE(srtp_transport_->SetSrtpSendKey(kTestSha1CryptoParams1).ok());
receiver_result =
ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
EXPECT_EQ(RTCErrorType::UNSUPPORTED_PARAMETER,
receiver_result.error().type());
EXPECT_TRUE(srtp_transport_->SetSrtpReceiveKey(kTestSha1CryptoParams2).ok());
// Ensure that after the keys are set, a receiver can be created, despite the
// previous errors.
receiver_result =
ortc_factory_->CreateRtpReceiver(GetParam(), srtp_transport_.get());
EXPECT_TRUE(receiver_result.ok());
}
INSTANTIATE_TEST_CASE_P(SenderCreatationTest,
SrtpTransportTestWithMediaType,
::testing::Values(cricket::MEDIA_TYPE_AUDIO,
cricket::MEDIA_TYPE_VIDEO));
} // namespace webrtc