Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004 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 #ifndef TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_
     29 #define TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_
     30 
     31 #include <vector>
     32 #include <map>
     33 
     34 #include "talk/base/buffer.h"
     35 #include "talk/base/byteorder.h"
     36 #include "talk/base/criticalsection.h"
     37 #include "talk/base/messagehandler.h"
     38 #include "talk/base/messagequeue.h"
     39 #include "talk/base/thread.h"
     40 #include "talk/media/base/mediachannel.h"
     41 #include "talk/media/base/rtputils.h"
     42 
     43 namespace cricket {
     44 
     45 // Fake NetworkInterface that sends/receives RTP/RTCP packets.
     46 class FakeNetworkInterface : public MediaChannel::NetworkInterface,
     47                              public talk_base::MessageHandler {
     48  public:
     49   FakeNetworkInterface()
     50       : thread_(talk_base::Thread::Current()),
     51         dest_(NULL),
     52         conf_(false),
     53         sendbuf_size_(-1),
     54         recvbuf_size_(-1) {
     55   }
     56 
     57   void SetDestination(MediaChannel* dest) { dest_ = dest; }
     58 
     59   // Conference mode is a mode where instead of simply forwarding the packets,
     60   // the transport will send multiple copies of the packet with the specified
     61   // SSRCs. This allows us to simulate receiving media from multiple sources.
     62   void SetConferenceMode(bool conf, const std::vector<uint32>& ssrcs) {
     63     talk_base::CritScope cs(&crit_);
     64     conf_ = conf;
     65     conf_sent_ssrcs_ = ssrcs;
     66   }
     67 
     68   int NumRtpBytes() {
     69     talk_base::CritScope cs(&crit_);
     70     int bytes = 0;
     71     for (size_t i = 0; i < rtp_packets_.size(); ++i) {
     72       bytes += static_cast<int>(rtp_packets_[i].length());
     73     }
     74     return bytes;
     75   }
     76 
     77   int NumRtpBytes(uint32 ssrc) {
     78     talk_base::CritScope cs(&crit_);
     79     int bytes = 0;
     80     GetNumRtpBytesAndPackets(ssrc, &bytes, NULL);
     81     return bytes;
     82   }
     83 
     84   int NumRtpPackets() {
     85     talk_base::CritScope cs(&crit_);
     86     return static_cast<int>(rtp_packets_.size());
     87   }
     88 
     89   int NumRtpPackets(uint32 ssrc) {
     90     talk_base::CritScope cs(&crit_);
     91     int packets = 0;
     92     GetNumRtpBytesAndPackets(ssrc, NULL, &packets);
     93     return packets;
     94   }
     95 
     96   int NumSentSsrcs() {
     97     talk_base::CritScope cs(&crit_);
     98     return static_cast<int>(sent_ssrcs_.size());
     99   }
    100 
    101   // Note: callers are responsible for deleting the returned buffer.
    102   const talk_base::Buffer* GetRtpPacket(int index) {
    103     talk_base::CritScope cs(&crit_);
    104     if (index >= NumRtpPackets()) {
    105       return NULL;
    106     }
    107     return new talk_base::Buffer(rtp_packets_[index]);
    108   }
    109 
    110   int NumRtcpPackets() {
    111     talk_base::CritScope cs(&crit_);
    112     return static_cast<int>(rtcp_packets_.size());
    113   }
    114 
    115   // Note: callers are responsible for deleting the returned buffer.
    116   const talk_base::Buffer* GetRtcpPacket(int index) {
    117     talk_base::CritScope cs(&crit_);
    118     if (index >= NumRtcpPackets()) {
    119       return NULL;
    120     }
    121     return new talk_base::Buffer(rtcp_packets_[index]);
    122   }
    123 
    124   // Indicate that |n|'th packet for |ssrc| should be dropped.
    125   void AddPacketDrop(uint32 ssrc, uint32 n) {
    126     drop_map_[ssrc].insert(n);
    127   }
    128 
    129   int sendbuf_size() const { return sendbuf_size_; }
    130   int recvbuf_size() const { return recvbuf_size_; }
    131 
    132  protected:
    133   virtual bool SendPacket(talk_base::Buffer* packet) {
    134     talk_base::CritScope cs(&crit_);
    135 
    136     uint32 cur_ssrc = 0;
    137     if (!GetRtpSsrc(packet->data(), packet->length(), &cur_ssrc)) {
    138       return false;
    139     }
    140     sent_ssrcs_[cur_ssrc]++;
    141 
    142     // Check if we need to drop this packet.
    143     std::map<uint32, std::set<uint32> >::iterator itr =
    144       drop_map_.find(cur_ssrc);
    145     if (itr != drop_map_.end() &&
    146         itr->second.count(sent_ssrcs_[cur_ssrc]) > 0) {
    147         // "Drop" the packet.
    148         return true;
    149     }
    150 
    151     rtp_packets_.push_back(*packet);
    152     if (conf_) {
    153       talk_base::Buffer buffer_copy(*packet);
    154       for (size_t i = 0; i < conf_sent_ssrcs_.size(); ++i) {
    155         if (!SetRtpSsrc(buffer_copy.data(), buffer_copy.length(),
    156                         conf_sent_ssrcs_[i])) {
    157           return false;
    158         }
    159         PostMessage(ST_RTP, buffer_copy);
    160       }
    161     } else {
    162       PostMessage(ST_RTP, *packet);
    163     }
    164     return true;
    165   }
    166 
    167   virtual bool SendRtcp(talk_base::Buffer* packet) {
    168     talk_base::CritScope cs(&crit_);
    169     rtcp_packets_.push_back(*packet);
    170     if (!conf_) {
    171       // don't worry about RTCP in conf mode for now
    172       PostMessage(ST_RTCP, *packet);
    173     }
    174     return true;
    175   }
    176 
    177   virtual int SetOption(SocketType type, talk_base::Socket::Option opt,
    178                         int option) {
    179     if (opt == talk_base::Socket::OPT_SNDBUF) {
    180       sendbuf_size_ = option;
    181     } else if (opt == talk_base::Socket::OPT_RCVBUF) {
    182       recvbuf_size_ = option;
    183     }
    184     return 0;
    185   }
    186 
    187   void PostMessage(int id, const talk_base::Buffer& packet) {
    188     thread_->Post(this, id, talk_base::WrapMessageData(packet));
    189   }
    190 
    191   virtual void OnMessage(talk_base::Message* msg) {
    192     talk_base::TypedMessageData<talk_base::Buffer>* msg_data =
    193         static_cast<talk_base::TypedMessageData<talk_base::Buffer>*>(
    194             msg->pdata);
    195     if (dest_) {
    196       if (msg->message_id == ST_RTP) {
    197         dest_->OnPacketReceived(&msg_data->data());
    198       } else {
    199         dest_->OnRtcpReceived(&msg_data->data());
    200       }
    201     }
    202     delete msg_data;
    203   }
    204 
    205  private:
    206   void GetNumRtpBytesAndPackets(uint32 ssrc, int* bytes, int* packets) {
    207     if (bytes) {
    208       *bytes = 0;
    209     }
    210     if (packets) {
    211       *packets = 0;
    212     }
    213     uint32 cur_ssrc = 0;
    214     for (size_t i = 0; i < rtp_packets_.size(); ++i) {
    215       if (!GetRtpSsrc(rtp_packets_[i].data(),
    216                       rtp_packets_[i].length(), &cur_ssrc)) {
    217         return;
    218       }
    219       if (ssrc == cur_ssrc) {
    220         if (bytes) {
    221           *bytes += static_cast<int>(rtp_packets_[i].length());
    222         }
    223         if (packets) {
    224           ++(*packets);
    225         }
    226       }
    227     }
    228   }
    229 
    230   talk_base::Thread* thread_;
    231   MediaChannel* dest_;
    232   bool conf_;
    233   // The ssrcs used in sending out packets in conference mode.
    234   std::vector<uint32> conf_sent_ssrcs_;
    235   // Map to track counts of packets that have been sent per ssrc.
    236   // This includes packets that are dropped.
    237   std::map<uint32, uint32> sent_ssrcs_;
    238   // Map to track packet-number that needs to be dropped per ssrc.
    239   std::map<uint32, std::set<uint32> > drop_map_;
    240   talk_base::CriticalSection crit_;
    241   std::vector<talk_base::Buffer> rtp_packets_;
    242   std::vector<talk_base::Buffer> rtcp_packets_;
    243   int sendbuf_size_;
    244   int recvbuf_size_;
    245 };
    246 
    247 }  // namespace cricket
    248 
    249 #endif  // TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_
    250