| Index: webrtc/pc/channel.cc | 
| diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc | 
| index 56335e24d085c74c37050233eb6ca6b73b75adaa..1f29261ed2532bdf7422792b5e9878b7a06e3efc 100644 | 
| --- a/webrtc/pc/channel.cc | 
| +++ b/webrtc/pc/channel.cc | 
| @@ -69,6 +69,7 @@ enum { | 
| MSG_READYTOSENDDATA, | 
| MSG_DATARECEIVED, | 
| MSG_FIRSTPACKETRECEIVED, | 
| +  MSG_STREAMCLOSEDREMOTELY, | 
| }; | 
|  | 
| // Value specified in RFC 5764. | 
| @@ -930,16 +931,16 @@ void BaseChannel::ChannelWritable_n() { | 
| UpdateMediaSendRecvState(); | 
| } | 
|  | 
| -void BaseChannel::SignalDtlsSrtpSetupFailure_n(bool rtcp) { | 
| +void BaseChannel::SignalDtlsSetupFailure_n(bool rtcp) { | 
| RTC_DCHECK(network_thread_->IsCurrent()); | 
| invoker_.AsyncInvoke<void>( | 
| RTC_FROM_HERE, signaling_thread(), | 
| -      Bind(&BaseChannel::SignalDtlsSrtpSetupFailure_s, this, rtcp)); | 
| +      Bind(&BaseChannel::SignalDtlsSetupFailure_s, this, rtcp)); | 
| } | 
|  | 
| -void BaseChannel::SignalDtlsSrtpSetupFailure_s(bool rtcp) { | 
| +void BaseChannel::SignalDtlsSetupFailure_s(bool rtcp) { | 
| RTC_DCHECK(signaling_thread() == rtc::Thread::Current()); | 
| -  SignalDtlsSrtpSetupFailure(this, rtcp); | 
| +  SignalDtlsSetupFailure(this, rtcp); | 
| } | 
|  | 
| bool BaseChannel::SetDtlsSrtpCryptoSuites_n(TransportChannel* tc, bool rtcp) { | 
| @@ -1060,13 +1061,13 @@ void BaseChannel::MaybeSetupDtlsSrtp_n() { | 
| } | 
|  | 
| if (!SetupDtlsSrtp_n(false)) { | 
| -    SignalDtlsSrtpSetupFailure_n(false); | 
| +    SignalDtlsSetupFailure_n(false); | 
| return; | 
| } | 
|  | 
| if (rtcp_transport_channel_) { | 
| if (!SetupDtlsSrtp_n(true)) { | 
| -      SignalDtlsSrtpSetupFailure_n(true); | 
| +      SignalDtlsSetupFailure_n(true); | 
| return; | 
| } | 
| } | 
| @@ -2146,23 +2147,25 @@ void VideoChannel::GetSrtpCryptoSuites_n( | 
| GetSupportedVideoCryptoSuites(crypto_options(), crypto_suites); | 
| } | 
|  | 
| -RtpDataChannel::RtpDataChannel(rtc::Thread* worker_thread, | 
| -                               rtc::Thread* network_thread, | 
| -                               DataMediaChannel* media_channel, | 
| -                               TransportController* transport_controller, | 
| -                               const std::string& content_name, | 
| -                               bool rtcp, | 
| -                               bool srtp_required) | 
| +DataChannel::DataChannel(rtc::Thread* worker_thread, | 
| +                         rtc::Thread* network_thread, | 
| +                         DataMediaChannel* media_channel, | 
| +                         TransportController* transport_controller, | 
| +                         const std::string& content_name, | 
| +                         bool rtcp, | 
| +                         bool srtp_required) | 
| : BaseChannel(worker_thread, | 
| network_thread, | 
| media_channel, | 
| transport_controller, | 
| content_name, | 
| rtcp, | 
| -                  srtp_required) {} | 
| +                  srtp_required), | 
| +      data_channel_type_(cricket::DCT_NONE), | 
| +      ready_to_send_data_(false) {} | 
|  | 
| -RtpDataChannel::~RtpDataChannel() { | 
| -  TRACE_EVENT0("webrtc", "RtpDataChannel::~RtpDataChannel"); | 
| +DataChannel::~DataChannel() { | 
| +  TRACE_EVENT0("webrtc", "DataChannel::~DataChannel"); | 
| StopMediaMonitor(); | 
| // this can't be done in the base class, since it calls a virtual | 
| DisableMedia_w(); | 
| @@ -2170,48 +2173,78 @@ RtpDataChannel::~RtpDataChannel() { | 
| Deinit(); | 
| } | 
|  | 
| -bool RtpDataChannel::Init_w(const std::string* bundle_transport_name) { | 
| +bool DataChannel::Init_w(const std::string* bundle_transport_name) { | 
| if (!BaseChannel::Init_w(bundle_transport_name)) { | 
| return false; | 
| } | 
| -  media_channel()->SignalDataReceived.connect(this, | 
| -                                              &RtpDataChannel::OnDataReceived); | 
| +  media_channel()->SignalDataReceived.connect( | 
| +      this, &DataChannel::OnDataReceived); | 
| media_channel()->SignalReadyToSend.connect( | 
| -      this, &RtpDataChannel::OnDataChannelReadyToSend); | 
| +      this, &DataChannel::OnDataChannelReadyToSend); | 
| +  media_channel()->SignalStreamClosedRemotely.connect( | 
| +      this, &DataChannel::OnStreamClosedRemotely); | 
| return true; | 
| } | 
|  | 
| -bool RtpDataChannel::SendData(const SendDataParams& params, | 
| -                              const rtc::CopyOnWriteBuffer& payload, | 
| -                              SendDataResult* result) { | 
| +bool DataChannel::SendData(const SendDataParams& params, | 
| +                           const rtc::CopyOnWriteBuffer& payload, | 
| +                           SendDataResult* result) { | 
| return InvokeOnWorker( | 
| RTC_FROM_HERE, Bind(&DataMediaChannel::SendData, media_channel(), params, | 
| payload, result)); | 
| } | 
|  | 
| -const ContentInfo* RtpDataChannel::GetFirstContent( | 
| +const ContentInfo* DataChannel::GetFirstContent( | 
| const SessionDescription* sdesc) { | 
| return GetFirstDataContent(sdesc); | 
| } | 
|  | 
| -bool RtpDataChannel::CheckDataChannelTypeFromContent( | 
| -    const DataContentDescription* content, | 
| -    std::string* error_desc) { | 
| -  bool is_sctp = ((content->protocol() == kMediaProtocolSctp) || | 
| -                  (content->protocol() == kMediaProtocolDtlsSctp)); | 
| +bool DataChannel::WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet) { | 
| +  if (data_channel_type_ == DCT_SCTP) { | 
| +    // TODO(pthatcher): Do this in a more robust way by checking for | 
| +    // SCTP or DTLS. | 
| +    return !IsRtpPacket(packet->data(), packet->size()); | 
| +  } else if (data_channel_type_ == DCT_RTP) { | 
| +    return BaseChannel::WantsPacket(rtcp, packet); | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| +bool DataChannel::SetDataChannelType(DataChannelType new_data_channel_type, | 
| +                                     std::string* error_desc) { | 
| +  // It hasn't been set before, so set it now. | 
| +  if (data_channel_type_ == DCT_NONE) { | 
| +    data_channel_type_ = new_data_channel_type; | 
| +    return true; | 
| +  } | 
| + | 
| // It's been set before, but doesn't match.  That's bad. | 
| -  if (is_sctp) { | 
| -    SafeSetError("Data channel type mismatch. Expected RTP, got SCTP.", | 
| -                 error_desc); | 
| +  if (data_channel_type_ != new_data_channel_type) { | 
| +    std::ostringstream desc; | 
| +    desc << "Data channel type mismatch." | 
| +         << " Expected " << data_channel_type_ | 
| +         << " Got " << new_data_channel_type; | 
| +    SafeSetError(desc.str(), error_desc); | 
| return false; | 
| } | 
| + | 
| +  // It's hasn't changed.  Nothing to do. | 
| return true; | 
| } | 
|  | 
| -bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, | 
| -                                       ContentAction action, | 
| -                                       std::string* error_desc) { | 
| -  TRACE_EVENT0("webrtc", "RtpDataChannel::SetLocalContent_w"); | 
| +bool DataChannel::SetDataChannelTypeFromContent( | 
| +    const DataContentDescription* content, | 
| +    std::string* error_desc) { | 
| +  bool is_sctp = ((content->protocol() == kMediaProtocolSctp) || | 
| +                  (content->protocol() == kMediaProtocolDtlsSctp)); | 
| +  DataChannelType data_channel_type = is_sctp ? DCT_SCTP : DCT_RTP; | 
| +  return SetDataChannelType(data_channel_type, error_desc); | 
| +} | 
| + | 
| +bool DataChannel::SetLocalContent_w(const MediaContentDescription* content, | 
| +                                    ContentAction action, | 
| +                                    std::string* error_desc) { | 
| +  TRACE_EVENT0("webrtc", "DataChannel::SetLocalContent_w"); | 
| RTC_DCHECK(worker_thread() == rtc::Thread::Current()); | 
| LOG(LS_INFO) << "Setting local data description"; | 
|  | 
| @@ -2223,14 +2256,19 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, | 
| return false; | 
| } | 
|  | 
| -  if (!CheckDataChannelTypeFromContent(data, error_desc)) { | 
| +  if (!SetDataChannelTypeFromContent(data, error_desc)) { | 
| return false; | 
| } | 
|  | 
| -  if (!SetRtpTransportParameters(content, action, CS_LOCAL, error_desc)) { | 
| -    return false; | 
| +  if (data_channel_type_ == DCT_RTP) { | 
| +    if (!SetRtpTransportParameters(content, action, CS_LOCAL, error_desc)) { | 
| +      return false; | 
| +    } | 
| } | 
|  | 
| +  // FYI: We send the SCTP port number (not to be confused with the | 
| +  // underlying UDP port number) as a codec parameter.  So even SCTP | 
| +  // data channels need codecs. | 
| DataRecvParameters recv_params = last_recv_params_; | 
| RtpParametersFromMediaDescription(data, &recv_params); | 
| if (!media_channel()->SetRecvParameters(recv_params)) { | 
| @@ -2238,8 +2276,10 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, | 
| error_desc); | 
| return false; | 
| } | 
| -  for (const DataCodec& codec : data->codecs()) { | 
| -    bundle_filter()->AddPayloadType(codec.id); | 
| +  if (data_channel_type_ == DCT_RTP) { | 
| +    for (const DataCodec& codec : data->codecs()) { | 
| +      bundle_filter()->AddPayloadType(codec.id); | 
| +    } | 
| } | 
| last_recv_params_ = recv_params; | 
|  | 
| @@ -2257,10 +2297,10 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content, | 
| return true; | 
| } | 
|  | 
| -bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content, | 
| -                                        ContentAction action, | 
| -                                        std::string* error_desc) { | 
| -  TRACE_EVENT0("webrtc", "RtpDataChannel::SetRemoteContent_w"); | 
| +bool DataChannel::SetRemoteContent_w(const MediaContentDescription* content, | 
| +                                     ContentAction action, | 
| +                                     std::string* error_desc) { | 
| +  TRACE_EVENT0("webrtc", "DataChannel::SetRemoteContent_w"); | 
| RTC_DCHECK(worker_thread() == rtc::Thread::Current()); | 
|  | 
| const DataContentDescription* data = | 
| @@ -2277,15 +2317,17 @@ bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content, | 
| return true; | 
| } | 
|  | 
| -  if (!CheckDataChannelTypeFromContent(data, error_desc)) { | 
| +  if (!SetDataChannelTypeFromContent(data, error_desc)) { | 
| return false; | 
| } | 
|  | 
| LOG(LS_INFO) << "Setting remote data description"; | 
| -  if (!SetRtpTransportParameters(content, action, CS_REMOTE, error_desc)) { | 
| +  if (data_channel_type_ == DCT_RTP && | 
| +      !SetRtpTransportParameters(content, action, CS_REMOTE, error_desc)) { | 
| return false; | 
| } | 
|  | 
| + | 
| DataSendParameters send_params = last_send_params_; | 
| RtpSendParametersFromMediaDescription<DataCodec>(data, &send_params); | 
| if (!media_channel()->SetSendParameters(send_params)) { | 
| @@ -2310,7 +2352,7 @@ bool RtpDataChannel::SetRemoteContent_w(const MediaContentDescription* content, | 
| return true; | 
| } | 
|  | 
| -void RtpDataChannel::UpdateMediaSendRecvState_w() { | 
| +void DataChannel::UpdateMediaSendRecvState_w() { | 
| // Render incoming data if we're the active call, and we have the local | 
| // content. We receive data on the default channel and multiplexed streams. | 
| bool recv = IsReadyToReceiveMedia_w(); | 
| @@ -2331,7 +2373,7 @@ void RtpDataChannel::UpdateMediaSendRecvState_w() { | 
| LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send; | 
| } | 
|  | 
| -void RtpDataChannel::OnMessage(rtc::Message* pmsg) { | 
| +void DataChannel::OnMessage(rtc::Message *pmsg) { | 
| switch (pmsg->message_id) { | 
| case MSG_READYTOSENDDATA: { | 
| DataChannelReadyToSendMessageData* data = | 
| @@ -2344,7 +2386,7 @@ void RtpDataChannel::OnMessage(rtc::Message* pmsg) { | 
| case MSG_DATARECEIVED: { | 
| DataReceivedMessageData* data = | 
| static_cast<DataReceivedMessageData*>(pmsg->pdata); | 
| -      SignalDataReceived(data->params, data->payload); | 
| +      SignalDataReceived(this, data->params, data->payload); | 
| delete data; | 
| break; | 
| } | 
| @@ -2354,27 +2396,33 @@ void RtpDataChannel::OnMessage(rtc::Message* pmsg) { | 
| delete data; | 
| break; | 
| } | 
| +    case MSG_STREAMCLOSEDREMOTELY: { | 
| +      rtc::TypedMessageData<uint32_t>* data = | 
| +          static_cast<rtc::TypedMessageData<uint32_t>*>(pmsg->pdata); | 
| +      SignalStreamClosedRemotely(data->data()); | 
| +      delete data; | 
| +      break; | 
| +    } | 
| default: | 
| BaseChannel::OnMessage(pmsg); | 
| break; | 
| } | 
| } | 
|  | 
| -void RtpDataChannel::OnConnectionMonitorUpdate( | 
| -    ConnectionMonitor* monitor, | 
| -    const std::vector<ConnectionInfo>& infos) { | 
| +void DataChannel::OnConnectionMonitorUpdate( | 
| +    ConnectionMonitor* monitor, const std::vector<ConnectionInfo>& infos) { | 
| SignalConnectionMonitor(this, infos); | 
| } | 
|  | 
| -void RtpDataChannel::StartMediaMonitor(int cms) { | 
| +void DataChannel::StartMediaMonitor(int cms) { | 
| media_monitor_.reset(new DataMediaMonitor(media_channel(), worker_thread(), | 
| rtc::Thread::Current())); | 
| -  media_monitor_->SignalUpdate.connect(this, | 
| -                                       &RtpDataChannel::OnMediaMonitorUpdate); | 
| +  media_monitor_->SignalUpdate.connect( | 
| +      this, &DataChannel::OnMediaMonitorUpdate); | 
| media_monitor_->Start(cms); | 
| } | 
|  | 
| -void RtpDataChannel::StopMediaMonitor() { | 
| +void DataChannel::StopMediaMonitor() { | 
| if (media_monitor_) { | 
| media_monitor_->Stop(); | 
| media_monitor_->SignalUpdate.disconnect(this); | 
| @@ -2382,28 +2430,27 @@ void RtpDataChannel::StopMediaMonitor() { | 
| } | 
| } | 
|  | 
| -void RtpDataChannel::OnMediaMonitorUpdate(DataMediaChannel* media_channel, | 
| -                                          const DataMediaInfo& info) { | 
| +void DataChannel::OnMediaMonitorUpdate( | 
| +    DataMediaChannel* media_channel, const DataMediaInfo& info) { | 
| RTC_DCHECK(media_channel == this->media_channel()); | 
| SignalMediaMonitor(this, info); | 
| } | 
|  | 
| -void RtpDataChannel::OnDataReceived(const ReceiveDataParams& params, | 
| -                                    const char* data, | 
| -                                    size_t len) { | 
| +void DataChannel::OnDataReceived( | 
| +    const ReceiveDataParams& params, const char* data, size_t len) { | 
| DataReceivedMessageData* msg = new DataReceivedMessageData( | 
| params, data, len); | 
| signaling_thread()->Post(RTC_FROM_HERE, this, MSG_DATARECEIVED, msg); | 
| } | 
|  | 
| -void RtpDataChannel::OnDataChannelError(uint32_t ssrc, | 
| -                                        DataMediaChannel::Error err) { | 
| +void DataChannel::OnDataChannelError(uint32_t ssrc, | 
| +                                     DataMediaChannel::Error err) { | 
| DataChannelErrorMessageData* data = new DataChannelErrorMessageData( | 
| ssrc, err); | 
| signaling_thread()->Post(RTC_FROM_HERE, this, MSG_CHANNEL_ERROR, data); | 
| } | 
|  | 
| -void RtpDataChannel::OnDataChannelReadyToSend(bool writable) { | 
| +void DataChannel::OnDataChannelReadyToSend(bool writable) { | 
| // This is usded for congestion control to indicate that the stream is ready | 
| // to send by the MediaChannel, as opposed to OnReadyToSend, which indicates | 
| // that the transport channel is ready. | 
| @@ -2411,9 +2458,19 @@ void RtpDataChannel::OnDataChannelReadyToSend(bool writable) { | 
| new DataChannelReadyToSendMessageData(writable)); | 
| } | 
|  | 
| -void RtpDataChannel::GetSrtpCryptoSuites_n( | 
| -    std::vector<int>* crypto_suites) const { | 
| +void DataChannel::GetSrtpCryptoSuites_n(std::vector<int>* crypto_suites) const { | 
| GetSupportedDataCryptoSuites(crypto_options(), crypto_suites); | 
| } | 
|  | 
| +bool DataChannel::ShouldSetupDtlsSrtp_n() const { | 
| +  return data_channel_type_ == DCT_RTP && BaseChannel::ShouldSetupDtlsSrtp_n(); | 
| +} | 
| + | 
| +void DataChannel::OnStreamClosedRemotely(uint32_t sid) { | 
| +  rtc::TypedMessageData<uint32_t>* message = | 
| +      new rtc::TypedMessageData<uint32_t>(sid); | 
| +  signaling_thread()->Post(RTC_FROM_HERE, this, MSG_STREAMCLOSEDREMOTELY, | 
| +                           message); | 
| +} | 
| + | 
| }  // namespace cricket | 
|  |