• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2012 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <string>
29 
30 #include "talk/media/base/constants.h"
31 #include "talk/media/base/fakenetworkinterface.h"
32 #include "talk/media/base/rtpdataengine.h"
33 #include "talk/media/base/rtputils.h"
34 #include "webrtc/base/buffer.h"
35 #include "webrtc/base/gunit.h"
36 #include "webrtc/base/helpers.h"
37 #include "webrtc/base/scoped_ptr.h"
38 #include "webrtc/base/ssladapter.h"
39 #include "webrtc/base/timing.h"
40 
41 class FakeTiming : public rtc::Timing {
42  public:
FakeTiming()43   FakeTiming() : now_(0.0) {}
44 
TimerNow()45   virtual double TimerNow() {
46     return now_;
47   }
48 
set_now(double now)49   void set_now(double now) {
50     now_ = now;
51   }
52 
53  private:
54   double now_;
55 };
56 
57 class FakeDataReceiver : public sigslot::has_slots<> {
58  public:
FakeDataReceiver()59   FakeDataReceiver() : has_received_data_(false) {}
60 
OnDataReceived(const cricket::ReceiveDataParams & params,const char * data,size_t len)61   void OnDataReceived(
62       const cricket::ReceiveDataParams& params,
63       const char* data, size_t len) {
64     has_received_data_ = true;
65     last_received_data_ = std::string(data, len);
66     last_received_data_len_ = len;
67     last_received_data_params_ = params;
68   }
69 
has_received_data() const70   bool has_received_data() const { return has_received_data_; }
last_received_data() const71   std::string last_received_data() const { return last_received_data_; }
last_received_data_len() const72   size_t last_received_data_len() const { return last_received_data_len_; }
last_received_data_params() const73   cricket::ReceiveDataParams last_received_data_params() const {
74     return last_received_data_params_;
75   }
76 
77  private:
78   bool has_received_data_;
79   std::string last_received_data_;
80   size_t last_received_data_len_;
81   cricket::ReceiveDataParams last_received_data_params_;
82 };
83 
84 class RtpDataMediaChannelTest : public testing::Test {
85  protected:
SetUp()86   virtual void SetUp() {
87     // Seed needed for each test to satisfy expectations.
88     iface_.reset(new cricket::FakeNetworkInterface());
89     timing_ = new FakeTiming();
90     dme_.reset(CreateEngine(timing_));
91     receiver_.reset(new FakeDataReceiver());
92   }
93 
SetNow(double now)94   void SetNow(double now) {
95     timing_->set_now(now);
96   }
97 
CreateEngine(FakeTiming * timing)98   cricket::RtpDataEngine* CreateEngine(FakeTiming* timing) {
99     cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
100     dme->SetTiming(timing);
101     return dme;
102   }
103 
CreateChannel()104   cricket::RtpDataMediaChannel* CreateChannel() {
105     return CreateChannel(dme_.get());
106   }
107 
CreateChannel(cricket::RtpDataEngine * dme)108   cricket::RtpDataMediaChannel* CreateChannel(cricket::RtpDataEngine* dme) {
109     cricket::RtpDataMediaChannel* channel =
110         static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(
111             cricket::DCT_RTP));
112     channel->SetInterface(iface_.get());
113     channel->SignalDataReceived.connect(
114         receiver_.get(), &FakeDataReceiver::OnDataReceived);
115     return channel;
116   }
117 
receiver()118   FakeDataReceiver* receiver() {
119     return receiver_.get();
120   }
121 
HasReceivedData()122   bool HasReceivedData() {
123     return receiver_->has_received_data();
124   }
125 
GetReceivedData()126   std::string GetReceivedData() {
127     return receiver_->last_received_data();
128   }
129 
GetReceivedDataLen()130   size_t GetReceivedDataLen() {
131     return receiver_->last_received_data_len();
132   }
133 
GetReceivedDataParams()134   cricket::ReceiveDataParams GetReceivedDataParams() {
135     return receiver_->last_received_data_params();
136   }
137 
HasSentData(int count)138   bool HasSentData(int count) {
139     return (iface_->NumRtpPackets() > count);
140   }
141 
GetSentData(int index)142   std::string GetSentData(int index) {
143     // Assume RTP header of length 12
144     rtc::scoped_ptr<const rtc::Buffer> packet(
145         iface_->GetRtpPacket(index));
146     if (packet->size() > 12) {
147       return std::string(packet->data<char>() + 12, packet->size() - 12);
148     } else {
149       return "";
150     }
151   }
152 
GetSentDataHeader(int index)153   cricket::RtpHeader GetSentDataHeader(int index) {
154     rtc::scoped_ptr<const rtc::Buffer> packet(
155         iface_->GetRtpPacket(index));
156     cricket::RtpHeader header;
157     GetRtpHeader(packet->data(), packet->size(), &header);
158     return header;
159   }
160 
161  private:
162   rtc::scoped_ptr<cricket::RtpDataEngine> dme_;
163   // Timing passed into dme_.  Owned by dme_;
164   FakeTiming* timing_;
165   rtc::scoped_ptr<cricket::FakeNetworkInterface> iface_;
166   rtc::scoped_ptr<FakeDataReceiver> receiver_;
167 };
168 
TEST_F(RtpDataMediaChannelTest,SetUnknownCodecs)169 TEST_F(RtpDataMediaChannelTest, SetUnknownCodecs) {
170   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
171 
172   cricket::DataCodec known_codec;
173   known_codec.id = 103;
174   known_codec.name = "google-data";
175   cricket::DataCodec unknown_codec;
176   unknown_codec.id = 104;
177   unknown_codec.name = "unknown-data";
178 
179   cricket::DataSendParameters send_parameters_known;
180   send_parameters_known.codecs.push_back(known_codec);
181   cricket::DataRecvParameters recv_parameters_known;
182   recv_parameters_known.codecs.push_back(known_codec);
183 
184   cricket::DataSendParameters send_parameters_unknown;
185   send_parameters_unknown.codecs.push_back(unknown_codec);
186   cricket::DataRecvParameters recv_parameters_unknown;
187   recv_parameters_unknown.codecs.push_back(unknown_codec);
188 
189   cricket::DataSendParameters send_parameters_mixed;
190   send_parameters_mixed.codecs.push_back(known_codec);
191   send_parameters_mixed.codecs.push_back(unknown_codec);
192   cricket::DataRecvParameters recv_parameters_mixed;
193   recv_parameters_mixed.codecs.push_back(known_codec);
194   recv_parameters_mixed.codecs.push_back(unknown_codec);
195 
196   EXPECT_TRUE(dmc->SetSendParameters(send_parameters_known));
197   EXPECT_FALSE(dmc->SetSendParameters(send_parameters_unknown));
198   EXPECT_TRUE(dmc->SetSendParameters(send_parameters_mixed));
199   EXPECT_TRUE(dmc->SetRecvParameters(recv_parameters_known));
200   EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_unknown));
201   EXPECT_FALSE(dmc->SetRecvParameters(recv_parameters_mixed));
202 }
203 
TEST_F(RtpDataMediaChannelTest,AddRemoveSendStream)204 TEST_F(RtpDataMediaChannelTest, AddRemoveSendStream) {
205   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
206 
207   cricket::StreamParams stream1;
208   stream1.add_ssrc(41);
209   EXPECT_TRUE(dmc->AddSendStream(stream1));
210   cricket::StreamParams stream2;
211   stream2.add_ssrc(42);
212   EXPECT_TRUE(dmc->AddSendStream(stream2));
213 
214   EXPECT_TRUE(dmc->RemoveSendStream(41));
215   EXPECT_TRUE(dmc->RemoveSendStream(42));
216   EXPECT_FALSE(dmc->RemoveSendStream(43));
217 }
218 
TEST_F(RtpDataMediaChannelTest,AddRemoveRecvStream)219 TEST_F(RtpDataMediaChannelTest, AddRemoveRecvStream) {
220   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
221 
222   cricket::StreamParams stream1;
223   stream1.add_ssrc(41);
224   EXPECT_TRUE(dmc->AddRecvStream(stream1));
225   cricket::StreamParams stream2;
226   stream2.add_ssrc(42);
227   EXPECT_TRUE(dmc->AddRecvStream(stream2));
228   EXPECT_FALSE(dmc->AddRecvStream(stream2));
229 
230   EXPECT_TRUE(dmc->RemoveRecvStream(41));
231   EXPECT_TRUE(dmc->RemoveRecvStream(42));
232 }
233 
TEST_F(RtpDataMediaChannelTest,SendData)234 TEST_F(RtpDataMediaChannelTest, SendData) {
235   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
236 
237   cricket::SendDataParams params;
238   params.ssrc = 42;
239   unsigned char data[] = "food";
240   rtc::Buffer payload(data, 4);
241   unsigned char padded_data[] = {
242     0x00, 0x00, 0x00, 0x00,
243     'f', 'o', 'o', 'd',
244   };
245   cricket::SendDataResult result;
246 
247   // Not sending
248   EXPECT_FALSE(dmc->SendData(params, payload, &result));
249   EXPECT_EQ(cricket::SDR_ERROR, result);
250   EXPECT_FALSE(HasSentData(0));
251   ASSERT_TRUE(dmc->SetSend(true));
252 
253   // Unknown stream name.
254   EXPECT_FALSE(dmc->SendData(params, payload, &result));
255   EXPECT_EQ(cricket::SDR_ERROR, result);
256   EXPECT_FALSE(HasSentData(0));
257 
258   cricket::StreamParams stream;
259   stream.add_ssrc(42);
260   ASSERT_TRUE(dmc->AddSendStream(stream));
261 
262   // Unknown codec;
263   EXPECT_FALSE(dmc->SendData(params, payload, &result));
264   EXPECT_EQ(cricket::SDR_ERROR, result);
265   EXPECT_FALSE(HasSentData(0));
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   // Length too large;
275   std::string x10000(10000, 'x');
276   EXPECT_FALSE(dmc->SendData(
277       params, rtc::Buffer(x10000.data(), x10000.length()), &result));
278   EXPECT_EQ(cricket::SDR_ERROR, result);
279   EXPECT_FALSE(HasSentData(0));
280 
281   // Finally works!
282   EXPECT_TRUE(dmc->SendData(params, payload, &result));
283   EXPECT_EQ(cricket::SDR_SUCCESS, result);
284   ASSERT_TRUE(HasSentData(0));
285   EXPECT_EQ(sizeof(padded_data), GetSentData(0).length());
286   EXPECT_EQ(0, memcmp(
287       padded_data, GetSentData(0).data(), sizeof(padded_data)));
288   cricket::RtpHeader header0 = GetSentDataHeader(0);
289   EXPECT_NE(0, header0.seq_num);
290   EXPECT_NE(0U, header0.timestamp);
291   EXPECT_EQ(header0.ssrc, 42U);
292   EXPECT_EQ(header0.payload_type, 103);
293 
294   // Should bump timestamp by 180000 because the clock rate is 90khz.
295   SetNow(2);
296 
297   EXPECT_TRUE(dmc->SendData(params, payload, &result));
298   ASSERT_TRUE(HasSentData(1));
299   EXPECT_EQ(sizeof(padded_data), GetSentData(1).length());
300   EXPECT_EQ(0, memcmp(
301       padded_data, GetSentData(1).data(), sizeof(padded_data)));
302   cricket::RtpHeader header1 = GetSentDataHeader(1);
303   EXPECT_EQ(header1.ssrc, 42U);
304   EXPECT_EQ(header1.payload_type, 103);
305   EXPECT_EQ(static_cast<uint16_t>(header0.seq_num + 1),
306             static_cast<uint16_t>(header1.seq_num));
307   EXPECT_EQ(header0.timestamp + 180000, header1.timestamp);
308 }
309 
TEST_F(RtpDataMediaChannelTest,SendDataMultipleClocks)310 TEST_F(RtpDataMediaChannelTest, SendDataMultipleClocks) {
311   // Timings owned by RtpDataEngines.
312   FakeTiming* timing1 = new FakeTiming();
313   rtc::scoped_ptr<cricket::RtpDataEngine> dme1(CreateEngine(timing1));
314   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc1(
315       CreateChannel(dme1.get()));
316   FakeTiming* timing2 = new FakeTiming();
317   rtc::scoped_ptr<cricket::RtpDataEngine> dme2(CreateEngine(timing2));
318   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc2(
319       CreateChannel(dme2.get()));
320 
321   ASSERT_TRUE(dmc1->SetSend(true));
322   ASSERT_TRUE(dmc2->SetSend(true));
323 
324   cricket::StreamParams stream1;
325   stream1.add_ssrc(41);
326   ASSERT_TRUE(dmc1->AddSendStream(stream1));
327   cricket::StreamParams stream2;
328   stream2.add_ssrc(42);
329   ASSERT_TRUE(dmc2->AddSendStream(stream2));
330 
331   cricket::DataCodec codec;
332   codec.id = 103;
333   codec.name = cricket::kGoogleRtpDataCodecName;
334   cricket::DataSendParameters parameters;
335   parameters.codecs.push_back(codec);
336   ASSERT_TRUE(dmc1->SetSendParameters(parameters));
337   ASSERT_TRUE(dmc2->SetSendParameters(parameters));
338 
339   cricket::SendDataParams params1;
340   params1.ssrc = 41;
341   cricket::SendDataParams params2;
342   params2.ssrc = 42;
343 
344   unsigned char data[] = "foo";
345   rtc::Buffer payload(data, 3);
346   cricket::SendDataResult result;
347 
348   EXPECT_TRUE(dmc1->SendData(params1, payload, &result));
349   EXPECT_TRUE(dmc2->SendData(params2, payload, &result));
350 
351   // Should bump timestamp by 90000 because the clock rate is 90khz.
352   timing1->set_now(1);
353   // Should bump timestamp by 180000 because the clock rate is 90khz.
354   timing2->set_now(2);
355 
356   EXPECT_TRUE(dmc1->SendData(params1, payload, &result));
357   EXPECT_TRUE(dmc2->SendData(params2, payload, &result));
358 
359   ASSERT_TRUE(HasSentData(3));
360   cricket::RtpHeader header1a = GetSentDataHeader(0);
361   cricket::RtpHeader header2a = GetSentDataHeader(1);
362   cricket::RtpHeader header1b = GetSentDataHeader(2);
363   cricket::RtpHeader header2b = GetSentDataHeader(3);
364 
365   EXPECT_EQ(static_cast<uint16_t>(header1a.seq_num + 1),
366             static_cast<uint16_t>(header1b.seq_num));
367   EXPECT_EQ(header1a.timestamp + 90000, header1b.timestamp);
368   EXPECT_EQ(static_cast<uint16_t>(header2a.seq_num + 1),
369             static_cast<uint16_t>(header2b.seq_num));
370   EXPECT_EQ(header2a.timestamp + 180000, header2b.timestamp);
371 }
372 
TEST_F(RtpDataMediaChannelTest,SendDataRate)373 TEST_F(RtpDataMediaChannelTest, SendDataRate) {
374   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
375 
376   ASSERT_TRUE(dmc->SetSend(true));
377 
378   cricket::DataCodec codec;
379   codec.id = 103;
380   codec.name = cricket::kGoogleRtpDataCodecName;
381   cricket::DataSendParameters parameters;
382   parameters.codecs.push_back(codec);
383   ASSERT_TRUE(dmc->SetSendParameters(parameters));
384 
385   cricket::StreamParams stream;
386   stream.add_ssrc(42);
387   ASSERT_TRUE(dmc->AddSendStream(stream));
388 
389   cricket::SendDataParams params;
390   params.ssrc = 42;
391   unsigned char data[] = "food";
392   rtc::Buffer payload(data, 4);
393   cricket::SendDataResult result;
394 
395   // With rtp overhead of 32 bytes, each one of our packets is 36
396   // bytes, or 288 bits.  So, a limit of 872bps will allow 3 packets,
397   // but not four.
398   parameters.max_bandwidth_bps = 872;
399   ASSERT_TRUE(dmc->SetSendParameters(parameters));
400 
401   EXPECT_TRUE(dmc->SendData(params, payload, &result));
402   EXPECT_TRUE(dmc->SendData(params, payload, &result));
403   EXPECT_TRUE(dmc->SendData(params, payload, &result));
404   EXPECT_FALSE(dmc->SendData(params, payload, &result));
405   EXPECT_FALSE(dmc->SendData(params, payload, &result));
406 
407   SetNow(0.9);
408   EXPECT_FALSE(dmc->SendData(params, payload, &result));
409 
410   SetNow(1.1);
411   EXPECT_TRUE(dmc->SendData(params, payload, &result));
412   EXPECT_TRUE(dmc->SendData(params, payload, &result));
413   SetNow(1.9);
414   EXPECT_TRUE(dmc->SendData(params, payload, &result));
415 
416   SetNow(2.2);
417   EXPECT_TRUE(dmc->SendData(params, payload, &result));
418   EXPECT_TRUE(dmc->SendData(params, payload, &result));
419   EXPECT_TRUE(dmc->SendData(params, payload, &result));
420   EXPECT_FALSE(dmc->SendData(params, payload, &result));
421 }
422 
TEST_F(RtpDataMediaChannelTest,ReceiveData)423 TEST_F(RtpDataMediaChannelTest, ReceiveData) {
424   // PT= 103, SN=2, TS=3, SSRC = 4, data = "abcde"
425   unsigned char data[] = {
426     0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2A,
427     0x00, 0x00, 0x00, 0x00,
428     'a', 'b', 'c', 'd', 'e'
429   };
430   rtc::Buffer packet(data, sizeof(data));
431 
432   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
433 
434   // SetReceived not called.
435   dmc->OnPacketReceived(&packet, rtc::PacketTime());
436   EXPECT_FALSE(HasReceivedData());
437 
438   dmc->SetReceive(true);
439 
440   // Unknown payload id
441   dmc->OnPacketReceived(&packet, rtc::PacketTime());
442   EXPECT_FALSE(HasReceivedData());
443 
444   cricket::DataCodec codec;
445   codec.id = 103;
446   codec.name = cricket::kGoogleRtpDataCodecName;
447   cricket::DataRecvParameters parameters;
448   parameters.codecs.push_back(codec);
449   ASSERT_TRUE(dmc->SetRecvParameters(parameters));
450 
451   // Unknown stream
452   dmc->OnPacketReceived(&packet, rtc::PacketTime());
453   EXPECT_FALSE(HasReceivedData());
454 
455   cricket::StreamParams stream;
456   stream.add_ssrc(42);
457   ASSERT_TRUE(dmc->AddRecvStream(stream));
458 
459   // Finally works!
460   dmc->OnPacketReceived(&packet, rtc::PacketTime());
461   EXPECT_TRUE(HasReceivedData());
462   EXPECT_EQ("abcde", GetReceivedData());
463   EXPECT_EQ(5U, GetReceivedDataLen());
464 }
465 
TEST_F(RtpDataMediaChannelTest,InvalidRtpPackets)466 TEST_F(RtpDataMediaChannelTest, InvalidRtpPackets) {
467   unsigned char data[] = {
468     0x80, 0x65, 0x00, 0x02
469   };
470   rtc::Buffer packet(data, sizeof(data));
471 
472   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
473 
474   // Too short
475   dmc->OnPacketReceived(&packet, rtc::PacketTime());
476   EXPECT_FALSE(HasReceivedData());
477 }
478