| Index: webrtc/pc/channel.cc
 | 
| diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
 | 
| index d99a1058683f0e6c51a00e862463edfcce6f9c05..59f0869431ae59aef1e26b3dbc555b0c897e7e14 100644
 | 
| --- a/webrtc/pc/channel.cc
 | 
| +++ b/webrtc/pc/channel.cc
 | 
| @@ -158,22 +158,18 @@
 | 
|        signaling_thread_(signaling_thread),
 | 
|        content_name_(content_name),
 | 
|        rtcp_mux_required_(rtcp_mux_required),
 | 
| +      rtp_transport_(
 | 
| +          srtp_required
 | 
| +              ? rtc::WrapUnique<webrtc::RtpTransportInternal>(
 | 
| +                    new webrtc::SrtpTransport(rtcp_mux_required, content_name))
 | 
| +              : rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required)),
 | 
|        srtp_required_(srtp_required),
 | 
|        media_channel_(media_channel),
 | 
|        selected_candidate_pair_(nullptr) {
 | 
|    RTC_DCHECK(worker_thread_ == rtc::Thread::Current());
 | 
| -  if (srtp_required) {
 | 
| -    auto transport =
 | 
| -        rtc::MakeUnique<webrtc::SrtpTransport>(rtcp_mux_required, content_name);
 | 
| -    srtp_transport_ = transport.get();
 | 
| -    rtp_transport_ = std::move(transport);
 | 
|  #if defined(ENABLE_EXTERNAL_AUTH)
 | 
| -    srtp_transport_->EnableExternalAuth();
 | 
| +  srtp_filter_.EnableExternalAuth();
 | 
|  #endif
 | 
| -  } else {
 | 
| -    rtp_transport_ = rtc::MakeUnique<webrtc::RtpTransport>(rtcp_mux_required);
 | 
| -    srtp_transport_ = nullptr;
 | 
| -  }
 | 
|    rtp_transport_->SignalReadyToSend.connect(
 | 
|        this, &BaseChannel::OnTransportReadyToSend);
 | 
|    // TODO(zstein):  RtpTransport::SignalPacketReceived will probably be replaced
 | 
| @@ -318,17 +314,14 @@
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  // When using DTLS-SRTP, we must reset the SrtpTransport every time the
 | 
| -  // DtlsTransport changes and wait until the DTLS handshake is complete to set
 | 
| -  // the newly negotiated parameters.
 | 
| +  // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport
 | 
| +  // changes and wait until the DTLS handshake is complete to set the newly
 | 
| +  // negotiated parameters.
 | 
|    if (ShouldSetupDtlsSrtp_n()) {
 | 
|      // Set |writable_| to false such that UpdateWritableState_w can set up
 | 
|      // DTLS-SRTP when |writable_| becomes true again.
 | 
|      writable_ = false;
 | 
| -    dtls_active_ = false;
 | 
| -    if (srtp_transport_) {
 | 
| -      srtp_transport_->ResetParams();
 | 
| -    }
 | 
| +    srtp_filter_.ResetParams();
 | 
|    }
 | 
|  
 | 
|    // If this BaseChannel doesn't require RTCP mux and we haven't fully
 | 
| @@ -384,8 +377,8 @@
 | 
|    }
 | 
|  
 | 
|    if (rtcp && new_dtls_transport) {
 | 
| -    RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_active()))
 | 
| -        << "Setting RTCP for DTLS/SRTP after the DTLS is active "
 | 
| +    RTC_CHECK(!(ShouldSetupDtlsSrtp_n() && srtp_filter_.IsActive()))
 | 
| +        << "Setting RTCP for DTLS/SRTP after SrtpFilter is active "
 | 
|          << "should never happen.";
 | 
|    }
 | 
|  
 | 
| @@ -536,7 +529,8 @@
 | 
|    // and we have had some form of connectivity.
 | 
|    return enabled() && IsReceiveContentDirection(remote_content_direction_) &&
 | 
|           IsSendContentDirection(local_content_direction_) &&
 | 
| -         was_ever_writable() && (srtp_active() || !ShouldSetupDtlsSrtp_n());
 | 
| +         was_ever_writable() &&
 | 
| +         (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp_n());
 | 
|  }
 | 
|  
 | 
|  bool BaseChannel::SendPacket(rtc::CopyOnWriteBuffer* packet,
 | 
| @@ -588,16 +582,13 @@
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  // Reset the SrtpTransport if it's not the CONNECTED state. For the CONNECTED
 | 
| +  // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED
 | 
|    // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to
 | 
|    // cover other scenarios like the whole transport is writable (not just this
 | 
|    // TransportChannel) or when TransportChannel is attached after DTLS is
 | 
|    // negotiated.
 | 
|    if (state != DTLS_TRANSPORT_CONNECTED) {
 | 
| -    dtls_active_ = false;
 | 
| -    if (srtp_transport_) {
 | 
| -      srtp_transport_->ResetParams();
 | 
| -    }
 | 
| +    srtp_filter_.ResetParams();
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -671,30 +662,91 @@
 | 
|      return false;
 | 
|    }
 | 
|  
 | 
| -  if (!srtp_active()) {
 | 
| -    if (srtp_required_) {
 | 
| -      // The audio/video engines may attempt to send RTCP packets as soon as the
 | 
| -      // streams are created, so don't treat this as an error for RTCP.
 | 
| -      // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
 | 
| -      if (rtcp) {
 | 
| +  rtc::PacketOptions updated_options;
 | 
| +  updated_options = options;
 | 
| +  // Protect if needed.
 | 
| +  if (srtp_filter_.IsActive()) {
 | 
| +    TRACE_EVENT0("webrtc", "SRTP Encode");
 | 
| +    bool res;
 | 
| +    uint8_t* data = packet->data();
 | 
| +    int len = static_cast<int>(packet->size());
 | 
| +    if (!rtcp) {
 | 
| +    // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
 | 
| +    // inside libsrtp for a RTP packet. A external HMAC module will be writing
 | 
| +    // a fake HMAC value. This is ONLY done for a RTP packet.
 | 
| +    // Socket layer will update rtp sendtime extension header if present in
 | 
| +    // packet with current time before updating the HMAC.
 | 
| +#if !defined(ENABLE_EXTERNAL_AUTH)
 | 
| +      res = srtp_filter_.ProtectRtp(
 | 
| +          data, len, static_cast<int>(packet->capacity()), &len);
 | 
| +#else
 | 
| +      if (!srtp_filter_.IsExternalAuthActive()) {
 | 
| +        res = srtp_filter_.ProtectRtp(
 | 
| +            data, len, static_cast<int>(packet->capacity()), &len);
 | 
| +      } else {
 | 
| +        updated_options.packet_time_params.rtp_sendtime_extension_id =
 | 
| +            rtp_abs_sendtime_extn_id_;
 | 
| +        res = srtp_filter_.ProtectRtp(
 | 
| +            data, len, static_cast<int>(packet->capacity()), &len,
 | 
| +            &updated_options.packet_time_params.srtp_packet_index);
 | 
| +        // If protection succeeds, let's get auth params from srtp.
 | 
| +        if (res) {
 | 
| +          uint8_t* auth_key = NULL;
 | 
| +          int key_len;
 | 
| +          res = srtp_filter_.GetRtpAuthParams(
 | 
| +              &auth_key, &key_len,
 | 
| +              &updated_options.packet_time_params.srtp_auth_tag_len);
 | 
| +          if (res) {
 | 
| +            updated_options.packet_time_params.srtp_auth_key.resize(key_len);
 | 
| +            updated_options.packet_time_params.srtp_auth_key.assign(
 | 
| +                auth_key, auth_key + key_len);
 | 
| +          }
 | 
| +        }
 | 
| +      }
 | 
| +#endif
 | 
| +      if (!res) {
 | 
| +        int seq_num = -1;
 | 
| +        uint32_t ssrc = 0;
 | 
| +        GetRtpSeqNum(data, len, &seq_num);
 | 
| +        GetRtpSsrc(data, len, &ssrc);
 | 
| +        LOG(LS_ERROR) << "Failed to protect " << content_name_
 | 
| +                      << " RTP packet: size=" << len
 | 
| +                      << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
 | 
|          return false;
 | 
|        }
 | 
| -      // However, there shouldn't be any RTP packets sent before SRTP is set up
 | 
| -      // (and SetSend(true) is called).
 | 
| -      LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive"
 | 
| -                    << " and crypto is required";
 | 
| -      RTC_NOTREACHED();
 | 
| +    } else {
 | 
| +      res = srtp_filter_.ProtectRtcp(data, len,
 | 
| +                                     static_cast<int>(packet->capacity()),
 | 
| +                                     &len);
 | 
| +      if (!res) {
 | 
| +        int type = -1;
 | 
| +        GetRtcpType(data, len, &type);
 | 
| +        LOG(LS_ERROR) << "Failed to protect " << content_name_
 | 
| +                      << " RTCP packet: size=" << len << ", type=" << type;
 | 
| +        return false;
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    // Update the length of the packet now that we've added the auth tag.
 | 
| +    packet->SetSize(len);
 | 
| +  } else if (srtp_required_) {
 | 
| +    // The audio/video engines may attempt to send RTCP packets as soon as the
 | 
| +    // streams are created, so don't treat this as an error for RTCP.
 | 
| +    // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=6809
 | 
| +    if (rtcp) {
 | 
|        return false;
 | 
|      }
 | 
| -    // Bon voyage.
 | 
| -    return rtcp ? rtp_transport_->SendRtcpPacket(packet, options, PF_NORMAL)
 | 
| -                : rtp_transport_->SendRtpPacket(packet, options, PF_NORMAL);
 | 
| -  }
 | 
| -  RTC_DCHECK(srtp_transport_);
 | 
| -  RTC_DCHECK(srtp_transport_->IsActive());
 | 
| +    // However, there shouldn't be any RTP packets sent before SRTP is set up
 | 
| +    // (and SetSend(true) is called).
 | 
| +    LOG(LS_ERROR) << "Can't send outgoing RTP packet when SRTP is inactive"
 | 
| +                  << " and crypto is required";
 | 
| +    RTC_NOTREACHED();
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
|    // Bon voyage.
 | 
| -  return rtcp ? srtp_transport_->SendRtcpPacket(packet, options, PF_SRTP_BYPASS)
 | 
| -              : srtp_transport_->SendRtpPacket(packet, options, PF_SRTP_BYPASS);
 | 
| +  int flags = (secure() && secure_dtls()) ? PF_SRTP_BYPASS : PF_NORMAL;
 | 
| +  return rtp_transport_->SendPacket(rtcp, packet, updated_options, flags);
 | 
|  }
 | 
|  
 | 
|  bool BaseChannel::HandlesPayloadType(int packet_type) const {
 | 
| @@ -709,7 +761,37 @@
 | 
|      signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
 | 
|    }
 | 
|  
 | 
| -  if (!srtp_active() && srtp_required_) {
 | 
| +  // Unprotect the packet, if needed.
 | 
| +  if (srtp_filter_.IsActive()) {
 | 
| +    TRACE_EVENT0("webrtc", "SRTP Decode");
 | 
| +    char* data = packet->data<char>();
 | 
| +    int len = static_cast<int>(packet->size());
 | 
| +    bool res;
 | 
| +    if (!rtcp) {
 | 
| +      res = srtp_filter_.UnprotectRtp(data, len, &len);
 | 
| +      if (!res) {
 | 
| +        int seq_num = -1;
 | 
| +        uint32_t ssrc = 0;
 | 
| +        GetRtpSeqNum(data, len, &seq_num);
 | 
| +        GetRtpSsrc(data, len, &ssrc);
 | 
| +        LOG(LS_ERROR) << "Failed to unprotect " << content_name_
 | 
| +                      << " RTP packet: size=" << len << ", seqnum=" << seq_num
 | 
| +                      << ", SSRC=" << ssrc;
 | 
| +        return;
 | 
| +      }
 | 
| +    } else {
 | 
| +      res = srtp_filter_.UnprotectRtcp(data, len, &len);
 | 
| +      if (!res) {
 | 
| +        int type = -1;
 | 
| +        GetRtcpType(data, len, &type);
 | 
| +        LOG(LS_ERROR) << "Failed to unprotect " << content_name_
 | 
| +                      << " RTCP packet: size=" << len << ", type=" << type;
 | 
| +        return;
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    packet->SetSize(len);
 | 
| +  } else if (srtp_required_) {
 | 
|      // Our session description indicates that SRTP is required, but we got a
 | 
|      // packet before our SRTP filter is active. This means either that
 | 
|      // a) we got SRTP packets before we received the SDES keys, in which case
 | 
| @@ -913,46 +995,48 @@
 | 
|      recv_key = &server_write_key;
 | 
|    }
 | 
|  
 | 
| -  if (rtcp) {
 | 
| -    if (!dtls_active()) {
 | 
| -      RTC_DCHECK(srtp_transport_);
 | 
| -      ret = srtp_transport_->SetRtcpParams(
 | 
| -          selected_crypto_suite, &(*send_key)[0],
 | 
| -          static_cast<int>(send_key->size()), selected_crypto_suite,
 | 
| -          &(*recv_key)[0], static_cast<int>(recv_key->size()));
 | 
| +  if (!srtp_filter_.IsActive()) {
 | 
| +    if (rtcp) {
 | 
| +      ret = srtp_filter_.SetRtcpParams(selected_crypto_suite, &(*send_key)[0],
 | 
| +                                       static_cast<int>(send_key->size()),
 | 
| +                                       selected_crypto_suite, &(*recv_key)[0],
 | 
| +                                       static_cast<int>(recv_key->size()));
 | 
|      } else {
 | 
| -      // RTCP doesn't need to call SetRtpParam because it is only used
 | 
| -      // to make the updated encrypted RTP header extension IDs take effect.
 | 
| -      ret = true;
 | 
| +      ret = srtp_filter_.SetRtpParams(selected_crypto_suite, &(*send_key)[0],
 | 
| +                                      static_cast<int>(send_key->size()),
 | 
| +                                      selected_crypto_suite, &(*recv_key)[0],
 | 
| +                                      static_cast<int>(recv_key->size()));
 | 
|      }
 | 
|    } else {
 | 
| -    RTC_DCHECK(srtp_transport_);
 | 
| -    ret = srtp_transport_->SetRtpParams(selected_crypto_suite, &(*send_key)[0],
 | 
| -                                        static_cast<int>(send_key->size()),
 | 
| -                                        selected_crypto_suite, &(*recv_key)[0],
 | 
| -                                        static_cast<int>(recv_key->size()));
 | 
| -    dtls_active_ = ret;
 | 
| +    if (rtcp) {
 | 
| +      // RTCP doesn't need to be updated because UpdateRtpParams is only used
 | 
| +      // to update the set of encrypted RTP header extension IDs.
 | 
| +      ret = true;
 | 
| +    } else {
 | 
| +      ret = srtp_filter_.UpdateRtpParams(
 | 
| +          selected_crypto_suite,
 | 
| +          &(*send_key)[0], static_cast<int>(send_key->size()),
 | 
| +          selected_crypto_suite,
 | 
| +          &(*recv_key)[0], static_cast<int>(recv_key->size()));
 | 
| +    }
 | 
|    }
 | 
|  
 | 
|    if (!ret) {
 | 
|      LOG(LS_WARNING) << "DTLS-SRTP key installation failed";
 | 
|    } else {
 | 
| +    dtls_keyed_ = true;
 | 
|      UpdateTransportOverhead();
 | 
|    }
 | 
|    return ret;
 | 
|  }
 | 
|  
 | 
|  void BaseChannel::MaybeSetupDtlsSrtp_n() {
 | 
| -  if (dtls_active()) {
 | 
| +  if (srtp_filter_.IsActive()) {
 | 
|      return;
 | 
|    }
 | 
|  
 | 
|    if (!ShouldSetupDtlsSrtp_n()) {
 | 
|      return;
 | 
| -  }
 | 
| -
 | 
| -  if (!srtp_transport_) {
 | 
| -    EnableSrtpTransport_n();
 | 
|    }
 | 
|  
 | 
|    if (!SetupDtlsSrtp_n(false)) {
 | 
| @@ -1038,24 +1122,6 @@
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| -void BaseChannel::EnableSrtpTransport_n() {
 | 
| -  if (srtp_transport_ == nullptr) {
 | 
| -    rtp_transport_->SignalReadyToSend.disconnect(this);
 | 
| -    rtp_transport_->SignalPacketReceived.disconnect(this);
 | 
| -
 | 
| -    auto transport = rtc::MakeUnique<webrtc::SrtpTransport>(
 | 
| -        std::move(rtp_transport_), content_name_);
 | 
| -    srtp_transport_ = transport.get();
 | 
| -    rtp_transport_ = std::move(transport);
 | 
| -
 | 
| -    rtp_transport_->SignalReadyToSend.connect(
 | 
| -        this, &BaseChannel::OnTransportReadyToSend);
 | 
| -    rtp_transport_->SignalPacketReceived.connect(
 | 
| -        this, &BaseChannel::OnPacketReceived);
 | 
| -    LOG(LS_INFO) << "Wrapping RtpTransport in SrtpTransport.";
 | 
| -  }
 | 
| -}
 | 
| -
 | 
|  bool BaseChannel::SetSrtp_n(const std::vector<CryptoParams>& cryptos,
 | 
|                              ContentAction action,
 | 
|                              ContentSource src,
 | 
| @@ -1072,69 +1138,36 @@
 | 
|    if (!ret) {
 | 
|      return false;
 | 
|    }
 | 
| -
 | 
| -  // If SRTP was not required, but we're setting a description that uses SDES,
 | 
| -  // we need to upgrade to an SrtpTransport.
 | 
| -  if (!srtp_transport_ && !dtls && !cryptos.empty()) {
 | 
| -    EnableSrtpTransport_n();
 | 
| -  }
 | 
| -  if (srtp_transport_) {
 | 
| -    srtp_transport_->SetEncryptedHeaderExtensionIds(src,
 | 
| -                                                    encrypted_extension_ids);
 | 
| -  }
 | 
| +  srtp_filter_.SetEncryptedHeaderExtensionIds(src, encrypted_extension_ids);
 | 
|    switch (action) {
 | 
|      case CA_OFFER:
 | 
|        // If DTLS is already active on the channel, we could be renegotiating
 | 
|        // here. We don't update the srtp filter.
 | 
|        if (!dtls) {
 | 
| -        ret = sdes_negotiator_.SetOffer(cryptos, src);
 | 
| +        ret = srtp_filter_.SetOffer(cryptos, src);
 | 
|        }
 | 
|        break;
 | 
|      case CA_PRANSWER:
 | 
|        // If we're doing DTLS-SRTP, we don't want to update the filter
 | 
|        // with an answer, because we already have SRTP parameters.
 | 
|        if (!dtls) {
 | 
| -        ret = sdes_negotiator_.SetProvisionalAnswer(cryptos, src);
 | 
| +        ret = srtp_filter_.SetProvisionalAnswer(cryptos, src);
 | 
|        }
 | 
|        break;
 | 
|      case CA_ANSWER:
 | 
|        // If we're doing DTLS-SRTP, we don't want to update the filter
 | 
|        // with an answer, because we already have SRTP parameters.
 | 
|        if (!dtls) {
 | 
| -        ret = sdes_negotiator_.SetAnswer(cryptos, src);
 | 
| +        ret = srtp_filter_.SetAnswer(cryptos, src);
 | 
|        }
 | 
|        break;
 | 
|      default:
 | 
|        break;
 | 
|    }
 | 
| -
 | 
| -  // If setting an SDES answer succeeded, apply the negotiated parameters
 | 
| -  // to the SRTP transport.
 | 
| -  if ((action == CA_PRANSWER || action == CA_ANSWER) && !dtls && ret) {
 | 
| -    if (sdes_negotiator_.send_cipher_suite() &&
 | 
| -        sdes_negotiator_.recv_cipher_suite()) {
 | 
| -      ret = srtp_transport_->SetRtpParams(
 | 
| -          *(sdes_negotiator_.send_cipher_suite()),
 | 
| -          sdes_negotiator_.send_key().data(),
 | 
| -          static_cast<int>(sdes_negotiator_.send_key().size()),
 | 
| -          *(sdes_negotiator_.recv_cipher_suite()),
 | 
| -          sdes_negotiator_.recv_key().data(),
 | 
| -          static_cast<int>(sdes_negotiator_.recv_key().size()));
 | 
| -    } else {
 | 
| -      LOG(LS_INFO) << "No crypto keys are provided for SDES.";
 | 
| -      if (action == CA_ANSWER && srtp_transport_) {
 | 
| -        // Explicitly reset the |srtp_transport_| if no crypto param is
 | 
| -        // provided in the answer. No need to call |ResetParams()| for
 | 
| -        // |sdes_negotiator_| because it resets the params inside |SetAnswer|.
 | 
| -        srtp_transport_->ResetParams();
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
|    // Only update SRTP filter if using DTLS. SDES is handled internally
 | 
|    // by the SRTP filter.
 | 
|    // TODO(jbauch): Only update if encrypted extension ids have changed.
 | 
| -  if (ret && dtls_active() && rtp_dtls_transport_ &&
 | 
| +  if (ret && dtls_keyed_ && rtp_dtls_transport_ &&
 | 
|        rtp_dtls_transport_->dtls_state() == DTLS_TRANSPORT_CONNECTED) {
 | 
|      bool rtcp = false;
 | 
|      ret = SetupDtlsSrtp_n(rtcp);
 | 
| @@ -1178,6 +1211,7 @@
 | 
|              transport_name_.empty()
 | 
|                  ? rtp_transport_->rtp_packet_transport()->debug_name()
 | 
|                  : transport_name_;
 | 
| +        ;
 | 
|          LOG(LS_INFO) << "Enabling rtcp-mux for " << content_name()
 | 
|                       << "; no longer need RTCP transport for " << debug_name;
 | 
|          if (rtp_transport_->rtcp_packet_transport()) {
 | 
| @@ -1406,13 +1440,7 @@
 | 
|  
 | 
|  void BaseChannel::CacheRtpAbsSendTimeHeaderExtension_n(
 | 
|      int rtp_abs_sendtime_extn_id) {
 | 
| -  if (srtp_transport_) {
 | 
| -    srtp_transport_->CacheRtpAbsSendTimeHeaderExtension(
 | 
| -        rtp_abs_sendtime_extn_id);
 | 
| -  } else {
 | 
| -    LOG(LS_WARNING) << "Trying to cache the Absolute Send Time extension id "
 | 
| -                       "but the SRTP is not active.";
 | 
| -  }
 | 
| +  rtp_abs_sendtime_extn_id_ = rtp_abs_sendtime_extn_id;
 | 
|  }
 | 
|  
 | 
|  void BaseChannel::OnMessage(rtc::Message *pmsg) {
 | 
| @@ -1696,9 +1724,9 @@
 | 
|            ? kTcpOverhaed
 | 
|            : kUdpOverhaed;
 | 
|  
 | 
| -  if (sdes_active()) {
 | 
| +  if (secure()) {
 | 
|      int srtp_overhead = 0;
 | 
| -    if (srtp_transport_->GetSrtpOverhead(&srtp_overhead))
 | 
| +    if (srtp_filter_.GetSrtpOverhead(&srtp_overhead))
 | 
|        transport_overhead_per_packet += srtp_overhead;
 | 
|    }
 | 
|  
 | 
| 
 |