| Index: talk/app/webrtc/webrtcsession.cc | 
| diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc | 
| index 1fc2a37902740aeda83a8d3c3e58d90aa9d9117c..e8749bbd86483e23c00943b9b9c231851b1bc8df 100644 | 
| --- a/talk/app/webrtc/webrtcsession.cc | 
| +++ b/talk/app/webrtc/webrtcsession.cc | 
| @@ -474,11 +474,12 @@ uint32_t ConvertIceTransportTypeToCandidateFilter( | 
| return cricket::CF_NONE; | 
| } | 
|  | 
| -// Help class used to remember if a a remote peer has requested ice restart by | 
| +// Helper class used to remember if a a remote peer has requested ICE restart by | 
| // by sending a description with new ice ufrag and password. | 
| class IceRestartAnswerLatch { | 
| public: | 
| -  IceRestartAnswerLatch() : ice_restart_(false) { } | 
| +  IceRestartAnswerLatch(cricket::MediaType media_type) | 
| +      : ice_restart_(false), media_type_(media_type) {} | 
|  | 
| // Returns true if CheckForRemoteIceRestart has been called with a new session | 
| // description where ice password and ufrag has changed since last time | 
| @@ -487,11 +488,7 @@ class IceRestartAnswerLatch { | 
| return ice_restart_; | 
| } | 
|  | 
| -  void Reset() { | 
| -    if (ice_restart_) { | 
| -      ice_restart_ = false; | 
| -    } | 
| -  } | 
| +  void Reset() { ice_restart_ = false; } | 
|  | 
| bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc, | 
| const SessionDescriptionInterface* new_desc) { | 
| @@ -500,36 +497,34 @@ class IceRestartAnswerLatch { | 
| } | 
| const SessionDescription* new_sd = new_desc->description(); | 
| const SessionDescription* old_sd = old_desc->description(); | 
| -    const ContentInfos& contents = new_sd->contents(); | 
| -    for (size_t index = 0; index < contents.size(); ++index) { | 
| -      const ContentInfo* cinfo = &contents[index]; | 
| -      if (cinfo->rejected) { | 
| -        continue; | 
| -      } | 
| -      // If the content isn't rejected, check if ufrag and password has | 
| -      // changed. | 
| -      const cricket::TransportDescription* new_transport_desc = | 
| -          new_sd->GetTransportDescriptionByName(cinfo->name); | 
| -      const cricket::TransportDescription* old_transport_desc = | 
| -          old_sd->GetTransportDescriptionByName(cinfo->name); | 
| -      if (!new_transport_desc || !old_transport_desc) { | 
| -        // No transport description exist. This is not an ice restart. | 
| -        continue; | 
| -      } | 
| -      if (cricket::IceCredentialsChanged(old_transport_desc->ice_ufrag, | 
| -                                         old_transport_desc->ice_pwd, | 
| -                                         new_transport_desc->ice_ufrag, | 
| -                                         new_transport_desc->ice_pwd)) { | 
| -        LOG(LS_INFO) << "Remote peer request ice restart."; | 
| -        ice_restart_ = true; | 
| -        return true; | 
| -      } | 
| +    const ContentInfo* cinfo = | 
| +        GetFirstMediaContent(new_sd->contents(), media_type_); | 
| +    if (!cinfo || cinfo->rejected) { | 
| +      return false; | 
| +    } | 
| +    // If the content isn't rejected, check if ufrag and password has changed. | 
| +    const cricket::TransportDescription* new_transport_desc = | 
| +        new_sd->GetTransportDescriptionByName(cinfo->name); | 
| +    const cricket::TransportDescription* old_transport_desc = | 
| +        old_sd->GetTransportDescriptionByName(cinfo->name); | 
| +    if (!new_transport_desc || !old_transport_desc) { | 
| +      // No transport description exists. This is not an ICE restart. | 
| +      return false; | 
| +    } | 
| +    if (cricket::IceCredentialsChanged( | 
| +            old_transport_desc->ice_ufrag, old_transport_desc->ice_pwd, | 
| +            new_transport_desc->ice_ufrag, new_transport_desc->ice_pwd)) { | 
| +      LOG(LS_INFO) << "Remote peer requested ICE restart for media type: " | 
| +                   << media_type_; | 
| +      ice_restart_ = true; | 
| +      return true; | 
| } | 
| return false; | 
| } | 
|  | 
| private: | 
| bool ice_restart_; | 
| +  cricket::MediaType media_type_; | 
| }; | 
|  | 
| WebRtcSession::WebRtcSession(webrtc::MediaControllerInterface* media_controller, | 
| @@ -554,7 +549,12 @@ WebRtcSession::WebRtcSession(webrtc::MediaControllerInterface* media_controller, | 
| older_version_remote_peer_(false), | 
| dtls_enabled_(false), | 
| data_channel_type_(cricket::DCT_NONE), | 
| -      ice_restart_latch_(new IceRestartAnswerLatch), | 
| +      audio_ice_restart_latch_( | 
| +          new IceRestartAnswerLatch(cricket::MEDIA_TYPE_AUDIO)), | 
| +      video_ice_restart_latch_( | 
| +          new IceRestartAnswerLatch(cricket::MEDIA_TYPE_VIDEO)), | 
| +      data_ice_restart_latch_( | 
| +          new IceRestartAnswerLatch(cricket::MEDIA_TYPE_DATA)), | 
| metrics_observer_(NULL) { | 
| transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED); | 
| transport_controller_->SignalConnectionState.connect( | 
| @@ -835,6 +835,10 @@ bool WebRtcSession::SetLocalDescription(SessionDescriptionInterface* desc, | 
| UseCandidatesInSessionDescription(remote_desc_.get()); | 
| } | 
|  | 
| +  audio_ice_restart_latch_->Reset(); | 
| +  video_ice_restart_latch_->Reset(); | 
| +  data_ice_restart_latch_->Reset(); | 
| + | 
| if (error() != ERROR_NONE) { | 
| return BadLocalSdp(desc->type(), GetSessionErrorMsg(), err_desc); | 
| } | 
| @@ -878,20 +882,34 @@ bool WebRtcSession::SetRemoteDescription(SessionDescriptionInterface* desc, | 
| return BadRemoteSdp(desc->type(), kInvalidCandidates, err_desc); | 
| } | 
|  | 
| +  audio_ice_restart_latch_->Reset(); | 
| +  video_ice_restart_latch_->Reset(); | 
| +  data_ice_restart_latch_->Reset(); | 
| + | 
| // Check if this new SessionDescription contains new ice ufrag and password | 
| // that indicates the remote peer requests ice restart. | 
| -  bool ice_restart = | 
| -      ice_restart_latch_->CheckForRemoteIceRestart(old_remote_desc.get(), desc); | 
| -  // We retain all received candidates only if ICE is not restarted. | 
| -  // When ICE is restarted, all previous candidates belong to an old generation | 
| -  // and should not be kept. | 
| -  // TODO(deadbeef): This goes against the W3C spec which says the remote | 
| -  // description should only contain candidates from the last set remote | 
| -  // description plus any candidates added since then. We should remove this | 
| -  // once we're sure it won't break anything. | 
| -  if (!ice_restart) { | 
| +  if (!audio_ice_restart_latch_->CheckForRemoteIceRestart(old_remote_desc.get(), | 
| +                                                          desc)) { | 
| +    // We retain all received candidates only if ICE is not restarted. | 
| +    // When ICE is restarted, all previous candidates belong to an old | 
| +    // generation | 
| +    // and should not be kept. | 
| +    // TODO(deadbeef): This goes against the W3C spec which says the remote | 
| +    // description should only contain candidates from the last set remote | 
| +    // description plus any candidates added since then. We should remove this | 
| +    // once we're sure it won't break anything. | 
| +    WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( | 
| +        old_remote_desc.get(), cricket::MEDIA_TYPE_AUDIO, desc); | 
| +  } | 
| +  if (!video_ice_restart_latch_->CheckForRemoteIceRestart(old_remote_desc.get(), | 
| +                                                          desc)) { | 
| +    WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( | 
| +        old_remote_desc.get(), cricket::MEDIA_TYPE_VIDEO, desc); | 
| +  } | 
| +  if (!data_ice_restart_latch_->CheckForRemoteIceRestart(old_remote_desc.get(), | 
| +                                                         desc)) { | 
| WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( | 
| -        old_remote_desc.get(), desc); | 
| +        old_remote_desc.get(), cricket::MEDIA_TYPE_DATA, desc); | 
| } | 
|  | 
| if (error() != ERROR_NONE) { | 
| @@ -1475,12 +1493,16 @@ cricket::DataChannelType WebRtcSession::data_channel_type() const { | 
| return data_channel_type_; | 
| } | 
|  | 
| -bool WebRtcSession::IceRestartPending() const { | 
| -  return ice_restart_latch_->Get(); | 
| +bool WebRtcSession::AudioIceRestartPending() const { | 
| +  return audio_ice_restart_latch_->Get(); | 
| +} | 
| + | 
| +bool WebRtcSession::VideoIceRestartPending() const { | 
| +  return video_ice_restart_latch_->Get(); | 
| } | 
|  | 
| -void WebRtcSession::ResetIceRestartLatch() { | 
| -  ice_restart_latch_->Reset(); | 
| +bool WebRtcSession::DataIceRestartPending() const { | 
| +  return data_ice_restart_latch_->Get(); | 
| } | 
|  | 
| void WebRtcSession::OnCertificateReady( | 
|  |