1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  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.
9  */
10 
11 #include "media/base/rtp_data_engine.h"
12 
13 #include <string.h>
14 
15 #include <memory>
16 #include <string>
17 
18 #include "media/base/fake_network_interface.h"
19 #include "media/base/media_constants.h"
20 #include "media/base/rtp_utils.h"
21 #include "rtc_base/copy_on_write_buffer.h"
22 #include "rtc_base/fake_clock.h"
23 #include "rtc_base/third_party/sigslot/sigslot.h"
24 #include "rtc_base/time_utils.h"
25 #include "test/gtest.h"
26 
27 class FakeDataReceiver : public sigslot::has_slots<> {
28  public:
FakeDataReceiver()29   FakeDataReceiver() : has_received_data_(false) {}
30 
OnDataReceived(const cricket::ReceiveDataParams & params,const char * data,size_t len)31   void OnDataReceived(const cricket::ReceiveDataParams& params,
32                       const char* data,
33                       size_t len) {
34     has_received_data_ = true;
35     last_received_data_ = std::string(data, len);
36     last_received_data_len_ = len;
37     last_received_data_params_ = params;
38   }
39 
has_received_data() const40   bool has_received_data() const { return has_received_data_; }
last_received_data() const41   std::string last_received_data() const { return last_received_data_; }
last_received_data_len() const42   size_t last_received_data_len() const { return last_received_data_len_; }
last_received_data_params() const43   cricket::ReceiveDataParams last_received_data_params() const {
44     return last_received_data_params_;
45   }
46 
47  private:
48   bool has_received_data_;
49   std::string last_received_data_;
50   size_t last_received_data_len_;
51   cricket::ReceiveDataParams last_received_data_params_;
52 };
53 
54 class RtpDataMediaChannelTest : public ::testing::Test {
55  protected:
SetUp()56   virtual void SetUp() {
57     // Seed needed for each test to satisfy expectations.
58     iface_.reset(new cricket::FakeNetworkInterface());
59     dme_.reset(CreateEngine());
60     receiver_.reset(new FakeDataReceiver());
61   }
62 
SetNow(double now)63   void SetNow(double now) { clock_.SetTime(webrtc::Timestamp::Seconds(now)); }
64 
CreateEngine()65   cricket::RtpDataEngine* CreateEngine() {
66     cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
67     return dme;
68   }
69 
CreateChannel()70   cricket::RtpDataMediaChannel* CreateChannel() {
71     return CreateChannel(dme_.get());
72   }
73 
CreateChannel(cricket::RtpDataEngine * dme)74   cricket::RtpDataMediaChannel* CreateChannel(cricket::RtpDataEngine* dme) {
75     cricket::MediaConfig config;
76     cricket::RtpDataMediaChannel* channel =
77         static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(config));
78     channel->SetInterface(iface_.get());
79     channel->SignalDataReceived.connect(receiver_.get(),
80                                         &FakeDataReceiver::OnDataReceived);
81     return channel;
82   }
83 
receiver()84   FakeDataReceiver* receiver() { return receiver_.get(); }
85 
HasReceivedData()86   bool HasReceivedData() { return receiver_->has_received_data(); }
87 
GetReceivedData()88   std::string GetReceivedData() { return receiver_->last_received_data(); }
89 
GetReceivedDataLen()90   size_t GetReceivedDataLen() { return receiver_->last_received_data_len(); }
91 
GetReceivedDataParams()92   cricket::ReceiveDataParams GetReceivedDataParams() {
93     return receiver_->last_received_data_params();
94   }
95 
HasSentData(int count)96   bool HasSentData(int count) { return (iface_->NumRtpPackets() > count); }
97 
GetSentData(int index)98   std::string GetSentData(int index) {
99     // Assume RTP header of length 12
100     std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
101         iface_->GetRtpPacket(index));
102     if (packet->size() > 12) {
103       return std::string(packet->data<char>() + 12, packet->size() - 12);
104     } else {
105       return "";
106     }
107   }
108 
GetSentDataHeader(int index)109   cricket::RtpHeader GetSentDataHeader(int index) {
110     std::unique_ptr<const rtc::CopyOnWriteBuffer> packet(
111         iface_->GetRtpPacket(index));
112     cricket::RtpHeader header;
113     GetRtpHeader(packet->data(), packet->size(), &header);
114     return header;
115   }
116 
117  private:
118   std::unique_ptr<cricket::RtpDataEngine> dme_;
119   rtc::ScopedFakeClock clock_;
120   std::unique_ptr<cricket::FakeNetworkInterface> iface_;
121   std::unique_ptr<FakeDataReceiver> receiver_;
122 };
123 
TEST_F(RtpDataMediaChannelTest,SetUnknownCodecs)124 TEST_F(RtpDataMediaChannelTest, SetUnknownCodecs) {
125   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
126 
127   cricket::DataCodec known_codec;
128   known_codec.id = 103;
129   known_codec.name = "google-data";
130   cricket::DataCodec unknown_codec;
131   unknown_codec.id = 104;
132   unknown_codec.name = "unknown-data";
133 
134   cricket::DataSendParameters send_parameters_known;
135   send_parameters_known.codecs.push_back(known_codec);
136   cricket::DataRecvParameters recv_parameters_known;
137   recv_parameters_known.codecs.push_back(known_codec);
138 
139   cricket::DataSendParameters send_parameters_unknown;
140   send_parameters_unknown.codecs.push_back(unknown_codec);
141   cricket::DataRecvParameters recv_parameters_unknown;
142   recv_parameters_unknown.codecs.push_back(unknown_codec);
143 
144   cricket::DataSendParameters send_parameters_mixed;
145   send_parameters_mixed.codecs.push_back(known_codec);
146   send_parameters_mixed.codecs.push_back(unknown_codec);
147   cricket::DataRecvParameters recv_parameters_mixed;
148   recv_parameters_mixed.codecs.push_back(known_codec);
149   recv_parameters_mixed.codecs.push_back(unknown_codec);
150 
151   EXPECT_TRUE(dmc->SetSendParameters(send_parameters_known));
152   EXPECT_FALSE(dmc->SetSendParameters(send_parameters_unknown));
153   EXPECT_TRUE(dmc->SetSendParameters(send_parameters_mixed));
154   EXPECT_TRUE(dmc->SetRecvParameters(recv_parameters_known));
155   EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_unknown));
156   EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_mixed));
157 }
158 
TEST_F(RtpDataMediaChannelTest,AddRemoveSendStream)159 TEST_F(RtpDataMediaChannelTest, AddRemoveSendStream) {
160   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
161 
162   cricket::StreamParams stream1;
163   stream1.add_ssrc(41);
164   EXPECT_TRUE(dmc->AddSendStream(stream1));
165   cricket::StreamParams stream2;
166   stream2.add_ssrc(42);
167   EXPECT_TRUE(dmc->AddSendStream(stream2));
168 
169   EXPECT_TRUE(dmc->RemoveSendStream(41));
170   EXPECT_TRUE(dmc->RemoveSendStream(42));
171   EXPECT_FALSE(dmc->RemoveSendStream(43));
172 }
173 
TEST_F(RtpDataMediaChannelTest,AddRemoveRecvStream)174 TEST_F(RtpDataMediaChannelTest, AddRemoveRecvStream) {
175   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
176 
177   cricket::StreamParams stream1;
178   stream1.add_ssrc(41);
179   EXPECT_TRUE(dmc->AddRecvStream(stream1));
180   cricket::StreamParams stream2;
181   stream2.add_ssrc(42);
182   EXPECT_TRUE(dmc->AddRecvStream(stream2));
183   EXPECT_FALSE(dmc->AddRecvStream(stream2));
184 
185   EXPECT_TRUE(dmc->RemoveRecvStream(41));
186   EXPECT_TRUE(dmc->RemoveRecvStream(42));
187 }
188 
TEST_F(RtpDataMediaChannelTest,SendData)189 TEST_F(RtpDataMediaChannelTest, SendData) {
190   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
191 
192   cricket::SendDataParams params;
193   params.ssrc = 42;
194   unsigned char data[] = "food";
195   rtc::CopyOnWriteBuffer payload(data, 4);
196   unsigned char padded_data[] = {
197       0x00, 0x00, 0x00, 0x00, 'f', 'o', 'o', 'd',
198   };
199   cricket::SendDataResult result;
200 
201   // Not sending
202   EXPECT_FALSE(dmc->SendData(params, payload, &result));
203   EXPECT_EQ(cricket::SDR_ERROR, result);
204   EXPECT_FALSE(HasSentData(0));
205   ASSERT_TRUE(dmc->SetSend(true));
206 
207   // Unknown stream name.
208   EXPECT_FALSE(dmc->SendData(params, payload, &result));
209   EXPECT_EQ(cricket::SDR_ERROR, result);
210   EXPECT_FALSE(HasSentData(0));
211 
212   cricket::StreamParams stream;
213   stream.add_ssrc(42);
214   ASSERT_TRUE(dmc->AddSendStream(stream));
215 
216   // Unknown codec;
217   EXPECT_FALSE(dmc->SendData(params, payload, &result));
218   EXPECT_EQ(cricket::SDR_ERROR, result);
219   EXPECT_FALSE(HasSentData(0));
220 
221   cricket::DataCodec codec;
222   codec.id = 103;
223   codec.name = cricket::kGoogleRtpDataCodecName;
224   cricket::DataSendParameters parameters;
225   parameters.codecs.push_back(codec);
226   ASSERT_TRUE(dmc->SetSendParameters(parameters));
227 
228   // Length too large;
229   std::string x10000(10000, 'x');
230   EXPECT_FALSE(dmc->SendData(
231       params, rtc::CopyOnWriteBuffer(x10000.data(), x10000.length()), &result));
232   EXPECT_EQ(cricket::SDR_ERROR, result);
233   EXPECT_FALSE(HasSentData(0));
234 
235   // Finally works!
236   EXPECT_TRUE(dmc->SendData(params, payload, &result));
237   EXPECT_EQ(cricket::SDR_SUCCESS, result);
238   ASSERT_TRUE(HasSentData(0));
239   EXPECT_EQ(sizeof(padded_data), GetSentData(0).length());
240   EXPECT_EQ(0, memcmp(padded_data, GetSentData(0).data(), sizeof(padded_data)));
241   cricket::RtpHeader header0 = GetSentDataHeader(0);
242   EXPECT_NE(0, header0.seq_num);
243   EXPECT_NE(0U, header0.timestamp);
244   EXPECT_EQ(header0.ssrc, 42U);
245   EXPECT_EQ(header0.payload_type, 103);
246 
247   // Should bump timestamp by 180000 because the clock rate is 90khz.
248   SetNow(2);
249 
250   EXPECT_TRUE(dmc->SendData(params, payload, &result));
251   ASSERT_TRUE(HasSentData(1));
252   EXPECT_EQ(sizeof(padded_data), GetSentData(1).length());
253   EXPECT_EQ(0, memcmp(padded_data, GetSentData(1).data(), sizeof(padded_data)));
254   cricket::RtpHeader header1 = GetSentDataHeader(1);
255   EXPECT_EQ(header1.ssrc, 42U);
256   EXPECT_EQ(header1.payload_type, 103);
257   EXPECT_EQ(static_cast<uint16_t>(header0.seq_num + 1),
258             static_cast<uint16_t>(header1.seq_num));
259   EXPECT_EQ(header0.timestamp + 180000, header1.timestamp);
260 }
261 
TEST_F(RtpDataMediaChannelTest,SendDataRate)262 TEST_F(RtpDataMediaChannelTest, SendDataRate) {
263   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
264 
265   ASSERT_TRUE(dmc->SetSend(true));
266 
267   cricket::DataCodec codec;
268   codec.id = 103;
269   codec.name = cricket::kGoogleRtpDataCodecName;
270   cricket::DataSendParameters parameters;
271   parameters.codecs.push_back(codec);
272   ASSERT_TRUE(dmc->SetSendParameters(parameters));
273 
274   cricket::StreamParams stream;
275   stream.add_ssrc(42);
276   ASSERT_TRUE(dmc->AddSendStream(stream));
277 
278   cricket::SendDataParams params;
279   params.ssrc = 42;
280   unsigned char data[] = "food";
281   rtc::CopyOnWriteBuffer payload(data, 4);
282   cricket::SendDataResult result;
283 
284   // With rtp overhead of 32 bytes, each one of our packets is 36
285   // bytes, or 288 bits.  So, a limit of 872bps will allow 3 packets,
286   // but not four.
287   parameters.max_bandwidth_bps = 872;
288   ASSERT_TRUE(dmc->SetSendParameters(parameters));
289 
290   EXPECT_TRUE(dmc->SendData(params, payload, &result));
291   EXPECT_TRUE(dmc->SendData(params, payload, &result));
292   EXPECT_TRUE(dmc->SendData(params, payload, &result));
293   EXPECT_FALSE(dmc->SendData(params, payload, &result));
294   EXPECT_FALSE(dmc->SendData(params, payload, &result));
295 
296   SetNow(0.9);
297   EXPECT_FALSE(dmc->SendData(params, payload, &result));
298 
299   SetNow(1.1);
300   EXPECT_TRUE(dmc->SendData(params, payload, &result));
301   EXPECT_TRUE(dmc->SendData(params, payload, &result));
302   SetNow(1.9);
303   EXPECT_TRUE(dmc->SendData(params, payload, &result));
304 
305   SetNow(2.2);
306   EXPECT_TRUE(dmc->SendData(params, payload, &result));
307   EXPECT_TRUE(dmc->SendData(params, payload, &result));
308   EXPECT_TRUE(dmc->SendData(params, payload, &result));
309   EXPECT_FALSE(dmc->SendData(params, payload, &result));
310 }
311 
TEST_F(RtpDataMediaChannelTest,ReceiveData)312 TEST_F(RtpDataMediaChannelTest, ReceiveData) {
313   // PT= 103, SN=2, TS=3, SSRC = 4, data = "abcde"
314   unsigned char data[] = {0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00,
315                           0x03, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00,
316                           0x00, 0x00, 'a',  'b',  'c',  'd',  'e'};
317   rtc::CopyOnWriteBuffer packet(data, sizeof(data));
318 
319   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
320 
321   // SetReceived not called.
322   dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
323   EXPECT_FALSE(HasReceivedData());
324 
325   dmc->SetReceive(true);
326 
327   // Unknown payload id
328   dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
329   EXPECT_FALSE(HasReceivedData());
330 
331   cricket::DataCodec codec;
332   codec.id = 103;
333   codec.name = cricket::kGoogleRtpDataCodecName;
334   cricket::DataRecvParameters parameters;
335   parameters.codecs.push_back(codec);
336   ASSERT_TRUE(dmc->SetRecvParameters(parameters));
337 
338   // Unknown stream
339   dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
340   EXPECT_FALSE(HasReceivedData());
341 
342   cricket::StreamParams stream;
343   stream.add_ssrc(42);
344   ASSERT_TRUE(dmc->AddRecvStream(stream));
345 
346   // Finally works!
347   dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
348   EXPECT_TRUE(HasReceivedData());
349   EXPECT_EQ("abcde", GetReceivedData());
350   EXPECT_EQ(5U, GetReceivedDataLen());
351 }
352 
TEST_F(RtpDataMediaChannelTest,InvalidRtpPackets)353 TEST_F(RtpDataMediaChannelTest, InvalidRtpPackets) {
354   unsigned char data[] = {0x80, 0x65, 0x00, 0x02};
355   rtc::CopyOnWriteBuffer packet(data, sizeof(data));
356 
357   std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
358 
359   // Too short
360   dmc->OnPacketReceived(packet, /* packet_time_us */ -1);
361   EXPECT_FALSE(HasReceivedData());
362 }
363