blob: cd11eb5cbd6d2e94f86b86359bf58f1d300f9ce0 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "media/base/rtp_data_engine.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
kwiberg686a8ef2016-02-26 03:00:35 -080015#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000016#include <string>
17
Anton Sukhanov4f08faa2019-05-21 11:12:57 -070018#include "api/media_transport_config.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "media/base/fake_network_interface.h"
20#include "media/base/media_constants.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "media/base/rtp_utils.h"
22#include "rtc_base/copy_on_write_buffer.h"
23#include "rtc_base/fake_clock.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#include "rtc_base/third_party/sigslot/sigslot.h"
Steve Anton10542f22019-01-11 09:11:00 -080025#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010026#include "test/gtest.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000027
henrike@webrtc.org28e20752013-07-10 00:45:36 +000028class FakeDataReceiver : public sigslot::has_slots<> {
29 public:
30 FakeDataReceiver() : has_received_data_(false) {}
31
Yves Gerey665174f2018-06-19 15:03:05 +020032 void OnDataReceived(const cricket::ReceiveDataParams& params,
33 const char* data,
34 size_t len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000035 has_received_data_ = true;
36 last_received_data_ = std::string(data, len);
37 last_received_data_len_ = len;
38 last_received_data_params_ = params;
39 }
40
41 bool has_received_data() const { return has_received_data_; }
42 std::string last_received_data() const { return last_received_data_; }
43 size_t last_received_data_len() const { return last_received_data_len_; }
44 cricket::ReceiveDataParams last_received_data_params() const {
45 return last_received_data_params_;
46 }
47
48 private:
49 bool has_received_data_;
50 std::string last_received_data_;
51 size_t last_received_data_len_;
52 cricket::ReceiveDataParams last_received_data_params_;
53};
54
Mirko Bonadei6a489f22019-04-09 15:11:12 +020055class RtpDataMediaChannelTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056 protected:
57 virtual void SetUp() {
58 // Seed needed for each test to satisfy expectations.
59 iface_.reset(new cricket::FakeNetworkInterface());
nissecdf37a92016-09-13 23:41:47 -070060 dme_.reset(CreateEngine());
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061 receiver_.reset(new FakeDataReceiver());
62 }
63
Sebastian Janssond624c392019-04-17 10:36:03 +020064 void SetNow(double now) { clock_.SetTime(webrtc::Timestamp::seconds(now)); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
nissecdf37a92016-09-13 23:41:47 -070066 cricket::RtpDataEngine* CreateEngine() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067 cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068 return dme;
69 }
70
71 cricket::RtpDataMediaChannel* CreateChannel() {
72 return CreateChannel(dme_.get());
73 }
74
75 cricket::RtpDataMediaChannel* CreateChannel(cricket::RtpDataEngine* dme) {
zhihuangebbe4f22016-12-06 10:45:42 -080076 cricket::MediaConfig config;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077 cricket::RtpDataMediaChannel* channel =
deadbeef953c2ce2017-01-09 14:53:41 -080078 static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(config));
Anton Sukhanov316f3ac2019-05-23 15:50:38 -070079 channel->SetInterface(iface_.get(), webrtc::MediaTransportConfig());
Yves Gerey665174f2018-06-19 15:03:05 +020080 channel->SignalDataReceived.connect(receiver_.get(),
81 &FakeDataReceiver::OnDataReceived);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082 return channel;
83 }
84
Yves Gerey665174f2018-06-19 15:03:05 +020085 FakeDataReceiver* receiver() { return receiver_.get(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086
Yves Gerey665174f2018-06-19 15:03:05 +020087 bool HasReceivedData() { return receiver_->has_received_data(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088
Yves Gerey665174f2018-06-19 15:03:05 +020089 std::string GetReceivedData() { return receiver_->last_received_data(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
Yves Gerey665174f2018-06-19 15:03:05 +020091 size_t GetReceivedDataLen() { return receiver_->last_received_data_len(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092
93 cricket::ReceiveDataParams GetReceivedDataParams() {
94 return receiver_->last_received_data_params();
95 }
96
Yves Gerey665174f2018-06-19 15:03:05 +020097 bool HasSentData(int count) { return (iface_->NumRtpPackets() > count); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098
99 std::string GetSentData(int index) {
100 // Assume RTP header of length 12
jbaucheec21bd2016-03-20 06:15:43 -0700101 std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
henrike@webrtc.org9de257d2013-07-17 14:42:53 +0000102 iface_->GetRtpPacket(index));
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000103 if (packet->size() > 12) {
Karl Wiberg94784372015-04-20 14:03:07 +0200104 return std::string(packet->data<char>() + 12, packet->size() - 12);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105 } else {
106 return "";
107 }
108 }
109
110 cricket::RtpHeader GetSentDataHeader(int index) {
jbaucheec21bd2016-03-20 06:15:43 -0700111 std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
henrike@webrtc.org9de257d2013-07-17 14:42:53 +0000112 iface_->GetRtpPacket(index));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113 cricket::RtpHeader header;
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +0000114 GetRtpHeader(packet->data(), packet->size(), &header);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 return header;
116 }
117
118 private:
kwiberg686a8ef2016-02-26 03:00:35 -0800119 std::unique_ptr<cricket::RtpDataEngine> dme_;
nissecdf37a92016-09-13 23:41:47 -0700120 rtc::ScopedFakeClock clock_;
kwiberg686a8ef2016-02-26 03:00:35 -0800121 std::unique_ptr<cricket::FakeNetworkInterface> iface_;
122 std::unique_ptr<FakeDataReceiver> receiver_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123};
124
125TEST_F(RtpDataMediaChannelTest, SetUnknownCodecs) {
kwiberg686a8ef2016-02-26 03:00:35 -0800126 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
128 cricket::DataCodec known_codec;
129 known_codec.id = 103;
130 known_codec.name = "google-data";
131 cricket::DataCodec unknown_codec;
132 unknown_codec.id = 104;
133 unknown_codec.name = "unknown-data";
134
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200135 cricket::DataSendParameters send_parameters_known;
136 send_parameters_known.codecs.push_back(known_codec);
137 cricket::DataRecvParameters recv_parameters_known;
138 recv_parameters_known.codecs.push_back(known_codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200140 cricket::DataSendParameters send_parameters_unknown;
141 send_parameters_unknown.codecs.push_back(unknown_codec);
142 cricket::DataRecvParameters recv_parameters_unknown;
143 recv_parameters_unknown.codecs.push_back(unknown_codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000144
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200145 cricket::DataSendParameters send_parameters_mixed;
146 send_parameters_mixed.codecs.push_back(known_codec);
147 send_parameters_mixed.codecs.push_back(unknown_codec);
148 cricket::DataRecvParameters recv_parameters_mixed;
149 recv_parameters_mixed.codecs.push_back(known_codec);
150 recv_parameters_mixed.codecs.push_back(unknown_codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200152 EXPECT_TRUE(dmc->SetSendParameters(send_parameters_known));
153 EXPECT_FALSE(dmc->SetSendParameters(send_parameters_unknown));
154 EXPECT_TRUE(dmc->SetSendParameters(send_parameters_mixed));
155 EXPECT_TRUE(dmc->SetRecvParameters(recv_parameters_known));
156 EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_unknown));
157 EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_mixed));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158}
159
160TEST_F(RtpDataMediaChannelTest, AddRemoveSendStream) {
kwiberg686a8ef2016-02-26 03:00:35 -0800161 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162
163 cricket::StreamParams stream1;
164 stream1.add_ssrc(41);
165 EXPECT_TRUE(dmc->AddSendStream(stream1));
166 cricket::StreamParams stream2;
167 stream2.add_ssrc(42);
168 EXPECT_TRUE(dmc->AddSendStream(stream2));
169
170 EXPECT_TRUE(dmc->RemoveSendStream(41));
171 EXPECT_TRUE(dmc->RemoveSendStream(42));
172 EXPECT_FALSE(dmc->RemoveSendStream(43));
173}
174
175TEST_F(RtpDataMediaChannelTest, AddRemoveRecvStream) {
kwiberg686a8ef2016-02-26 03:00:35 -0800176 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177
178 cricket::StreamParams stream1;
179 stream1.add_ssrc(41);
180 EXPECT_TRUE(dmc->AddRecvStream(stream1));
181 cricket::StreamParams stream2;
182 stream2.add_ssrc(42);
183 EXPECT_TRUE(dmc->AddRecvStream(stream2));
184 EXPECT_FALSE(dmc->AddRecvStream(stream2));
185
186 EXPECT_TRUE(dmc->RemoveRecvStream(41));
187 EXPECT_TRUE(dmc->RemoveRecvStream(42));
188}
189
190TEST_F(RtpDataMediaChannelTest, SendData) {
kwiberg686a8ef2016-02-26 03:00:35 -0800191 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192
193 cricket::SendDataParams params;
194 params.ssrc = 42;
195 unsigned char data[] = "food";
jbaucheec21bd2016-03-20 06:15:43 -0700196 rtc::CopyOnWriteBuffer payload(data, 4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197 unsigned char padded_data[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200198 0x00, 0x00, 0x00, 0x00, 'f', 'o', 'o', 'd',
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199 };
200 cricket::SendDataResult result;
201
202 // Not sending
203 EXPECT_FALSE(dmc->SendData(params, payload, &result));
204 EXPECT_EQ(cricket::SDR_ERROR, result);
205 EXPECT_FALSE(HasSentData(0));
206 ASSERT_TRUE(dmc->SetSend(true));
207
208 // Unknown stream name.
209 EXPECT_FALSE(dmc->SendData(params, payload, &result));
210 EXPECT_EQ(cricket::SDR_ERROR, result);
211 EXPECT_FALSE(HasSentData(0));
212
213 cricket::StreamParams stream;
214 stream.add_ssrc(42);
215 ASSERT_TRUE(dmc->AddSendStream(stream));
216
217 // Unknown codec;
218 EXPECT_FALSE(dmc->SendData(params, payload, &result));
219 EXPECT_EQ(cricket::SDR_ERROR, result);
220 EXPECT_FALSE(HasSentData(0));
221
222 cricket::DataCodec codec;
223 codec.id = 103;
224 codec.name = cricket::kGoogleRtpDataCodecName;
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200225 cricket::DataSendParameters parameters;
226 parameters.codecs.push_back(codec);
227 ASSERT_TRUE(dmc->SetSendParameters(parameters));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228
229 // Length too large;
230 std::string x10000(10000, 'x');
231 EXPECT_FALSE(dmc->SendData(
jbaucheec21bd2016-03-20 06:15:43 -0700232 params, rtc::CopyOnWriteBuffer(x10000.data(), x10000.length()), &result));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233 EXPECT_EQ(cricket::SDR_ERROR, result);
234 EXPECT_FALSE(HasSentData(0));
235
236 // Finally works!
237 EXPECT_TRUE(dmc->SendData(params, payload, &result));
238 EXPECT_EQ(cricket::SDR_SUCCESS, result);
239 ASSERT_TRUE(HasSentData(0));
240 EXPECT_EQ(sizeof(padded_data), GetSentData(0).length());
Yves Gerey665174f2018-06-19 15:03:05 +0200241 EXPECT_EQ(0, memcmp(padded_data, GetSentData(0).data(), sizeof(padded_data)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242 cricket::RtpHeader header0 = GetSentDataHeader(0);
243 EXPECT_NE(0, header0.seq_num);
244 EXPECT_NE(0U, header0.timestamp);
245 EXPECT_EQ(header0.ssrc, 42U);
246 EXPECT_EQ(header0.payload_type, 103);
247
248 // Should bump timestamp by 180000 because the clock rate is 90khz.
249 SetNow(2);
250
251 EXPECT_TRUE(dmc->SendData(params, payload, &result));
252 ASSERT_TRUE(HasSentData(1));
253 EXPECT_EQ(sizeof(padded_data), GetSentData(1).length());
Yves Gerey665174f2018-06-19 15:03:05 +0200254 EXPECT_EQ(0, memcmp(padded_data, GetSentData(1).data(), sizeof(padded_data)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 cricket::RtpHeader header1 = GetSentDataHeader(1);
256 EXPECT_EQ(header1.ssrc, 42U);
257 EXPECT_EQ(header1.payload_type, 103);
Peter Boström0c4e06b2015-10-07 12:23:21 +0200258 EXPECT_EQ(static_cast<uint16_t>(header0.seq_num + 1),
259 static_cast<uint16_t>(header1.seq_num));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260 EXPECT_EQ(header0.timestamp + 180000, header1.timestamp);
261}
262
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263TEST_F(RtpDataMediaChannelTest, SendDataRate) {
kwiberg686a8ef2016-02-26 03:00:35 -0800264 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265
266 ASSERT_TRUE(dmc->SetSend(true));
267
268 cricket::DataCodec codec;
269 codec.id = 103;
270 codec.name = cricket::kGoogleRtpDataCodecName;
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200271 cricket::DataSendParameters parameters;
272 parameters.codecs.push_back(codec);
273 ASSERT_TRUE(dmc->SetSendParameters(parameters));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274
275 cricket::StreamParams stream;
276 stream.add_ssrc(42);
277 ASSERT_TRUE(dmc->AddSendStream(stream));
278
279 cricket::SendDataParams params;
280 params.ssrc = 42;
281 unsigned char data[] = "food";
jbaucheec21bd2016-03-20 06:15:43 -0700282 rtc::CopyOnWriteBuffer payload(data, 4);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 cricket::SendDataResult result;
284
285 // With rtp overhead of 32 bytes, each one of our packets is 36
286 // bytes, or 288 bits. So, a limit of 872bps will allow 3 packets,
287 // but not four.
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200288 parameters.max_bandwidth_bps = 872;
289 ASSERT_TRUE(dmc->SetSendParameters(parameters));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000290
291 EXPECT_TRUE(dmc->SendData(params, payload, &result));
292 EXPECT_TRUE(dmc->SendData(params, payload, &result));
293 EXPECT_TRUE(dmc->SendData(params, payload, &result));
294 EXPECT_FALSE(dmc->SendData(params, payload, &result));
295 EXPECT_FALSE(dmc->SendData(params, payload, &result));
296
297 SetNow(0.9);
298 EXPECT_FALSE(dmc->SendData(params, payload, &result));
299
300 SetNow(1.1);
301 EXPECT_TRUE(dmc->SendData(params, payload, &result));
302 EXPECT_TRUE(dmc->SendData(params, payload, &result));
303 SetNow(1.9);
304 EXPECT_TRUE(dmc->SendData(params, payload, &result));
305
306 SetNow(2.2);
307 EXPECT_TRUE(dmc->SendData(params, payload, &result));
308 EXPECT_TRUE(dmc->SendData(params, payload, &result));
309 EXPECT_TRUE(dmc->SendData(params, payload, &result));
310 EXPECT_FALSE(dmc->SendData(params, payload, &result));
311}
312
313TEST_F(RtpDataMediaChannelTest, ReceiveData) {
314 // PT= 103, SN=2, TS=3, SSRC = 4, data = "abcde"
Yves Gerey665174f2018-06-19 15:03:05 +0200315 unsigned char data[] = {0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00,
316 0x03, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00,
317 0x00, 0x00, 'a', 'b', 'c', 'd', 'e'};
jbaucheec21bd2016-03-20 06:15:43 -0700318 rtc::CopyOnWriteBuffer packet(data, sizeof(data));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319
kwiberg686a8ef2016-02-26 03:00:35 -0800320 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321
322 // SetReceived not called.
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700323 dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 EXPECT_FALSE(HasReceivedData());
325
326 dmc->SetReceive(true);
327
328 // Unknown payload id
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700329 dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000330 EXPECT_FALSE(HasReceivedData());
331
332 cricket::DataCodec codec;
333 codec.id = 103;
334 codec.name = cricket::kGoogleRtpDataCodecName;
Fredrik Solenbergb071a192015-09-17 16:42:56 +0200335 cricket::DataRecvParameters parameters;
336 parameters.codecs.push_back(codec);
337 ASSERT_TRUE(dmc->SetRecvParameters(parameters));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338
339 // Unknown stream
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700340 dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000341 EXPECT_FALSE(HasReceivedData());
342
343 cricket::StreamParams stream;
344 stream.add_ssrc(42);
345 ASSERT_TRUE(dmc->AddRecvStream(stream));
346
347 // Finally works!
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700348 dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 EXPECT_TRUE(HasReceivedData());
350 EXPECT_EQ("abcde", GetReceivedData());
351 EXPECT_EQ(5U, GetReceivedDataLen());
352}
353
354TEST_F(RtpDataMediaChannelTest, InvalidRtpPackets) {
Yves Gerey665174f2018-06-19 15:03:05 +0200355 unsigned char data[] = {0x80, 0x65, 0x00, 0x02};
jbaucheec21bd2016-03-20 06:15:43 -0700356 rtc::CopyOnWriteBuffer packet(data, sizeof(data));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357
kwiberg686a8ef2016-02-26 03:00:35 -0800358 std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359
360 // Too short
Amit Hilbuche7a5f7b2019-03-12 11:10:27 -0700361 dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 EXPECT_FALSE(HasReceivedData());
363}