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 "talk/media/base/rtpdataengine.h" 29 30 #include "talk/media/base/codec.h" 31 #include "talk/media/base/constants.h" 32 #include "talk/media/base/rtputils.h" 33 #include "talk/media/base/streamparams.h" 34 #include "webrtc/base/buffer.h" 35 #include "webrtc/base/helpers.h" 36 #include "webrtc/base/logging.h" 37 #include "webrtc/base/ratelimiter.h" 38 #include "webrtc/base/timing.h" 39 40 namespace cricket { 41 42 // We want to avoid IP fragmentation. 43 static const size_t kDataMaxRtpPacketLen = 1200U; 44 // We reserve space after the RTP header for future wiggle room. 45 static const unsigned char kReservedSpace[] = { 46 0x00, 0x00, 0x00, 0x00 47 }; 48 49 // Amount of overhead SRTP may take. We need to leave room in the 50 // buffer for it, otherwise SRTP will fail later. If SRTP ever uses 51 // more than this, we need to increase this number. 52 static const size_t kMaxSrtpHmacOverhead = 16; 53 54 RtpDataEngine::RtpDataEngine() { 55 data_codecs_.push_back( 56 DataCodec(kGoogleRtpDataCodecId, 57 kGoogleRtpDataCodecName, 0)); 58 SetTiming(new rtc::Timing()); 59 } 60 61 DataMediaChannel* RtpDataEngine::CreateChannel( 62 DataChannelType data_channel_type) { 63 if (data_channel_type != DCT_RTP) { 64 return NULL; 65 } 66 return new RtpDataMediaChannel(timing_.get()); 67 } 68 69 bool FindCodecByName(const std::vector<DataCodec>& codecs, 70 const std::string& name, DataCodec* codec_out) { 71 std::vector<DataCodec>::const_iterator iter; 72 for (iter = codecs.begin(); iter != codecs.end(); ++iter) { 73 if (iter->name == name) { 74 *codec_out = *iter; 75 return true; 76 } 77 } 78 return false; 79 } 80 81 RtpDataMediaChannel::RtpDataMediaChannel(rtc::Timing* timing) { 82 Construct(timing); 83 } 84 85 RtpDataMediaChannel::RtpDataMediaChannel() { 86 Construct(NULL); 87 } 88 89 void RtpDataMediaChannel::Construct(rtc::Timing* timing) { 90 sending_ = false; 91 receiving_ = false; 92 timing_ = timing; 93 send_limiter_.reset(new rtc::RateLimiter(kDataMaxBandwidth / 8, 1.0)); 94 } 95 96 97 RtpDataMediaChannel::~RtpDataMediaChannel() { 98 std::map<uint32_t, RtpClock*>::const_iterator iter; 99 for (iter = rtp_clock_by_send_ssrc_.begin(); 100 iter != rtp_clock_by_send_ssrc_.end(); 101 ++iter) { 102 delete iter->second; 103 } 104 } 105 106 void RtpClock::Tick(double now, int* seq_num, uint32_t* timestamp) { 107 *seq_num = ++last_seq_num_; 108 *timestamp = timestamp_offset_ + static_cast<uint32_t>(now * clockrate_); 109 } 110 111 const DataCodec* FindUnknownCodec(const std::vector<DataCodec>& codecs) { 112 DataCodec data_codec(kGoogleRtpDataCodecId, kGoogleRtpDataCodecName, 0); 113 std::vector<DataCodec>::const_iterator iter; 114 for (iter = codecs.begin(); iter != codecs.end(); ++iter) { 115 if (!iter->Matches(data_codec)) { 116 return &(*iter); 117 } 118 } 119 return NULL; 120 } 121 122 const DataCodec* FindKnownCodec(const std::vector<DataCodec>& codecs) { 123 DataCodec data_codec(kGoogleRtpDataCodecId, kGoogleRtpDataCodecName, 0); 124 std::vector<DataCodec>::const_iterator iter; 125 for (iter = codecs.begin(); iter != codecs.end(); ++iter) { 126 if (iter->Matches(data_codec)) { 127 return &(*iter); 128 } 129 } 130 return NULL; 131 } 132 133 bool RtpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { 134 const DataCodec* unknown_codec = FindUnknownCodec(codecs); 135 if (unknown_codec) { 136 LOG(LS_WARNING) << "Failed to SetRecvCodecs because of unknown codec: " 137 << unknown_codec->ToString(); 138 return false; 139 } 140 141 recv_codecs_ = codecs; 142 return true; 143 } 144 145 bool RtpDataMediaChannel::SetSendCodecs(const std::vector<DataCodec>& codecs) { 146 const DataCodec* known_codec = FindKnownCodec(codecs); 147 if (!known_codec) { 148 LOG(LS_WARNING) << 149 "Failed to SetSendCodecs because there is no known codec."; 150 return false; 151 } 152 153 send_codecs_ = codecs; 154 return true; 155 } 156 157 bool RtpDataMediaChannel::SetSendParameters(const DataSendParameters& params) { 158 return (SetSendCodecs(params.codecs) && 159 SetMaxSendBandwidth(params.max_bandwidth_bps)); 160 } 161 162 bool RtpDataMediaChannel::SetRecvParameters(const DataRecvParameters& params) { 163 return SetRecvCodecs(params.codecs); 164 } 165 166 bool RtpDataMediaChannel::AddSendStream(const StreamParams& stream) { 167 if (!stream.has_ssrcs()) { 168 return false; 169 } 170 171 if (GetStreamBySsrc(send_streams_, stream.first_ssrc())) { 172 LOG(LS_WARNING) << "Not adding data send stream '" << stream.id 173 << "' with ssrc=" << stream.first_ssrc() 174 << " because stream already exists."; 175 return false; 176 } 177 178 send_streams_.push_back(stream); 179 // TODO(pthatcher): This should be per-stream, not per-ssrc. 180 // And we should probably allow more than one per stream. 181 rtp_clock_by_send_ssrc_[stream.first_ssrc()] = new RtpClock( 182 kDataCodecClockrate, 183 rtc::CreateRandomNonZeroId(), rtc::CreateRandomNonZeroId()); 184 185 LOG(LS_INFO) << "Added data send stream '" << stream.id 186 << "' with ssrc=" << stream.first_ssrc(); 187 return true; 188 } 189 190 bool RtpDataMediaChannel::RemoveSendStream(uint32_t ssrc) { 191 if (!GetStreamBySsrc(send_streams_, ssrc)) { 192 return false; 193 } 194 195 RemoveStreamBySsrc(&send_streams_, ssrc); 196 delete rtp_clock_by_send_ssrc_[ssrc]; 197 rtp_clock_by_send_ssrc_.erase(ssrc); 198 return true; 199 } 200 201 bool RtpDataMediaChannel::AddRecvStream(const StreamParams& stream) { 202 if (!stream.has_ssrcs()) { 203 return false; 204 } 205 206 if (GetStreamBySsrc(recv_streams_, stream.first_ssrc())) { 207 LOG(LS_WARNING) << "Not adding data recv stream '" << stream.id 208 << "' with ssrc=" << stream.first_ssrc() 209 << " because stream already exists."; 210 return false; 211 } 212 213 recv_streams_.push_back(stream); 214 LOG(LS_INFO) << "Added data recv stream '" << stream.id 215 << "' with ssrc=" << stream.first_ssrc(); 216 return true; 217 } 218 219 bool RtpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) { 220 RemoveStreamBySsrc(&recv_streams_, ssrc); 221 return true; 222 } 223 224 void RtpDataMediaChannel::OnPacketReceived( 225 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { 226 RtpHeader header; 227 if (!GetRtpHeader(packet->data(), packet->size(), &header)) { 228 // Don't want to log for every corrupt packet. 229 // LOG(LS_WARNING) << "Could not read rtp header from packet of length " 230 // << packet->length() << "."; 231 return; 232 } 233 234 size_t header_length; 235 if (!GetRtpHeaderLen(packet->data(), packet->size(), &header_length)) { 236 // Don't want to log for every corrupt packet. 237 // LOG(LS_WARNING) << "Could not read rtp header" 238 // << length from packet of length " 239 // << packet->length() << "."; 240 return; 241 } 242 const char* data = 243 packet->data<char>() + header_length + sizeof(kReservedSpace); 244 size_t data_len = packet->size() - header_length - sizeof(kReservedSpace); 245 246 if (!receiving_) { 247 LOG(LS_WARNING) << "Not receiving packet " 248 << header.ssrc << ":" << header.seq_num 249 << " before SetReceive(true) called."; 250 return; 251 } 252 253 DataCodec codec; 254 if (!FindCodecById(recv_codecs_, header.payload_type, &codec)) { 255 // For bundling, this will be logged for every message. 256 // So disable this logging. 257 // LOG(LS_WARNING) << "Not receiving packet " 258 // << header.ssrc << ":" << header.seq_num 259 // << " (" << data_len << ")" 260 // << " because unknown payload id: " << header.payload_type; 261 return; 262 } 263 264 if (!GetStreamBySsrc(recv_streams_, header.ssrc)) { 265 LOG(LS_WARNING) << "Received packet for unknown ssrc: " << header.ssrc; 266 return; 267 } 268 269 // Uncomment this for easy debugging. 270 // const auto* found_stream = GetStreamBySsrc(recv_streams_, header.ssrc); 271 // LOG(LS_INFO) << "Received packet" 272 // << " groupid=" << found_stream.groupid 273 // << ", ssrc=" << header.ssrc 274 // << ", seqnum=" << header.seq_num 275 // << ", timestamp=" << header.timestamp 276 // << ", len=" << data_len; 277 278 ReceiveDataParams params; 279 params.ssrc = header.ssrc; 280 params.seq_num = header.seq_num; 281 params.timestamp = header.timestamp; 282 SignalDataReceived(params, data, data_len); 283 } 284 285 bool RtpDataMediaChannel::SetMaxSendBandwidth(int bps) { 286 if (bps <= 0) { 287 bps = kDataMaxBandwidth; 288 } 289 send_limiter_.reset(new rtc::RateLimiter(bps / 8, 1.0)); 290 LOG(LS_INFO) << "RtpDataMediaChannel::SetSendBandwidth to " << bps << "bps."; 291 return true; 292 } 293 294 bool RtpDataMediaChannel::SendData( 295 const SendDataParams& params, 296 const rtc::Buffer& payload, 297 SendDataResult* result) { 298 if (result) { 299 // If we return true, we'll set this to SDR_SUCCESS. 300 *result = SDR_ERROR; 301 } 302 if (!sending_) { 303 LOG(LS_WARNING) << "Not sending packet with ssrc=" << params.ssrc 304 << " len=" << payload.size() << " before SetSend(true)."; 305 return false; 306 } 307 308 if (params.type != cricket::DMT_TEXT) { 309 LOG(LS_WARNING) << "Not sending data because binary type is unsupported."; 310 return false; 311 } 312 313 const StreamParams* found_stream = 314 GetStreamBySsrc(send_streams_, params.ssrc); 315 if (!found_stream) { 316 LOG(LS_WARNING) << "Not sending data because ssrc is unknown: " 317 << params.ssrc; 318 return false; 319 } 320 321 DataCodec found_codec; 322 if (!FindCodecByName(send_codecs_, kGoogleRtpDataCodecName, &found_codec)) { 323 LOG(LS_WARNING) << "Not sending data because codec is unknown: " 324 << kGoogleRtpDataCodecName; 325 return false; 326 } 327 328 size_t packet_len = (kMinRtpPacketLen + sizeof(kReservedSpace) + 329 payload.size() + kMaxSrtpHmacOverhead); 330 if (packet_len > kDataMaxRtpPacketLen) { 331 return false; 332 } 333 334 double now = timing_->TimerNow(); 335 336 if (!send_limiter_->CanUse(packet_len, now)) { 337 LOG(LS_VERBOSE) << "Dropped data packet of len=" << packet_len 338 << "; already sent " << send_limiter_->used_in_period() 339 << "/" << send_limiter_->max_per_period(); 340 return false; 341 } 342 343 RtpHeader header; 344 header.payload_type = found_codec.id; 345 header.ssrc = params.ssrc; 346 rtp_clock_by_send_ssrc_[header.ssrc]->Tick( 347 now, &header.seq_num, &header.timestamp); 348 349 rtc::Buffer packet(kMinRtpPacketLen, packet_len); 350 if (!SetRtpHeader(packet.data(), packet.size(), header)) { 351 return false; 352 } 353 packet.AppendData(kReservedSpace); 354 packet.AppendData(payload); 355 356 LOG(LS_VERBOSE) << "Sent RTP data packet: " 357 << " stream=" << found_stream->id << " ssrc=" << header.ssrc 358 << ", seqnum=" << header.seq_num 359 << ", timestamp=" << header.timestamp 360 << ", len=" << payload.size(); 361 362 MediaChannel::SendPacket(&packet, rtc::PacketOptions()); 363 send_limiter_->Use(packet_len, now); 364 if (result) { 365 *result = SDR_SUCCESS; 366 } 367 return true; 368 } 369 370 } // namespace cricket 371