Home | History | Annotate | Download | only in base
      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