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