Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / media / base / rtpdataengine_unittest.cc
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:
43   FakeTiming() : now_(0.0) {}
44
45   virtual double TimerNow() {
46     return now_;
47   }
48
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:
59   FakeDataReceiver() : has_received_data_(false) {}
60
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
70   bool has_received_data() const { return has_received_data_; }
71   std::string last_received_data() const { return last_received_data_; }
72   size_t last_received_data_len() const { return last_received_data_len_; }
73   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:
86   static void SetUpTestCase() {
87     rtc::InitializeSSL();
88   }
89
90   static void TearDownTestCase() {
91     rtc::CleanupSSL();
92   }
93
94   virtual void SetUp() {
95     // Seed needed for each test to satisfy expectations.
96     iface_.reset(new cricket::FakeNetworkInterface());
97     timing_ = new FakeTiming();
98     dme_.reset(CreateEngine(timing_));
99     receiver_.reset(new FakeDataReceiver());
100   }
101
102   void SetNow(double now) {
103     timing_->set_now(now);
104   }
105
106   cricket::RtpDataEngine* CreateEngine(FakeTiming* timing) {
107     cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
108     dme->SetTiming(timing);
109     return dme;
110   }
111
112   cricket::RtpDataMediaChannel* CreateChannel() {
113     return CreateChannel(dme_.get());
114   }
115
116   cricket::RtpDataMediaChannel* CreateChannel(cricket::RtpDataEngine* dme) {
117     cricket::RtpDataMediaChannel* channel =
118         static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(
119             cricket::DCT_RTP));
120     channel->SetInterface(iface_.get());
121     channel->SignalDataReceived.connect(
122         receiver_.get(), &FakeDataReceiver::OnDataReceived);
123     return channel;
124   }
125
126   FakeDataReceiver* receiver() {
127     return receiver_.get();
128   }
129
130   bool HasReceivedData() {
131     return receiver_->has_received_data();
132   }
133
134   std::string GetReceivedData() {
135     return receiver_->last_received_data();
136   }
137
138   size_t GetReceivedDataLen() {
139     return receiver_->last_received_data_len();
140   }
141
142   cricket::ReceiveDataParams GetReceivedDataParams() {
143     return receiver_->last_received_data_params();
144   }
145
146   bool HasSentData(int count) {
147     return (iface_->NumRtpPackets() > count);
148   }
149
150   std::string GetSentData(int index) {
151     // Assume RTP header of length 12
152     rtc::scoped_ptr<const rtc::Buffer> packet(
153         iface_->GetRtpPacket(index));
154     if (packet->length() > 12) {
155       return std::string(packet->data() + 12, packet->length() - 12);
156     } else {
157       return "";
158     }
159   }
160
161   cricket::RtpHeader GetSentDataHeader(int index) {
162     rtc::scoped_ptr<const rtc::Buffer> packet(
163         iface_->GetRtpPacket(index));
164     cricket::RtpHeader header;
165     GetRtpHeader(packet->data(), packet->length(), &header);
166     return header;
167   }
168
169  private:
170   rtc::scoped_ptr<cricket::RtpDataEngine> dme_;
171   // Timing passed into dme_.  Owned by dme_;
172   FakeTiming* timing_;
173   rtc::scoped_ptr<cricket::FakeNetworkInterface> iface_;
174   rtc::scoped_ptr<FakeDataReceiver> receiver_;
175 };
176
177 TEST_F(RtpDataMediaChannelTest, SetUnknownCodecs) {
178   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
179
180   cricket::DataCodec known_codec;
181   known_codec.id = 103;
182   known_codec.name = "google-data";
183   cricket::DataCodec unknown_codec;
184   unknown_codec.id = 104;
185   unknown_codec.name = "unknown-data";
186
187   std::vector<cricket::DataCodec> known_codecs;
188   known_codecs.push_back(known_codec);
189
190   std::vector<cricket::DataCodec> unknown_codecs;
191   unknown_codecs.push_back(unknown_codec);
192
193   std::vector<cricket::DataCodec> mixed_codecs;
194   mixed_codecs.push_back(known_codec);
195   mixed_codecs.push_back(unknown_codec);
196
197   EXPECT_TRUE(dmc->SetSendCodecs(known_codecs));
198   EXPECT_FALSE(dmc->SetSendCodecs(unknown_codecs));
199   EXPECT_TRUE(dmc->SetSendCodecs(mixed_codecs));
200   EXPECT_TRUE(dmc->SetRecvCodecs(known_codecs));
201   EXPECT_FALSE(dmc->SetRecvCodecs(unknown_codecs));
202   EXPECT_FALSE(dmc->SetRecvCodecs(mixed_codecs));
203 }
204
205 TEST_F(RtpDataMediaChannelTest, AddRemoveSendStream) {
206   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
207
208   cricket::StreamParams stream1;
209   stream1.add_ssrc(41);
210   EXPECT_TRUE(dmc->AddSendStream(stream1));
211   cricket::StreamParams stream2;
212   stream2.add_ssrc(42);
213   EXPECT_TRUE(dmc->AddSendStream(stream2));
214
215   EXPECT_TRUE(dmc->RemoveSendStream(41));
216   EXPECT_TRUE(dmc->RemoveSendStream(42));
217   EXPECT_FALSE(dmc->RemoveSendStream(43));
218 }
219
220 TEST_F(RtpDataMediaChannelTest, AddRemoveRecvStream) {
221   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
222
223   cricket::StreamParams stream1;
224   stream1.add_ssrc(41);
225   EXPECT_TRUE(dmc->AddRecvStream(stream1));
226   cricket::StreamParams stream2;
227   stream2.add_ssrc(42);
228   EXPECT_TRUE(dmc->AddRecvStream(stream2));
229   EXPECT_FALSE(dmc->AddRecvStream(stream2));
230
231   EXPECT_TRUE(dmc->RemoveRecvStream(41));
232   EXPECT_TRUE(dmc->RemoveRecvStream(42));
233 }
234
235 TEST_F(RtpDataMediaChannelTest, SendData) {
236   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
237
238   cricket::SendDataParams params;
239   params.ssrc = 42;
240   unsigned char data[] = "food";
241   rtc::Buffer payload(data, 4);
242   unsigned char padded_data[] = {
243     0x00, 0x00, 0x00, 0x00,
244     'f', 'o', 'o', 'd',
245   };
246   cricket::SendDataResult result;
247
248   // Not sending
249   EXPECT_FALSE(dmc->SendData(params, payload, &result));
250   EXPECT_EQ(cricket::SDR_ERROR, result);
251   EXPECT_FALSE(HasSentData(0));
252   ASSERT_TRUE(dmc->SetSend(true));
253
254   // Unknown stream name.
255   EXPECT_FALSE(dmc->SendData(params, payload, &result));
256   EXPECT_EQ(cricket::SDR_ERROR, result);
257   EXPECT_FALSE(HasSentData(0));
258
259   cricket::StreamParams stream;
260   stream.add_ssrc(42);
261   ASSERT_TRUE(dmc->AddSendStream(stream));
262
263   // Unknown codec;
264   EXPECT_FALSE(dmc->SendData(params, payload, &result));
265   EXPECT_EQ(cricket::SDR_ERROR, result);
266   EXPECT_FALSE(HasSentData(0));
267
268   cricket::DataCodec codec;
269   codec.id = 103;
270   codec.name = cricket::kGoogleRtpDataCodecName;
271   std::vector<cricket::DataCodec> codecs;
272   codecs.push_back(codec);
273   ASSERT_TRUE(dmc->SetSendCodecs(codecs));
274
275   // Length too large;
276   std::string x10000(10000, 'x');
277   EXPECT_FALSE(dmc->SendData(
278       params, rtc::Buffer(x10000.data(), x10000.length()), &result));
279   EXPECT_EQ(cricket::SDR_ERROR, result);
280   EXPECT_FALSE(HasSentData(0));
281
282   // Finally works!
283   EXPECT_TRUE(dmc->SendData(params, payload, &result));
284   EXPECT_EQ(cricket::SDR_SUCCESS, result);
285   ASSERT_TRUE(HasSentData(0));
286   EXPECT_EQ(sizeof(padded_data), GetSentData(0).length());
287   EXPECT_EQ(0, memcmp(
288       padded_data, GetSentData(0).data(), sizeof(padded_data)));
289   cricket::RtpHeader header0 = GetSentDataHeader(0);
290   EXPECT_NE(0, header0.seq_num);
291   EXPECT_NE(0U, header0.timestamp);
292   EXPECT_EQ(header0.ssrc, 42U);
293   EXPECT_EQ(header0.payload_type, 103);
294
295   // Should bump timestamp by 180000 because the clock rate is 90khz.
296   SetNow(2);
297
298   EXPECT_TRUE(dmc->SendData(params, payload, &result));
299   ASSERT_TRUE(HasSentData(1));
300   EXPECT_EQ(sizeof(padded_data), GetSentData(1).length());
301   EXPECT_EQ(0, memcmp(
302       padded_data, GetSentData(1).data(), sizeof(padded_data)));
303   cricket::RtpHeader header1 = GetSentDataHeader(1);
304   EXPECT_EQ(header1.ssrc, 42U);
305   EXPECT_EQ(header1.payload_type, 103);
306   EXPECT_EQ(static_cast<uint16>(header0.seq_num + 1),
307             static_cast<uint16>(header1.seq_num));
308   EXPECT_EQ(header0.timestamp + 180000, header1.timestamp);
309 }
310
311 TEST_F(RtpDataMediaChannelTest, SendDataMultipleClocks) {
312   // Timings owned by RtpDataEngines.
313   FakeTiming* timing1 = new FakeTiming();
314   rtc::scoped_ptr<cricket::RtpDataEngine> dme1(CreateEngine(timing1));
315   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc1(
316       CreateChannel(dme1.get()));
317   FakeTiming* timing2 = new FakeTiming();
318   rtc::scoped_ptr<cricket::RtpDataEngine> dme2(CreateEngine(timing2));
319   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc2(
320       CreateChannel(dme2.get()));
321
322   ASSERT_TRUE(dmc1->SetSend(true));
323   ASSERT_TRUE(dmc2->SetSend(true));
324
325   cricket::StreamParams stream1;
326   stream1.add_ssrc(41);
327   ASSERT_TRUE(dmc1->AddSendStream(stream1));
328   cricket::StreamParams stream2;
329   stream2.add_ssrc(42);
330   ASSERT_TRUE(dmc2->AddSendStream(stream2));
331
332   cricket::DataCodec codec;
333   codec.id = 103;
334   codec.name = cricket::kGoogleRtpDataCodecName;
335   std::vector<cricket::DataCodec> codecs;
336   codecs.push_back(codec);
337   ASSERT_TRUE(dmc1->SetSendCodecs(codecs));
338   ASSERT_TRUE(dmc2->SetSendCodecs(codecs));
339
340   cricket::SendDataParams params1;
341   params1.ssrc = 41;
342   cricket::SendDataParams params2;
343   params2.ssrc = 42;
344
345   unsigned char data[] = "foo";
346   rtc::Buffer payload(data, 3);
347   cricket::SendDataResult result;
348
349   EXPECT_TRUE(dmc1->SendData(params1, payload, &result));
350   EXPECT_TRUE(dmc2->SendData(params2, payload, &result));
351
352   // Should bump timestamp by 90000 because the clock rate is 90khz.
353   timing1->set_now(1);
354   // Should bump timestamp by 180000 because the clock rate is 90khz.
355   timing2->set_now(2);
356
357   EXPECT_TRUE(dmc1->SendData(params1, payload, &result));
358   EXPECT_TRUE(dmc2->SendData(params2, payload, &result));
359
360   ASSERT_TRUE(HasSentData(3));
361   cricket::RtpHeader header1a = GetSentDataHeader(0);
362   cricket::RtpHeader header2a = GetSentDataHeader(1);
363   cricket::RtpHeader header1b = GetSentDataHeader(2);
364   cricket::RtpHeader header2b = GetSentDataHeader(3);
365
366   EXPECT_EQ(static_cast<uint16>(header1a.seq_num + 1),
367             static_cast<uint16>(header1b.seq_num));
368   EXPECT_EQ(header1a.timestamp + 90000, header1b.timestamp);
369   EXPECT_EQ(static_cast<uint16>(header2a.seq_num + 1),
370             static_cast<uint16>(header2b.seq_num));
371   EXPECT_EQ(header2a.timestamp + 180000, header2b.timestamp);
372 }
373
374 TEST_F(RtpDataMediaChannelTest, SendDataRate) {
375   rtc::scoped_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel());
376
377   ASSERT_TRUE(dmc->SetSend(true));
378
379   cricket::DataCodec codec;
380   codec.id = 103;
381   codec.name = cricket::kGoogleRtpDataCodecName;
382   std::vector<cricket::DataCodec> codecs;
383   codecs.push_back(codec);
384   ASSERT_TRUE(dmc->SetSendCodecs(codecs));
385
386   cricket::StreamParams stream;
387   stream.add_ssrc(42);
388   ASSERT_TRUE(dmc->AddSendStream(stream));
389
390   cricket::SendDataParams params;
391   params.ssrc = 42;
392   unsigned char data[] = "food";
393   rtc::Buffer payload(data, 4);
394   cricket::SendDataResult result;
395
396   // With rtp overhead of 32 bytes, each one of our packets is 36
397   // bytes, or 288 bits.  So, a limit of 872bps will allow 3 packets,
398   // but not four.
399   dmc->SetMaxSendBandwidth(872);
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
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   std::vector<cricket::DataCodec> codecs;
448   codecs.push_back(codec);
449   ASSERT_TRUE(dmc->SetRecvCodecs(codecs));
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
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 }