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