Home | History | Annotate | Download | only in base
      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   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 
     94   void SetNow(double now) {
     95     timing_->set_now(now);
     96   }
     97 
     98   cricket::RtpDataEngine* CreateEngine(FakeTiming* timing) {
     99     cricket::RtpDataEngine* dme = new cricket::RtpDataEngine();
    100     dme->SetTiming(timing);
    101     return dme;
    102   }
    103 
    104   cricket::RtpDataMediaChannel* CreateChannel() {
    105     return CreateChannel(dme_.get());
    106   }
    107 
    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 
    118   FakeDataReceiver* receiver() {
    119     return receiver_.get();
    120   }
    121 
    122   bool HasReceivedData() {
    123     return receiver_->has_received_data();
    124   }
    125 
    126   std::string GetReceivedData() {
    127     return receiver_->last_received_data();
    128   }
    129 
    130   size_t GetReceivedDataLen() {
    131     return receiver_->last_received_data_len();
    132   }
    133 
    134   cricket::ReceiveDataParams GetReceivedDataParams() {
    135     return receiver_->last_received_data_params();
    136   }
    137 
    138   bool HasSentData(int count) {
    139     return (iface_->NumRtpPackets() > count);
    140   }
    141 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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