OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/cast_extension_session.h" | 5 #include "remoting/host/cast_extension_session.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 // results of creating descriptions for this end of the PeerConnection. | 89 // results of creating descriptions for this end of the PeerConnection. |
90 class CastCreateSessionDescriptionObserver | 90 class CastCreateSessionDescriptionObserver |
91 : public webrtc::CreateSessionDescriptionObserver { | 91 : public webrtc::CreateSessionDescriptionObserver { |
92 public: | 92 public: |
93 static CastCreateSessionDescriptionObserver* Create( | 93 static CastCreateSessionDescriptionObserver* Create( |
94 CastExtensionSession* session) { | 94 CastExtensionSession* session) { |
95 return new rtc::RefCountedObject<CastCreateSessionDescriptionObserver>( | 95 return new rtc::RefCountedObject<CastCreateSessionDescriptionObserver>( |
96 session); | 96 session); |
97 } | 97 } |
98 void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { | 98 void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { |
99 if (cast_extension_session_ == NULL) { | 99 if (cast_extension_session_ == nullptr) { |
100 LOG(ERROR) | 100 LOG(ERROR) |
101 << "No CastExtensionSession. Creating session description succeeded."; | 101 << "No CastExtensionSession. Creating session description succeeded."; |
102 return; | 102 return; |
103 } | 103 } |
104 cast_extension_session_->OnCreateSessionDescription(desc); | 104 cast_extension_session_->OnCreateSessionDescription(desc); |
105 } | 105 } |
106 void OnFailure(const std::string& error) override { | 106 void OnFailure(const std::string& error) override { |
107 if (cast_extension_session_ == NULL) { | 107 if (cast_extension_session_ == nullptr) { |
108 LOG(ERROR) | 108 LOG(ERROR) |
109 << "No CastExtensionSession. Creating session description failed."; | 109 << "No CastExtensionSession. Creating session description failed."; |
110 return; | 110 return; |
111 } | 111 } |
112 cast_extension_session_->OnCreateSessionDescriptionFailure(error); | 112 cast_extension_session_->OnCreateSessionDescriptionFailure(error); |
113 } | 113 } |
114 void SetCastExtensionSession(CastExtensionSession* cast_extension_session) { | 114 void SetCastExtensionSession(CastExtensionSession* cast_extension_session) { |
115 cast_extension_session_ = cast_extension_session; | 115 cast_extension_session_ = cast_extension_session; |
116 } | 116 } |
117 | 117 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 | 155 |
156 // TODO(aiguha): Fix PeerConnnection-related tear down crash caused by premature | 156 // TODO(aiguha): Fix PeerConnnection-related tear down crash caused by premature |
157 // destruction of cricket::CaptureManager (which occurs on releasing | 157 // destruction of cricket::CaptureManager (which occurs on releasing |
158 // |peer_conn_factory_|). See crbug.com/403840. | 158 // |peer_conn_factory_|). See crbug.com/403840. |
159 CastExtensionSession::~CastExtensionSession() { | 159 CastExtensionSession::~CastExtensionSession() { |
160 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 160 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
161 | 161 |
162 // Explicitly clear |create_session_desc_observer_|'s pointer to |this|, | 162 // Explicitly clear |create_session_desc_observer_|'s pointer to |this|, |
163 // since the CastExtensionSession is destructing. Otherwise, | 163 // since the CastExtensionSession is destructing. Otherwise, |
164 // |create_session_desc_observer_| would be left with a dangling pointer. | 164 // |create_session_desc_observer_| would be left with a dangling pointer. |
165 create_session_desc_observer_->SetCastExtensionSession(NULL); | 165 create_session_desc_observer_->SetCastExtensionSession(nullptr); |
166 | 166 |
167 CleanupPeerConnection(); | 167 CleanupPeerConnection(); |
168 } | 168 } |
169 | 169 |
170 // static | 170 // static |
171 scoped_ptr<CastExtensionSession> CastExtensionSession::Create( | 171 scoped_ptr<CastExtensionSession> CastExtensionSession::Create( |
172 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, | 172 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner, |
173 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, | 173 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, |
174 const protocol::NetworkSettings& network_settings, | 174 const protocol::NetworkSettings& network_settings, |
175 ClientSessionControl* client_session_control, | 175 ClientSessionControl* client_session_control, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
232 if (has_grabbed_capturer_) { | 232 if (has_grabbed_capturer_) { |
233 LOG(ERROR) << "The video pipeline was reset unexpectedly."; | 233 LOG(ERROR) << "The video pipeline was reset unexpectedly."; |
234 has_grabbed_capturer_ = false; | 234 has_grabbed_capturer_ = false; |
235 peer_connection_->RemoveStream(stream_.release()); | 235 peer_connection_->RemoveStream(stream_.release()); |
236 return; | 236 return; |
237 } | 237 } |
238 | 238 |
239 if (received_offer_) { | 239 if (received_offer_) { |
240 has_grabbed_capturer_ = true; | 240 has_grabbed_capturer_ = true; |
241 if (SetupVideoStream(capturer->Pass())) { | 241 if (SetupVideoStream(capturer->Pass())) { |
242 peer_connection_->CreateAnswer(create_session_desc_observer_, NULL); | 242 peer_connection_->CreateAnswer(create_session_desc_observer_, nullptr); |
243 } else { | 243 } else { |
244 has_grabbed_capturer_ = false; | 244 has_grabbed_capturer_ = false; |
245 // Ignore the received offer, since we failed to setup a video stream. | 245 // Ignore the received offer, since we failed to setup a video stream. |
246 received_offer_ = false; | 246 received_offer_ = false; |
247 } | 247 } |
248 return; | 248 return; |
249 } | 249 } |
250 } | 250 } |
251 | 251 |
252 bool CastExtensionSession::ModifiesVideoPipeline() const { | 252 bool CastExtensionSession::ModifiesVideoPipeline() const { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 ClientSessionControl* client_session_control, | 306 ClientSessionControl* client_session_control, |
307 protocol::ClientStub* client_stub) | 307 protocol::ClientStub* client_stub) |
308 : caller_task_runner_(caller_task_runner), | 308 : caller_task_runner_(caller_task_runner), |
309 url_request_context_getter_(url_request_context_getter), | 309 url_request_context_getter_(url_request_context_getter), |
310 network_settings_(network_settings), | 310 network_settings_(network_settings), |
311 client_session_control_(client_session_control), | 311 client_session_control_(client_session_control), |
312 client_stub_(client_stub), | 312 client_stub_(client_stub), |
313 stats_observer_(CastStatsObserver::Create()), | 313 stats_observer_(CastStatsObserver::Create()), |
314 received_offer_(false), | 314 received_offer_(false), |
315 has_grabbed_capturer_(false), | 315 has_grabbed_capturer_(false), |
316 signaling_thread_wrapper_(NULL), | 316 signaling_thread_wrapper_(nullptr), |
317 worker_thread_wrapper_(NULL), | 317 worker_thread_wrapper_(nullptr), |
318 worker_thread_(kWorkerThreadName) { | 318 worker_thread_(kWorkerThreadName) { |
319 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 319 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
320 DCHECK(url_request_context_getter_.get()); | 320 DCHECK(url_request_context_getter_.get()); |
321 DCHECK(client_session_control_); | 321 DCHECK(client_session_control_); |
322 DCHECK(client_stub_); | 322 DCHECK(client_stub_); |
323 | 323 |
324 // The worker thread is created with base::MessageLoop::TYPE_IO because | 324 // The worker thread is created with base::MessageLoop::TYPE_IO because |
325 // the PeerConnection performs some port allocation operations on this thread | 325 // the PeerConnection performs some port allocation operations on this thread |
326 // that require it. See crbug.com/404013. | 326 // that require it. See crbug.com/404013. |
327 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); | 327 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); |
328 worker_thread_.StartWithOptions(options); | 328 worker_thread_.StartWithOptions(options); |
329 worker_task_runner_ = worker_thread_.task_runner(); | 329 worker_task_runner_ = worker_thread_.task_runner(); |
330 } | 330 } |
331 | 331 |
332 bool CastExtensionSession::ParseAndSetRemoteDescription( | 332 bool CastExtensionSession::ParseAndSetRemoteDescription( |
333 base::DictionaryValue* message) { | 333 base::DictionaryValue* message) { |
334 DCHECK(peer_connection_.get() != NULL); | 334 DCHECK(peer_connection_.get() != nullptr); |
335 | 335 |
336 base::DictionaryValue* message_data; | 336 base::DictionaryValue* message_data; |
337 if (!message->GetDictionary(kTopLevelData, &message_data)) { | 337 if (!message->GetDictionary(kTopLevelData, &message_data)) { |
338 LOG(ERROR) << "Invalid Cast Extension Message (missing data)."; | 338 LOG(ERROR) << "Invalid Cast Extension Message (missing data)."; |
339 return false; | 339 return false; |
340 } | 340 } |
341 | 341 |
342 std::string webrtc_type; | 342 std::string webrtc_type; |
343 if (!message_data->GetString(kWebRtcSessionDescType, &webrtc_type)) { | 343 if (!message_data->GetString(kWebRtcSessionDescType, &webrtc_type)) { |
344 LOG(ERROR) | 344 LOG(ERROR) |
(...skipping 17 matching lines...) Expand all Loading... |
362 return false; | 362 return false; |
363 } | 363 } |
364 | 364 |
365 peer_connection_->SetRemoteDescription( | 365 peer_connection_->SetRemoteDescription( |
366 CastSetSessionDescriptionObserver::Create(), session_description); | 366 CastSetSessionDescriptionObserver::Create(), session_description); |
367 return true; | 367 return true; |
368 } | 368 } |
369 | 369 |
370 bool CastExtensionSession::ParseAndAddICECandidate( | 370 bool CastExtensionSession::ParseAndAddICECandidate( |
371 base::DictionaryValue* message) { | 371 base::DictionaryValue* message) { |
372 DCHECK(peer_connection_.get() != NULL); | 372 DCHECK(peer_connection_.get() != nullptr); |
373 | 373 |
374 base::DictionaryValue* message_data; | 374 base::DictionaryValue* message_data; |
375 if (!message->GetDictionary(kTopLevelData, &message_data)) { | 375 if (!message->GetDictionary(kTopLevelData, &message_data)) { |
376 LOG(ERROR) << "Invalid Cast Extension Message (missing data)."; | 376 LOG(ERROR) << "Invalid Cast Extension Message (missing data)."; |
377 return false; | 377 return false; |
378 } | 378 } |
379 | 379 |
380 std::string candidate_str; | 380 std::string candidate_str; |
381 std::string sdp_mid; | 381 std::string sdp_mid; |
382 int sdp_mlineindex = 0; | 382 int sdp_mlineindex = 0; |
(...skipping 19 matching lines...) Expand all Loading... |
402 | 402 |
403 VLOG(1) << "Received and Added ICE Candidate: " << candidate_str; | 403 VLOG(1) << "Received and Added ICE Candidate: " << candidate_str; |
404 | 404 |
405 return true; | 405 return true; |
406 } | 406 } |
407 | 407 |
408 bool CastExtensionSession::SendMessageToClient(const std::string& subject, | 408 bool CastExtensionSession::SendMessageToClient(const std::string& subject, |
409 const std::string& data) { | 409 const std::string& data) { |
410 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 410 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
411 | 411 |
412 if (client_stub_ == NULL) { | 412 if (client_stub_ == nullptr) { |
413 LOG(ERROR) << "No Client Stub. Cannot send message to client."; | 413 LOG(ERROR) << "No Client Stub. Cannot send message to client."; |
414 return false; | 414 return false; |
415 } | 415 } |
416 | 416 |
417 base::DictionaryValue message_dict; | 417 base::DictionaryValue message_dict; |
418 message_dict.SetString(kTopLevelSubject, subject); | 418 message_dict.SetString(kTopLevelSubject, subject); |
419 message_dict.SetString(kTopLevelData, data); | 419 message_dict.SetString(kTopLevelData, data); |
420 std::string message_json; | 420 std::string message_json; |
421 | 421 |
422 if (!base::JSONWriter::Write(&message_dict, &message_json)) { | 422 if (!base::JSONWriter::Write(&message_dict, &message_json)) { |
423 LOG(ERROR) << "Failed to serialize JSON message."; | 423 LOG(ERROR) << "Failed to serialize JSON message."; |
424 return false; | 424 return false; |
425 } | 425 } |
426 | 426 |
427 protocol::ExtensionMessage message; | 427 protocol::ExtensionMessage message; |
428 message.set_type(kExtensionMessageType); | 428 message.set_type(kExtensionMessageType); |
429 message.set_data(message_json); | 429 message.set_data(message_json); |
430 client_stub_->DeliverHostMessage(message); | 430 client_stub_->DeliverHostMessage(message); |
431 return true; | 431 return true; |
432 } | 432 } |
433 | 433 |
434 void CastExtensionSession::EnsureTaskAndSetSend(rtc::Thread** ptr, | 434 void CastExtensionSession::EnsureTaskAndSetSend(rtc::Thread** ptr, |
435 base::WaitableEvent* event) { | 435 base::WaitableEvent* event) { |
436 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | 436 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); |
437 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); | 437 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); |
438 *ptr = jingle_glue::JingleThreadWrapper::current(); | 438 *ptr = jingle_glue::JingleThreadWrapper::current(); |
439 | 439 |
440 if (event != NULL) { | 440 if (event != nullptr) { |
441 event->Signal(); | 441 event->Signal(); |
442 } | 442 } |
443 } | 443 } |
444 | 444 |
445 bool CastExtensionSession::WrapTasksAndSave() { | 445 bool CastExtensionSession::WrapTasksAndSave() { |
446 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 446 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
447 | 447 |
448 EnsureTaskAndSetSend(&signaling_thread_wrapper_); | 448 EnsureTaskAndSetSend(&signaling_thread_wrapper_); |
449 if (signaling_thread_wrapper_ == NULL) | 449 if (signaling_thread_wrapper_ == nullptr) |
450 return false; | 450 return false; |
451 | 451 |
452 base::WaitableEvent wrap_worker_thread_event(true, false); | 452 base::WaitableEvent wrap_worker_thread_event(true, false); |
453 worker_task_runner_->PostTask( | 453 worker_task_runner_->PostTask( |
454 FROM_HERE, | 454 FROM_HERE, |
455 base::Bind(&CastExtensionSession::EnsureTaskAndSetSend, | 455 base::Bind(&CastExtensionSession::EnsureTaskAndSetSend, |
456 base::Unretained(this), | 456 base::Unretained(this), |
457 &worker_thread_wrapper_, | 457 &worker_thread_wrapper_, |
458 &wrap_worker_thread_event)); | 458 &wrap_worker_thread_event)); |
459 wrap_worker_thread_event.Wait(); | 459 wrap_worker_thread_event.Wait(); |
460 | 460 |
461 return (worker_thread_wrapper_ != NULL); | 461 return (worker_thread_wrapper_ != nullptr); |
462 } | 462 } |
463 | 463 |
464 bool CastExtensionSession::InitializePeerConnection() { | 464 bool CastExtensionSession::InitializePeerConnection() { |
465 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 465 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
466 DCHECK(!peer_conn_factory_); | 466 DCHECK(!peer_conn_factory_); |
467 DCHECK(!peer_connection_); | 467 DCHECK(!peer_connection_); |
468 DCHECK(worker_thread_wrapper_ != NULL); | 468 DCHECK(worker_thread_wrapper_ != nullptr); |
469 DCHECK(signaling_thread_wrapper_ != NULL); | 469 DCHECK(signaling_thread_wrapper_ != nullptr); |
470 | 470 |
471 peer_conn_factory_ = webrtc::CreatePeerConnectionFactory( | 471 peer_conn_factory_ = webrtc::CreatePeerConnectionFactory( |
472 worker_thread_wrapper_, signaling_thread_wrapper_, NULL, NULL, NULL); | 472 worker_thread_wrapper_, signaling_thread_wrapper_, nullptr, nullptr, |
| 473 nullptr); |
473 | 474 |
474 if (!peer_conn_factory_.get()) { | 475 if (!peer_conn_factory_.get()) { |
475 CleanupPeerConnection(); | 476 CleanupPeerConnection(); |
476 return false; | 477 return false; |
477 } | 478 } |
478 | 479 |
479 VLOG(1) << "Created PeerConnectionFactory successfully."; | 480 VLOG(1) << "Created PeerConnectionFactory successfully."; |
480 | 481 |
481 webrtc::PeerConnectionInterface::IceServers servers; | 482 webrtc::PeerConnectionInterface::IceServers servers; |
482 webrtc::PeerConnectionInterface::IceServer server; | 483 webrtc::PeerConnectionInterface::IceServer server; |
483 server.uri = kDefaultStunURI; | 484 server.uri = kDefaultStunURI; |
484 servers.push_back(server); | 485 servers.push_back(server); |
485 webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; | 486 webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; |
486 rtc_config.servers = servers; | 487 rtc_config.servers = servers; |
487 | 488 |
488 // DTLS-SRTP is the preferred encryption method. If set to kValueFalse, the | 489 // DTLS-SRTP is the preferred encryption method. If set to kValueFalse, the |
489 // peer connection uses SDES. Disabling SDES as well will cause the peer | 490 // peer connection uses SDES. Disabling SDES as well will cause the peer |
490 // connection to fail to connect. | 491 // connection to fail to connect. |
491 // Note: For protection and unprotection of SRTP packets, the libjingle | 492 // Note: For protection and unprotection of SRTP packets, the libjingle |
492 // ENABLE_EXTERNAL_AUTH flag must not be set. | 493 // ENABLE_EXTERNAL_AUTH flag must not be set. |
493 webrtc::FakeConstraints constraints; | 494 webrtc::FakeConstraints constraints; |
494 constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, | 495 constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, |
495 webrtc::MediaConstraintsInterface::kValueTrue); | 496 webrtc::MediaConstraintsInterface::kValueTrue); |
496 | 497 |
497 rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface> | 498 rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface> |
498 port_allocator_factory = ChromiumPortAllocatorFactory::Create( | 499 port_allocator_factory = ChromiumPortAllocatorFactory::Create( |
499 network_settings_, url_request_context_getter_); | 500 network_settings_, url_request_context_getter_); |
500 | 501 |
501 peer_connection_ = peer_conn_factory_->CreatePeerConnection( | 502 peer_connection_ = peer_conn_factory_->CreatePeerConnection( |
502 rtc_config, &constraints, port_allocator_factory, NULL, this); | 503 rtc_config, &constraints, port_allocator_factory, nullptr, this); |
503 | 504 |
504 if (!peer_connection_.get()) { | 505 if (!peer_connection_.get()) { |
505 CleanupPeerConnection(); | 506 CleanupPeerConnection(); |
506 return false; | 507 return false; |
507 } | 508 } |
508 | 509 |
509 VLOG(1) << "Created PeerConnection successfully."; | 510 VLOG(1) << "Created PeerConnection successfully."; |
510 | 511 |
511 create_session_desc_observer_ = | 512 create_session_desc_observer_ = |
512 CastCreateSessionDescriptionObserver::Create(this); | 513 CastCreateSessionDescriptionObserver::Create(this); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> video_track = | 566 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> video_track = |
566 stream_->FindVideoTrack(kVideoLabel); | 567 stream_->FindVideoTrack(kVideoLabel); |
567 peer_connection_->GetStats( | 568 peer_connection_->GetStats( |
568 stats_observer_, | 569 stats_observer_, |
569 video_track.release(), | 570 video_track.release(), |
570 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); | 571 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); |
571 } | 572 } |
572 | 573 |
573 void CastExtensionSession::CleanupPeerConnection() { | 574 void CastExtensionSession::CleanupPeerConnection() { |
574 peer_connection_->Close(); | 575 peer_connection_->Close(); |
575 peer_connection_ = NULL; | 576 peer_connection_ = nullptr; |
576 stream_ = NULL; | 577 stream_ = nullptr; |
577 peer_conn_factory_ = NULL; | 578 peer_conn_factory_ = nullptr; |
578 worker_thread_.Stop(); | 579 worker_thread_.Stop(); |
579 } | 580 } |
580 | 581 |
581 bool CastExtensionSession::connection_active() const { | 582 bool CastExtensionSession::connection_active() const { |
582 return peer_connection_.get() != NULL; | 583 return peer_connection_.get() != nullptr; |
583 } | 584 } |
584 | 585 |
585 // webrtc::PeerConnectionObserver implementation ------------------------------- | 586 // webrtc::PeerConnectionObserver implementation ------------------------------- |
586 void CastExtensionSession::OnSignalingChange( | 587 void CastExtensionSession::OnSignalingChange( |
587 webrtc::PeerConnectionInterface::SignalingState new_state) { | 588 webrtc::PeerConnectionInterface::SignalingState new_state) { |
588 VLOG(1) << "PeerConnectionObserver: SignalingState changed to:" << new_state; | 589 VLOG(1) << "PeerConnectionObserver: SignalingState changed to:" << new_state; |
589 } | 590 } |
590 | 591 |
591 void CastExtensionSession::OnStateChange( | 592 void CastExtensionSession::OnStateChange( |
592 webrtc::PeerConnectionObserver::StateType state_changed) { | 593 webrtc::PeerConnectionObserver::StateType state_changed) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 json->SetString(kWebRtcCandidate, candidate_str); | 652 json->SetString(kWebRtcCandidate, candidate_str); |
652 std::string json_str; | 653 std::string json_str; |
653 if (!base::JSONWriter::Write(json.get(), &json_str)) { | 654 if (!base::JSONWriter::Write(json.get(), &json_str)) { |
654 LOG(ERROR) << "Failed to serialize candidate message."; | 655 LOG(ERROR) << "Failed to serialize candidate message."; |
655 return; | 656 return; |
656 } | 657 } |
657 SendMessageToClient(kSubjectNewCandidate, json_str); | 658 SendMessageToClient(kSubjectNewCandidate, json_str); |
658 } | 659 } |
659 | 660 |
660 } // namespace remoting | 661 } // namespace remoting |
OLD | NEW |