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_t>& 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].size()); 75 } 76 return bytes; 77 } 78 79 int NumRtpBytes(uint32_t 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_t 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 int sendbuf_size() const { return sendbuf_size_; } 127 int recvbuf_size() const { return recvbuf_size_; } 128 rtc::DiffServCodePoint dscp() const { return dscp_; } 129 130 protected: 131 virtual bool SendPacket(rtc::Buffer* packet, 132 const rtc::PacketOptions& options) { 133 rtc::CritScope cs(&crit_); 134 135 uint32_t cur_ssrc = 0; 136 if (!GetRtpSsrc(packet->data(), packet->size(), &cur_ssrc)) { 137 return false; 138 } 139 sent_ssrcs_[cur_ssrc]++; 140 141 rtp_packets_.push_back(*packet); 142 if (conf_) { 143 rtc::Buffer buffer_copy(*packet); 144 for (size_t i = 0; i < conf_sent_ssrcs_.size(); ++i) { 145 if (!SetRtpSsrc(buffer_copy.data(), buffer_copy.size(), 146 conf_sent_ssrcs_[i])) { 147 return false; 148 } 149 PostMessage(ST_RTP, buffer_copy); 150 } 151 } else { 152 PostMessage(ST_RTP, *packet); 153 } 154 return true; 155 } 156 157 virtual bool SendRtcp(rtc::Buffer* packet, 158 const rtc::PacketOptions& options) { 159 rtc::CritScope cs(&crit_); 160 rtcp_packets_.push_back(*packet); 161 if (!conf_) { 162 // don't worry about RTCP in conf mode for now 163 PostMessage(ST_RTCP, *packet); 164 } 165 return true; 166 } 167 168 virtual int SetOption(SocketType type, rtc::Socket::Option opt, 169 int option) { 170 if (opt == rtc::Socket::OPT_SNDBUF) { 171 sendbuf_size_ = option; 172 } else if (opt == rtc::Socket::OPT_RCVBUF) { 173 recvbuf_size_ = option; 174 } else if (opt == rtc::Socket::OPT_DSCP) { 175 dscp_ = static_cast<rtc::DiffServCodePoint>(option); 176 } 177 return 0; 178 } 179 180 void PostMessage(int id, const rtc::Buffer& packet) { 181 thread_->Post(this, id, rtc::WrapMessageData(packet)); 182 } 183 184 virtual void OnMessage(rtc::Message* msg) { 185 rtc::TypedMessageData<rtc::Buffer>* msg_data = 186 static_cast<rtc::TypedMessageData<rtc::Buffer>*>( 187 msg->pdata); 188 if (dest_) { 189 if (msg->message_id == ST_RTP) { 190 dest_->OnPacketReceived(&msg_data->data(), 191 rtc::CreatePacketTime(0)); 192 } else { 193 dest_->OnRtcpReceived(&msg_data->data(), 194 rtc::CreatePacketTime(0)); 195 } 196 } 197 delete msg_data; 198 } 199 200 private: 201 void GetNumRtpBytesAndPackets(uint32_t ssrc, int* bytes, int* packets) { 202 if (bytes) { 203 *bytes = 0; 204 } 205 if (packets) { 206 *packets = 0; 207 } 208 uint32_t cur_ssrc = 0; 209 for (size_t i = 0; i < rtp_packets_.size(); ++i) { 210 if (!GetRtpSsrc(rtp_packets_[i].data(), rtp_packets_[i].size(), 211 &cur_ssrc)) { 212 return; 213 } 214 if (ssrc == cur_ssrc) { 215 if (bytes) { 216 *bytes += static_cast<int>(rtp_packets_[i].size()); 217 } 218 if (packets) { 219 ++(*packets); 220 } 221 } 222 } 223 } 224 225 rtc::Thread* thread_; 226 MediaChannel* dest_; 227 bool conf_; 228 // The ssrcs used in sending out packets in conference mode. 229 std::vector<uint32_t> conf_sent_ssrcs_; 230 // Map to track counts of packets that have been sent per ssrc. 231 // This includes packets that are dropped. 232 std::map<uint32_t, uint32_t> sent_ssrcs_; 233 // Map to track packet-number that needs to be dropped per ssrc. 234 std::map<uint32_t, std::set<uint32_t> > drop_map_; 235 rtc::CriticalSection crit_; 236 std::vector<rtc::Buffer> rtp_packets_; 237 std::vector<rtc::Buffer> rtcp_packets_; 238 int sendbuf_size_; 239 int recvbuf_size_; 240 rtc::DiffServCodePoint dscp_; 241 }; 242 243 } // namespace cricket 244 245 #endif // TALK_MEDIA_BASE_FAKENETWORKINTERFACE_H_ 246