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