 Chromium Code Reviews
 Chromium Code Reviews Issue 1246913005:
  TransportController refactoring  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master
    
  
    Issue 1246913005:
  TransportController refactoring  (Closed) 
  Base URL: https://chromium.googlesource.com/external/webrtc.git@master| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/p2p/base/transportcontroller.h" | |
| 12 | |
| 13 #include "webrtc/base/bind.h" | |
| 14 #include "webrtc/base/thread.h" | |
| 15 #include "webrtc/p2p/base/dtlstransport.h" | |
| 16 #include "webrtc/p2p/base/p2ptransport.h" | |
| 17 | |
| 18 namespace cricket { | |
| 19 | |
| 20 enum { | |
| 21 MSG_ICECONNECTIONSTATE, | |
| 22 MSG_RECEIVING, | |
| 23 MSG_ICEGATHERINGSTATE, | |
| 24 MSG_CANDIDATESGATHERED, | |
| 25 }; | |
| 26 | |
| 27 struct CandidatesData : public rtc::MessageData { | |
| 28 CandidatesData(const std::string& transport_name, | |
| 29 const Candidates& candidates) | |
| 30 : transport_name(transport_name), candidates(candidates) {} | |
| 31 | |
| 32 std::string transport_name; | |
| 33 Candidates candidates; | |
| 34 }; | |
| 35 | |
| 36 TransportController::TransportController(rtc::Thread* signaling_thread, | |
| 37 rtc::Thread* worker_thread, | |
| 38 PortAllocator* port_allocator) | |
| 39 : signaling_thread_(signaling_thread), | |
| 40 worker_thread_(worker_thread), | |
| 41 port_allocator_(port_allocator) { | |
| 42 } | |
| 43 | |
| 44 TransportController::~TransportController() { | |
| 45 worker_thread_->Invoke<void>( | |
| 46 rtc::Bind(&TransportController::DestroyAllTransports_w, this)); | |
| 47 signaling_thread_->Clear(this); | |
| 48 } | |
| 49 | |
| 50 bool TransportController::SetSslMaxProtocolVersion( | |
| 51 rtc::SSLProtocolVersion version) { | |
| 52 return worker_thread_->Invoke<bool>(rtc::Bind( | |
| 53 &TransportController::SetSslMaxProtocolVersion_w, this, version)); | |
| 54 } | |
| 55 | |
| 56 void TransportController::SetIceConnectionReceivingTimeout(int timeout_ms) { | |
| 57 worker_thread_->Invoke<void>( | |
| 58 rtc::Bind(&TransportController::SetIceConnectionReceivingTimeout_w, this, | |
| 59 timeout_ms)); | |
| 60 } | |
| 61 | |
| 62 void TransportController::SetIceRole(IceRole ice_role) { | |
| 63 worker_thread_->Invoke<void>( | |
| 64 rtc::Bind(&TransportController::SetIceRole_w, this, ice_role)); | |
| 65 } | |
| 66 | |
| 67 bool TransportController::GetSslRole(rtc::SSLRole* role) { | |
| 68 return worker_thread_->Invoke<bool>( | |
| 69 rtc::Bind(&TransportController::GetSslRole_w, this, role)); | |
| 70 } | |
| 71 | |
| 72 bool TransportController::SetIdentity(rtc::SSLIdentity* identity) { | |
| 73 return worker_thread_->Invoke<bool>( | |
| 74 rtc::Bind(&TransportController::SetIdentity_w, this, identity)); | |
| 75 } | |
| 76 | |
| 77 bool TransportController::GetIdentity(const std::string& transport_name, | |
| 78 rtc::SSLIdentity** identity) { | |
| 79 return worker_thread_->Invoke<bool>(rtc::Bind( | |
| 80 &TransportController::GetIdentity_w, this, transport_name, identity)); | |
| 81 } | |
| 82 | |
| 83 bool TransportController::GetRemoteCertificate( | |
| 84 const std::string& transport_name, | |
| 85 rtc::SSLCertificate** cert) { | |
| 86 return worker_thread_->Invoke<bool>( | |
| 87 rtc::Bind(&TransportController::GetRemoteCertificate_w, this, | |
| 88 transport_name, cert)); | |
| 89 } | |
| 90 | |
| 91 bool TransportController::SetLocalTransportDescription( | |
| 92 const std::string& transport_name, | |
| 93 const TransportDescription& tdesc, | |
| 94 ContentAction action, | |
| 95 std::string* err) { | |
| 96 return worker_thread_->Invoke<bool>( | |
| 97 rtc::Bind(&TransportController::SetLocalTransportDescription_w, this, | |
| 98 transport_name, tdesc, action, err)); | |
| 99 } | |
| 100 | |
| 101 bool TransportController::SetRemoteTransportDescription( | |
| 102 const std::string& transport_name, | |
| 103 const TransportDescription& tdesc, | |
| 104 ContentAction action, | |
| 105 std::string* err) { | |
| 106 return worker_thread_->Invoke<bool>( | |
| 107 rtc::Bind(&TransportController::SetRemoteTransportDescription_w, this, | |
| 108 transport_name, tdesc, action, err)); | |
| 109 } | |
| 110 | |
| 111 bool TransportController::AddRemoteCandidates(const std::string& transport_name, | |
| 112 const Candidates& candidates, | |
| 113 std::string* err) { | |
| 114 return worker_thread_->Invoke<bool>( | |
| 115 rtc::Bind(&TransportController::AddRemoteCandidates_w, this, | |
| 116 transport_name, candidates, err)); | |
| 117 } | |
| 118 | |
| 119 bool TransportController::ReadyForRemoteCandidates( | |
| 120 const std::string& transport_name) { | |
| 121 return worker_thread_->Invoke<bool>(rtc::Bind( | |
| 122 &TransportController::ReadyForRemoteCandidates_w, this, transport_name)); | |
| 123 } | |
| 124 | |
| 125 bool TransportController::GetStats(const std::string& transport_name, | |
| 126 TransportStats* stats) { | |
| 127 return worker_thread_->Invoke<bool>( | |
| 128 rtc::Bind(&TransportController::GetStats_w, this, transport_name, stats)); | |
| 129 } | |
| 130 | |
| 131 TransportChannel* TransportController::CreateTransportChannel_w( | |
| 132 const std::string& transport_name, | |
| 133 int component) { | |
| 134 ASSERT(worker_thread_->IsCurrent()); | |
| 135 | |
| 136 Transport* transport = GetOrCreateTransport_w(transport_name); | |
| 137 return transport->CreateChannel(component); | |
| 138 } | |
| 139 | |
| 140 void TransportController::DestroyTransportChannel_w( | |
| 141 const std::string& transport_name, | |
| 142 int component) { | |
| 143 ASSERT(worker_thread_->IsCurrent()); | |
| 144 | |
| 145 Transport* transport = GetTransport_w(transport_name); | |
| 146 if (!transport) { | |
| 147 ASSERT(false); | |
| 148 return; | |
| 149 } | |
| 150 transport->DestroyChannel(component); | |
| 151 | |
| 152 // Just as we create a Transport when its first channel is created, | |
| 153 // we delete it when its last channel is deleted. | |
| 154 if (!transport->HasChannels()) { | |
| 155 DestroyTransport_w(transport_name); | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 void TransportController::OnMessage(rtc::Message* pmsg) { | |
| 160 ASSERT(signaling_thread_->IsCurrent()); | |
| 161 | |
| 162 switch (pmsg->message_id) { | |
| 163 case MSG_ICECONNECTIONSTATE: { | |
| 164 rtc::TypedMessageData<IceConnectionState>* data = | |
| 165 static_cast<rtc::TypedMessageData<IceConnectionState>*>(pmsg->pdata); | |
| 166 SignalConnectionState(data->data()); | |
| 167 delete data; | |
| 168 break; | |
| 169 } | |
| 170 case MSG_RECEIVING: { | |
| 171 rtc::TypedMessageData<bool>* data = | |
| 172 static_cast<rtc::TypedMessageData<bool>*>(pmsg->pdata); | |
| 173 SignalReceiving(data->data()); | |
| 174 delete data; | |
| 175 break; | |
| 176 } | |
| 177 case MSG_ICEGATHERINGSTATE: { | |
| 178 rtc::TypedMessageData<IceGatheringState>* data = | |
| 179 static_cast<rtc::TypedMessageData<IceGatheringState>*>(pmsg->pdata); | |
| 180 SignalGatheringState(data->data()); | |
| 181 delete data; | |
| 182 break; | |
| 183 } | |
| 184 case MSG_CANDIDATESGATHERED: { | |
| 185 CandidatesData* data = static_cast<CandidatesData*>(pmsg->pdata); | |
| 186 SignalCandidatesGathered(data->transport_name, data->candidates); | |
| 187 delete data; | |
| 188 break; | |
| 189 } | |
| 190 default: | |
| 191 ASSERT(false); | |
| 192 } | |
| 193 } | |
| 194 | |
| 195 Transport* TransportController::CreateTransport_w( | |
| 196 const std::string& transport_name) { | |
| 197 ASSERT(worker_thread_->IsCurrent()); | |
| 198 | |
| 199 Transport* transport = new DtlsTransport<P2PTransport>( | |
| 200 transport_name, port_allocator(), identity_.get()); | |
| 201 return transport; | |
| 202 } | |
| 203 | |
| 204 Transport* TransportController::GetOrCreateTransport_w( | |
| 205 const std::string& transport_name) { | |
| 206 ASSERT(worker_thread_->IsCurrent()); | |
| 207 | |
| 208 Transport* transport = GetTransport_w(transport_name); | |
| 209 if (transport) { | |
| 210 return transport; | |
| 211 } | |
| 212 | |
| 213 transport = CreateTransport_w(transport_name); | |
| 214 // The stuff below happens outside of CreateTransport_w so that unit tests | |
| 215 // can override CreateTransport_w to return a different type of transport. | |
| 216 transport->SetSslMaxProtocolVersion(ssl_max_version_); | |
| 217 transport->SetChannelReceivingTimeout(ice_receiving_timeout_ms_); | |
| 218 transport->SetIceRole(ice_role_); | |
| 219 transport->SetIceTiebreaker(ice_tiebreaker_); | |
| 220 if (identity_) { | |
| 221 transport->SetIdentity(identity_.get()); | |
| 222 } | |
| 223 transport->SignalConnecting.connect( | |
| 224 this, &TransportController::OnTransportConnecting_w); | |
| 225 transport->SignalWritableState.connect( | |
| 226 this, &TransportController::OnTransportWritableState_w); | |
| 227 transport->SignalReceivingState.connect( | |
| 228 this, &TransportController::OnTransportReceivingState_w); | |
| 229 transport->SignalCompleted.connect( | |
| 230 this, &TransportController::OnTransportCompleted_w); | |
| 231 transport->SignalFailed.connect(this, | |
| 232 &TransportController::OnTransportFailed_w); | |
| 233 transport->SignalGatheringState.connect( | |
| 234 this, &TransportController::OnTransportGatheringState_w); | |
| 235 transport->SignalCandidatesGathered.connect( | |
| 236 this, &TransportController::OnTransportCandidatesGathered_w); | |
| 237 transport->SignalRoleConflict.connect( | |
| 238 this, &TransportController::OnTransportRoleConflict_w); | |
| 239 transports_[transport_name] = transport; | |
| 240 | |
| 241 return transport; | |
| 242 } | |
| 243 | |
| 244 Transport* TransportController::GetTransport_w( | |
| 245 const std::string& transport_name) { | |
| 246 ASSERT(worker_thread_->IsCurrent()); | |
| 247 | |
| 248 auto iter = transports_.find(transport_name); | |
| 249 return (iter != transports_.end()) ? iter->second : nullptr; | |
| 250 } | |
| 251 | |
| 252 void TransportController::DestroyTransport_w( | |
| 253 const std::string& transport_name) { | |
| 254 ASSERT(worker_thread_->IsCurrent()); | |
| 255 | |
| 256 auto iter = transports_.find(transport_name); | |
| 257 if (iter != transports_.end()) { | |
| 258 delete iter->second; | |
| 259 transports_.erase(transport_name); | |
| 260 } | |
| 261 // Destroying a transport may cause aggregate state to change | |
| 262 UpdateAggregateStates_w(); | |
| 263 } | |
| 264 | |
| 265 void TransportController::DestroyAllTransports_w() { | |
| 266 ASSERT(worker_thread_->IsCurrent()); | |
| 267 | |
| 268 for (const auto& kv : transports_) { | |
| 269 delete kv.second; | |
| 270 } | |
| 271 transports_.clear(); | |
| 272 } | |
| 273 | |
| 274 bool TransportController::SetSslMaxProtocolVersion_w( | |
| 275 rtc::SSLProtocolVersion version) { | |
| 276 ASSERT(worker_thread_->IsCurrent()); | |
| 277 | |
| 278 // Max SSL version can only be set before transports are created | |
| 279 if (!transports_.empty()) { | |
| 280 return false; | |
| 281 } | |
| 282 | |
| 283 ssl_max_version_ = version; | |
| 284 return true; | |
| 285 } | |
| 286 | |
| 287 void TransportController::SetIceConnectionReceivingTimeout_w(int timeout_ms) { | |
| 288 ASSERT(worker_thread_->IsCurrent()); | |
| 289 ice_receiving_timeout_ms_ = timeout_ms; | |
| 290 for (const auto& kv : transports_) { | |
| 291 kv.second->SetChannelReceivingTimeout(timeout_ms); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 void TransportController::SetIceRole_w(IceRole ice_role) { | |
| 296 ASSERT(worker_thread_->IsCurrent()); | |
| 297 ice_role_ = ice_role; | |
| 298 for (const auto& kv : transports_) { | |
| 299 kv.second->SetIceRole(ice_role_); | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 bool TransportController::GetSslRole_w(rtc::SSLRole* role) { | |
| 304 ASSERT(worker_thread()->IsCurrent()); | |
| 305 | |
| 306 // TODO(mallinath) - Return role of each transport, as role may differ from | |
| 307 // one another. | |
| 308 // In current implementaion we just return the role of first transport in the | |
| 309 // transport map. | |
| 310 for (const auto& kv : transports_) { | |
| 311 return kv.second->GetSslRole(role); | |
| 312 } | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 bool TransportController::SetIdentity_w(rtc::SSLIdentity* identity) { | |
| 317 ASSERT(worker_thread_->IsCurrent()); | |
| 318 | |
| 319 if (identity_) { | |
| 320 return false; | |
| 321 } | |
| 322 identity_.reset(identity); | |
| 323 | |
| 324 for (const auto& kv : transports_) { | |
| 325 kv.second->SetIdentity(identity_.get()); | |
| 326 } | |
| 327 return true; | |
| 328 } | |
| 329 | |
| 330 bool TransportController::GetIdentity_w(const std::string& transport_name, | |
| 331 rtc::SSLIdentity** identity) { | |
| 332 ASSERT(worker_thread_->IsCurrent()); | |
| 333 | |
| 334 Transport* t = GetTransport_w(transport_name); | |
| 335 if (!t) { | |
| 336 return false; | |
| 337 } | |
| 338 | |
| 339 return t->GetIdentity(identity); | |
| 340 } | |
| 341 | |
| 342 bool TransportController::GetRemoteCertificate_w( | |
| 343 const std::string& transport_name, | |
| 344 rtc::SSLCertificate** cert) { | |
| 345 ASSERT(worker_thread_->IsCurrent()); | |
| 346 | |
| 347 Transport* t = GetTransport_w(transport_name); | |
| 348 if (!t) { | |
| 349 return false; | |
| 350 } | |
| 351 | |
| 352 return t->GetRemoteCertificate(cert); | |
| 353 } | |
| 354 | |
| 355 bool TransportController::SetLocalTransportDescription_w( | |
| 356 const std::string& transport_name, | |
| 357 const TransportDescription& tdesc, | |
| 358 ContentAction action, | |
| 359 std::string* err) { | |
| 360 ASSERT(worker_thread()->IsCurrent()); | |
| 361 | |
| 362 Transport* transport = GetTransport_w(transport_name); | |
| 363 if (!transport) { | |
| 364 // If we didn't find a transport, that's not an error; | |
| 365 // it could have been deleted as a result of bundling. | |
| 366 // TODO(deadbeef): Make callers smarter so they won't attempt to set a | |
| 367 // description on a deleted transport. | |
| 368 return true; | |
| 369 } | |
| 370 | |
| 371 return transport->SetLocalTransportDescription(tdesc, action, err); | |
| 372 } | |
| 373 | |
| 374 bool TransportController::SetRemoteTransportDescription_w( | |
| 375 const std::string& transport_name, | |
| 376 const TransportDescription& tdesc, | |
| 377 ContentAction action, | |
| 378 std::string* err) { | |
| 379 ASSERT(worker_thread()->IsCurrent()); | |
| 380 | |
| 381 Transport* transport = GetTransport_w(transport_name); | |
| 382 if (!transport) { | |
| 383 // If we didn't find a transport, that's not an error; | |
| 384 // it could have been deleted as a result of bundling. | |
| 385 // TODO(deadbeef): Make callers smarter so they won't attempt to set a | |
| 386 // description on a deleted transport. | |
| 387 return true; | |
| 388 } | |
| 389 | |
| 390 return transport->SetRemoteTransportDescription(tdesc, action, err); | |
| 391 } | |
| 392 | |
| 393 bool TransportController::AddRemoteCandidates_w( | |
| 394 const std::string& transport_name, | |
| 395 const Candidates& candidates, | |
| 396 std::string* err) { | |
| 397 ASSERT(worker_thread()->IsCurrent()); | |
| 398 | |
| 399 Transport* transport = GetTransport_w(transport_name); | |
| 400 if (!transport) { | |
| 401 // If we didn't find a transport, that's not an error; | |
| 402 // it could have been deleted as a result of bundling. | |
| 403 return true; | |
| 404 } | |
| 405 | |
| 406 return transport->AddRemoteCandidates(candidates, err); | |
| 407 } | |
| 408 | |
| 409 bool TransportController::ReadyForRemoteCandidates_w( | |
| 410 const std::string& transport_name) { | |
| 411 ASSERT(worker_thread()->IsCurrent()); | |
| 412 | |
| 413 Transport* transport = GetTransport_w(transport_name); | |
| 414 if (!transport) { | |
| 415 return false; | |
| 416 } | |
| 417 return transport->ready_for_remote_candidates(); | |
| 418 } | |
| 419 | |
| 420 bool TransportController::GetStats_w(const std::string& transport_name, | |
| 421 TransportStats* stats) { | |
| 422 ASSERT(worker_thread()->IsCurrent()); | |
| 423 | |
| 424 Transport* transport = GetTransport_w(transport_name); | |
| 425 if (!transport) { | |
| 426 return false; | |
| 427 } | |
| 428 return transport->GetStats(stats); | |
| 429 } | |
| 430 | |
| 431 void TransportController::OnTransportConnecting_w(Transport* transport) { | |
| 432 ASSERT(worker_thread_->IsCurrent()); | |
| 433 UpdateAggregateStates_w(); | |
| 434 } | |
| 435 | |
| 436 void TransportController::OnTransportWritableState_w(Transport* transport) { | |
| 437 ASSERT(worker_thread_->IsCurrent()); | |
| 438 UpdateAggregateStates_w(); | |
| 439 } | |
| 440 | |
| 441 void TransportController::OnTransportReceivingState_w(Transport* transport) { | |
| 442 ASSERT(worker_thread_->IsCurrent()); | |
| 443 UpdateAggregateStates_w(); | |
| 444 } | |
| 445 | |
| 446 void TransportController::OnTransportCompleted_w(Transport* transport) { | |
| 447 ASSERT(worker_thread_->IsCurrent()); | |
| 448 UpdateAggregateStates_w(); | |
| 449 } | |
| 450 | |
| 451 void TransportController::OnTransportFailed_w(Transport* transport) { | |
| 452 ASSERT(worker_thread_->IsCurrent()); | |
| 453 UpdateAggregateStates_w(); | |
| 454 } | |
| 455 | |
| 456 void TransportController::OnTransportGatheringState_w(Transport* transport) { | |
| 457 ASSERT(worker_thread_->IsCurrent()); | |
| 458 UpdateAggregateStates_w(); | |
| 459 } | |
| 460 | |
| 461 void TransportController::OnTransportCandidatesGathered_w( | |
| 462 Transport* transport, | |
| 463 const std::vector<Candidate>& candidates) { | |
| 464 ASSERT(worker_thread_->IsCurrent()); | |
| 465 CandidatesData* data = | |
| 466 new CandidatesData(transport->content_name(), candidates); | |
| 467 signaling_thread_->Post(this, MSG_CANDIDATESGATHERED, data); | |
| 468 } | |
| 469 | |
| 470 void TransportController::OnTransportRoleConflict_w() { | |
| 471 ASSERT(worker_thread_->IsCurrent()); | |
| 472 | |
| 473 if (ice_role_switch_) { | |
| 474 LOG(LS_WARNING) << "Repeat of role conflict signal from Transport."; | |
| 475 return; | |
| 476 } | |
| 477 | |
| 478 ice_role_switch_ = true; | |
| 479 IceRole reversed_role = (ice_role_ == ICEROLE_CONTROLLING) | |
| 480 ? ICEROLE_CONTROLLED | |
| 481 : ICEROLE_CONTROLLING; | |
| 482 for (const auto& kv : transports_) { | |
| 483 kv.second->SetIceRole(reversed_role); | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 void TransportController::UpdateAggregateStates_w() { | |
| 488 ASSERT(worker_thread_->IsCurrent()); | |
| 489 | |
| 490 IceConnectionState new_connection_state = kIceConnectionConnecting; | |
| 491 IceGatheringState new_gathering_state = kIceGatheringNew; | |
| 492 bool any_receiving = false; | |
| 493 bool any_failed = false; | |
| 494 bool all_connected = !transports_.empty(); | |
| 495 bool all_completed = !transports_.empty(); | |
| 496 bool any_gathering = false; | |
| 497 bool all_done_gathering = !transports_.empty(); | |
| 498 for (const auto& kv : transports_) { | |
| 499 any_receiving = any_receiving || kv.second->any_channel_receiving(); | |
| 500 any_failed = any_failed || kv.second->AnyChannelFailed(); | |
| 501 all_connected = all_connected && kv.second->all_channels_writable(); | |
| 502 all_completed = all_completed && kv.second->AllChannelsCompleted(); | |
| 503 any_gathering = | |
| 504 any_gathering || kv.second->gathering_state() != kIceGatheringNew; | |
| 505 all_done_gathering = all_done_gathering && | |
| 506 kv.second->gathering_state() == kIceGatheringComplete; | |
| 507 } | |
| 508 | |
| 509 if (any_failed) { | |
| 510 new_connection_state = kIceConnectionFailed; | |
| 511 } else if (all_completed) { | |
| 512 new_connection_state = kIceConnectionCompleted; | |
| 513 } else if (all_connected) { | |
| 514 new_connection_state = kIceConnectionConnected; | |
| 515 } | |
| 
pthatcher1
2015/08/25 18:40:39
A good way to write that comment I was talking abo
 
Taylor Brandstetter
2015/08/25 20:39:55
Acknowledged.
 | |
| 516 if (connection_state_ != new_connection_state) { | |
| 517 connection_state_ = new_connection_state; | |
| 518 signaling_thread_->Post( | |
| 519 this, MSG_ICECONNECTIONSTATE, | |
| 520 new rtc::TypedMessageData<IceConnectionState>(new_connection_state)); | |
| 521 } | |
| 522 | |
| 523 if (receiving_ != any_receiving) { | |
| 524 receiving_ = any_receiving; | |
| 525 signaling_thread_->Post(this, MSG_RECEIVING, | |
| 526 new rtc::TypedMessageData<bool>(any_receiving)); | |
| 527 } | |
| 528 | |
| 529 if (all_done_gathering) { | |
| 530 new_gathering_state = kIceGatheringComplete; | |
| 531 } else if (any_gathering) { | |
| 532 new_gathering_state = kIceGatheringGathering; | |
| 533 } | |
| 534 if (gathering_state_ != new_gathering_state) { | |
| 535 gathering_state_ = new_gathering_state; | |
| 536 signaling_thread_->Post( | |
| 537 this, MSG_ICEGATHERINGSTATE, | |
| 538 new rtc::TypedMessageData<IceGatheringState>(new_gathering_state)); | |
| 539 } | |
| 540 } | |
| 541 | |
| 542 } // namespace cricket | |
| OLD | NEW |