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