Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "remoting/host/cast_extension_session.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/callback.h" | |
| 9 #include "base/json/json_reader.h" | |
| 10 #include "base/json/json_writer.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/synchronization/waitable_event.h" | |
| 14 #include "net/url_request/url_request_context_getter.h" | |
| 15 #include "remoting/host/chromium_port_allocator_factory.h" | |
| 16 // #include "remoting/host/cast_video_capturer.h" | |
| 17 #include "remoting/host/client_session.h" | |
| 18 #include "remoting/proto/control.pb.h" | |
| 19 #include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h " | |
| 20 #include "third_party/libjingle/source/talk/app/webrtc/test/fakeconstraints.h" | |
| 21 #include "third_party/libjingle/source/talk/app/webrtc/videosourceinterface.h" | |
| 22 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_shape.h" | |
| 23 | |
| 24 namespace remoting { | |
| 25 | |
| 26 // Constant keys used in JSON messages to the host. | |
| 27 // Must keep synced with webapp. | |
| 28 const char kMessageData[] = "data"; // Use chromoting_data for CC v2. | |
| 29 const char kMessageSubject[] = "subject"; | |
| 30 const char kMessageType[] = "cast_message"; | |
| 31 | |
| 32 const char kSubjectNewCandidate[] = "webrtc_candidate"; | |
| 33 const char kSubjectReady[] = "ready"; | |
| 34 const char kSubjectSDP[] = "webrtc_sdp"; | |
| 35 const char kSubjectTest[] = "test"; | |
| 36 | |
| 37 const char kWebRtcPrefix[] = "webrtc_"; | |
| 38 | |
| 39 // WebRTC Headers inside cast extension messages. | |
| 40 const char kWebRtcCandidate[] = "candidate"; | |
| 41 const char kWebRtcSessionDescType[] = "type"; | |
| 42 const char kWebRtcSessionDescSDP[] = "sdp"; | |
| 43 const char kWebRtcSDPMid[] = "sdpMid"; | |
| 44 const char kWebRtcSDPMLineIndex[] = "sdpMLineIndex"; | |
| 45 | |
| 46 // Constants used by PeerConnection. | |
| 47 const char kVideoLabel[] = "cast_video_label"; | |
| 48 const char kStreamLabel[] = "stream_label"; | |
| 49 const char kDefaultStunURI[] = "stun:stun.l.google.com:19302"; | |
| 50 | |
| 51 //------------------------------------------------------------------------------ | |
| 52 | |
| 53 // webrtc::SetSessionDescriptionObserver implementation. | |
| 54 class CastSetSessionDescriptionObserver | |
| 55 : public webrtc::SetSessionDescriptionObserver { | |
| 56 public: | |
| 57 static CastSetSessionDescriptionObserver* Create() { | |
| 58 return new talk_base::RefCountedObject<CastSetSessionDescriptionObserver>(); | |
| 59 } | |
| 60 virtual void OnSuccess() OVERRIDE { | |
| 61 VLOG(1) << "SetSessionDescriptionObserver success."; | |
| 62 } | |
| 63 virtual void OnFailure(const std::string& error) OVERRIDE { | |
| 64 LOG(ERROR) << "CastSetSessionDescriptionObserver" << __FUNCTION__ << " " | |
| 65 << error; | |
| 66 } | |
| 67 | |
| 68 protected: | |
| 69 CastSetSessionDescriptionObserver() {} | |
| 70 virtual ~CastSetSessionDescriptionObserver() {} | |
| 71 }; | |
| 72 | |
| 73 // webrtc::CreateSessionDescriptionObserver implementation. | |
| 74 class CastCreateSessionDescriptionObserver | |
| 75 : public webrtc::CreateSessionDescriptionObserver { | |
| 76 public: | |
| 77 static CastCreateSessionDescriptionObserver* Create( | |
| 78 CastExtensionSession* session) { | |
| 79 return new talk_base::RefCountedObject< | |
| 80 CastCreateSessionDescriptionObserver>(session); | |
| 81 } | |
| 82 virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE { | |
| 83 if (session_ == NULL) { | |
| 84 LOG(ERROR) << "No Session, cannot create session description."; | |
| 85 return; | |
| 86 } | |
| 87 session_->OnSuccess(desc); | |
| 88 } | |
| 89 virtual void OnFailure(const std::string& error) OVERRIDE { | |
| 90 if (session_ == NULL) { | |
| 91 LOG(ERROR) << "No Session, cannot create session description."; | |
| 92 return; | |
| 93 } | |
| 94 session_->OnFailure(error); | |
| 95 } | |
| 96 | |
| 97 protected: | |
| 98 explicit CastCreateSessionDescriptionObserver(CastExtensionSession* session) | |
| 99 : session_(session) {} | |
| 100 virtual ~CastCreateSessionDescriptionObserver() {} | |
| 101 | |
| 102 private: | |
| 103 CastExtensionSession* session_; | |
| 104 }; | |
| 105 | |
| 106 // webrtc::StatsObserver implementation. | |
| 107 class CastStatsObserver : public webrtc::StatsObserver { | |
| 108 public: | |
| 109 static CastStatsObserver* Create() { | |
| 110 return new talk_base::RefCountedObject<CastStatsObserver>(); | |
| 111 } | |
| 112 | |
| 113 virtual void OnComplete( | |
| 114 const std::vector<webrtc::StatsReport>& reports) OVERRIDE { | |
| 115 if (reports.empty()) { | |
| 116 VLOG(1) << "Received 0 StatsReports."; | |
| 117 } | |
| 118 VLOG(1) << "Received " << reports.size() << " new StatsReports."; | |
| 119 std::vector<webrtc::StatsReport>::const_iterator it; | |
| 120 for (it = reports.begin(); it != reports.end(); ++it) { | |
| 121 LogStatsReport(*it); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 protected: | |
| 126 CastStatsObserver() {} | |
| 127 virtual ~CastStatsObserver() {} | |
| 128 | |
| 129 void LogStatsReport(const webrtc::StatsReport& report) { | |
| 130 typedef webrtc::StatsReport StatsReport; | |
| 131 typedef webrtc::StatsReport::Values::iterator ValuesIterator; | |
| 132 webrtc::StatsReport::Values v = report.values; | |
| 133 for (ValuesIterator it = v.begin(); it != v.end(); ++it) { | |
| 134 VLOG(1) << "Param: " << it->name << "; Value: " << it->value << "."; | |
| 135 } | |
| 136 } | |
| 137 }; | |
| 138 | |
| 139 //------------------------------------------------------------------------------ | |
| 140 | |
| 141 // static | |
| 142 CastExtensionSession* CastExtensionSession::Create( | |
| 143 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | |
| 144 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, | |
| 145 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, | |
| 146 const protocol::NetworkSettings& network_settings, | |
| 147 ClientSession* client_session) { | |
| 148 scoped_ptr<CastExtensionSession> cast_extension_session( | |
| 149 new CastExtensionSession(network_task_runner, | |
| 150 video_capture_task_runner, | |
| 151 url_request_context_getter, | |
| 152 network_settings, | |
| 153 client_session)); | |
| 154 bool success = cast_extension_session->WrapTasksAndSave(); | |
| 155 success = cast_extension_session->InitializePeerConnection(); | |
| 156 return (success ? cast_extension_session.release() : NULL); | |
| 157 } | |
| 158 | |
| 159 CastExtensionSession::CastExtensionSession( | |
| 160 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner, | |
| 161 scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner, | |
| 162 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter, | |
| 163 const protocol::NetworkSettings& network_settings, | |
| 164 ClientSession* client_session) | |
| 165 : network_task_runner_(network_task_runner), | |
| 166 capture_task_runner_(video_capture_task_runner), | |
| 167 network_thread_wrapper_(NULL), | |
| 168 capture_thread_wrapper_(NULL), | |
| 169 url_request_context_getter_(url_request_context_getter), | |
| 170 network_settings_(network_settings), | |
| 171 client_session_(client_session), | |
| 172 stats_observer_(CastStatsObserver::Create()) { | |
| 173 DCHECK(network_task_runner_.get() != NULL); | |
| 174 DCHECK(capture_task_runner_.get() != NULL); | |
| 175 DCHECK(url_request_context_getter_.get() != NULL); | |
| 176 DCHECK(client_session_); | |
| 177 } | |
| 178 | |
| 179 CastExtensionSession::~CastExtensionSession() { | |
| 180 DeletePeerConnection(); | |
| 181 } | |
| 182 | |
| 183 std::string append_path(const char* first, const char* second) { | |
| 184 std::string path(first); | |
| 185 path.append("."); | |
| 186 path.append(second); | |
| 187 return path; | |
| 188 } | |
| 189 | |
| 190 // Returns true if the ExtensionMessage was of type |kMessageType|, even if | |
| 191 // it was badly formed or a resulting action failed. This is done so that | |
| 192 // the host does not continue to attempt to pass |message| to other | |
| 193 // HostExtensionSessions. | |
| 194 bool CastExtensionSession::OnExtensionMessage( | |
| 195 ClientSession* client_session, | |
| 196 const protocol::ExtensionMessage& message) { | |
| 197 if (!message.has_type() || message.type().compare(kMessageType) != 0) { | |
| 198 return false; | |
| 199 } | |
| 200 | |
| 201 scoped_ptr<base::Value> value(base::JSONReader::Read(message.data())); | |
| 202 base::DictionaryValue* client_message; | |
| 203 | |
| 204 if (!(value && value->GetAsDictionary(&client_message))) { | |
| 205 LOG(ERROR) << "Could not read cast extension message."; | |
| 206 return true; | |
| 207 } | |
| 208 | |
| 209 std::string subject; | |
| 210 if (!client_message->GetString(kMessageSubject, &subject)) { | |
| 211 LOG(ERROR) << "Invalid Cast Extension Message (missing subject header)."; | |
| 212 return true; | |
| 213 } | |
| 214 | |
| 215 if (subject == kSubjectSDP) { | |
| 216 std::string webrtc_type; | |
| 217 std::string sdp; | |
| 218 if (!client_message->GetString( | |
| 219 append_path(kMessageData, kWebRtcSessionDescType), &webrtc_type)) { | |
| 220 LOG(ERROR) | |
| 221 << "Invalid Cast Extension Message (missing webrtc type header)."; | |
| 222 return true; | |
| 223 } | |
| 224 if (!client_message->GetString( | |
| 225 append_path(kMessageData, kWebRtcSessionDescSDP), &sdp)) { | |
| 226 LOG(ERROR) | |
| 227 << "Invalid Cast Extension Message (missing webrtc sdp header)."; | |
| 228 return true; | |
| 229 } | |
| 230 webrtc::SdpParseError error; | |
| 231 webrtc::SessionDescriptionInterface* session_description( | |
| 232 webrtc::CreateSessionDescription(webrtc_type, sdp, &error)); | |
| 233 | |
| 234 if (!session_description) { | |
| 235 LOG(ERROR) << "Invalid Cast Extension Message (could not parse sdp)."; | |
| 236 VLOG(1) << "SdpParseError was: " << error.line << "; " | |
| 237 << error.description + ". (Ignore if empty)."; | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 // Save the type because session_description is going to be given off to | |
| 242 // PeerConnection. | |
| 243 std::string sdp_type = session_description->type(); | |
| 244 VLOG(1) << "Setting Remote Description."; | |
| 245 peer_connection_->SetRemoteDescription( | |
| 246 CastSetSessionDescriptionObserver::Create(), session_description); | |
| 247 if (sdp_type == webrtc::SessionDescriptionInterface::kOffer) { | |
| 248 // Setup MediaStream in PeerConnection because client has made an offer. | |
| 249 // TODO(aiguha): Notify client of failure. | |
| 250 if (!InitializeAndAddMediaStream()) { | |
| 251 LOG(ERROR) << "InitializeAndAddMediaStream failed."; | |
| 252 return true; | |
| 253 } | |
| 254 | |
| 255 VLOG(1) << "Received Offer. Creating Answer."; | |
| 256 peer_connection_->CreateAnswer( | |
| 257 CastCreateSessionDescriptionObserver::Create(this), NULL); | |
| 258 } | |
| 259 return true; | |
| 260 } else if (subject == kSubjectNewCandidate) { | |
| 261 std::string candidate_str; | |
| 262 std::string sdp_mid; | |
| 263 int sdp_mlineindex = 0; | |
| 264 if (!client_message->GetString(append_path(kMessageData, kWebRtcSDPMid), | |
| 265 &sdp_mid) || | |
| 266 !client_message->GetInteger( | |
| 267 append_path(kMessageData, kWebRtcSDPMLineIndex), &sdp_mlineindex) || | |
| 268 !client_message->GetString(append_path(kMessageData, kWebRtcCandidate), | |
| 269 &candidate_str)) { | |
| 270 LOG(ERROR) << "Invalid Cast Extension Message (could not parse)."; | |
| 271 return true; | |
| 272 } | |
| 273 talk_base::scoped_ptr<webrtc::IceCandidateInterface> candidate( | |
| 274 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate_str)); | |
| 275 if (!candidate.get()) { | |
| 276 LOG(ERROR) | |
| 277 << "Invalid Cast Extension Message (could not create candidate)."; | |
| 278 return true; | |
| 279 } | |
| 280 if (!peer_connection_->AddIceCandidate(candidate.get())) { | |
| 281 LOG(ERROR) << "Failed to apply received ICE Candidate to PeerConnection."; | |
| 282 return true; | |
| 283 } | |
| 284 VLOG(1) << "Received ICE Candidate: " << candidate_str; | |
| 285 } else { | |
| 286 VLOG(1) << "Unexpected CastExtension Message: " << message.data(); | |
| 287 } | |
| 288 return true; | |
| 289 } | |
| 290 | |
| 291 // Private Methods ------------------------------------------------------------- | |
| 292 | |
| 293 bool CastExtensionSession::SendMessageToClient(const char* subject, | |
| 294 const std::string& data) { | |
| 295 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
| 296 if (client_session_ == NULL) { | |
| 297 LOG(ERROR) << "No Client Session. Cannot send message to client."; | |
| 298 return false; | |
| 299 } | |
| 300 | |
| 301 base::DictionaryValue message_dict; | |
| 302 message_dict.SetString(kMessageSubject, subject); | |
| 303 message_dict.SetString(kMessageData, data); | |
| 304 std::string message_json; | |
| 305 | |
| 306 if (!base::JSONWriter::Write(&message_dict, &message_json)) { | |
| 307 LOG(ERROR) << "Failed to create message json."; | |
| 308 return false; | |
| 309 } | |
| 310 | |
| 311 protocol::ExtensionMessage message; | |
| 312 message.set_type(kMessageType); | |
| 313 message.set_data(message_json); | |
| 314 client_session_->connection()->client_stub()->DeliverHostMessage(message); | |
| 315 return true; | |
| 316 } | |
| 317 | |
| 318 void CastExtensionSession::SendCursorShape( | |
| 319 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) { | |
| 320 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
| 321 if (client_session_ == NULL) | |
| 322 return; | |
| 323 | |
| 324 protocol::ClientStub* client_stub = | |
| 325 client_session_->connection()->client_stub(); | |
| 326 | |
| 327 if (client_stub == NULL) | |
| 328 return; | |
| 329 | |
| 330 client_stub->SetCursorShape(*cursor_shape); | |
| 331 } | |
| 332 | |
| 333 void CastExtensionSession::EnsureTaskAndSetSend(talk_base::Thread** ptr, | |
| 334 base::WaitableEvent* event) { | |
| 335 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop(); | |
| 336 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true); | |
| 337 *ptr = jingle_glue::JingleThreadWrapper::current(); | |
| 338 | |
| 339 if (event != NULL) | |
| 340 event->Signal(); | |
| 341 } | |
| 342 | |
| 343 bool CastExtensionSession::WrapTasksAndSave() { | |
| 344 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
| 345 EnsureTaskAndSetSend(&network_thread_wrapper_); | |
| 346 | |
| 347 if (network_thread_wrapper_ == NULL) | |
| 348 return false; | |
| 349 | |
| 350 base::WaitableEvent wrap_capture_thread_event(true, false); | |
| 351 capture_task_runner_->PostTask( | |
| 352 FROM_HERE, | |
| 353 base::Bind(&CastExtensionSession::EnsureTaskAndSetSend, | |
| 354 base::Unretained(this), | |
| 355 &capture_thread_wrapper_, | |
| 356 &wrap_capture_thread_event)); | |
| 357 wrap_capture_thread_event.Wait(); | |
| 358 | |
| 359 return (capture_thread_wrapper_ != NULL); | |
| 360 } | |
| 361 | |
| 362 bool CastExtensionSession::InitializePeerConnection() { | |
| 363 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
| 364 DCHECK(peer_conn_factory_.get() == NULL); | |
| 365 DCHECK(peer_connection_.get() == NULL); | |
| 366 DCHECK(capture_thread_wrapper_ != NULL); | |
| 367 DCHECK(network_thread_wrapper_ != NULL); | |
| 368 | |
| 369 // TODO(aiguha): Confirm that worker and signalling threads are being | |
| 370 // assigned appropriately. For the below configuration to work, | |
| 371 // |capture_task_runner_| was changed to have a TYPE_IO MessageLoop. | |
| 372 peer_conn_factory_ = webrtc::CreatePeerConnectionFactory( | |
| 373 capture_thread_wrapper_, network_thread_wrapper_, NULL, NULL, NULL); | |
| 374 | |
| 375 if (!peer_conn_factory_.get()) { | |
| 376 LOG(ERROR) << "Failed to initialize PeerConnectionFactory"; | |
| 377 DeletePeerConnection(); | |
| 378 return false; | |
| 379 } | |
| 380 | |
| 381 VLOG(1) << "Created PeerConnectionFactory successfully."; | |
| 382 | |
| 383 webrtc::PeerConnectionInterface::IceServers servers; | |
| 384 webrtc::PeerConnectionInterface::IceServer server; | |
| 385 server.uri = kDefaultStunURI; | |
| 386 servers.push_back(server); | |
| 387 webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; | |
| 388 rtc_config.servers = servers; | |
| 389 webrtc::FakeConstraints constraints; | |
| 390 | |
| 391 // DTLS-SRTP is the preferred encryption method. If set to kValueFalse, the | |
| 392 // peer connection uses SDES. Disabling SDES as well will cause the peer | |
| 393 // connection to fail to connect. | |
| 394 // Note: For protection and unprotection of SRTP packets, the libjingle | |
| 395 // ENABLE_EXTERNAL_AUTH flag must not be set. | |
| 396 constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, | |
| 397 webrtc::MediaConstraintsInterface::kValueTrue); | |
| 398 | |
| 399 peer_connection_ = peer_conn_factory_->CreatePeerConnection( | |
| 400 rtc_config, | |
| 401 &constraints, | |
| 402 ChromiumPortAllocatorFactory::Create(network_settings_, | |
| 403 url_request_context_getter_), | |
| 404 NULL, | |
| 405 this); | |
| 406 | |
| 407 if (!peer_connection_.get()) { | |
| 408 LOG(ERROR) << "Failed to initialize PeerConnection."; | |
| 409 DeletePeerConnection(); | |
| 410 return false; | |
| 411 } | |
| 412 | |
| 413 VLOG(1) << "Created PeerConnection successfully."; | |
| 414 | |
| 415 if (!SendMessageToClient(kSubjectTest, "Hello, client.")) { | |
| 416 LOG(ERROR) << "Failed to send test message to client."; | |
| 417 return false; | |
| 418 } | |
| 419 // Sending this message triggers the client to start the peer connection | |
| 420 // offer/answer negotiation. | |
| 421 if (!SendMessageToClient(kSubjectReady, "Host ready to receive offers.")) { | |
| 422 LOG(ERROR) << "Failed to send ready message to client."; | |
| 423 return false; | |
| 424 } | |
| 425 | |
| 426 return true; | |
| 427 } | |
| 428 | |
| 429 bool CastExtensionSession::InitializeAndAddMediaStream() { | |
| 430 DCHECK(network_task_runner_->BelongsToCurrentThread()); | |
| 431 | |
| 432 if (stream_) { | |
| 433 VLOG(1) << "Already added MediaStream."; | |
| 434 return false; // Already added. | |
| 435 } | |
| 436 scoped_ptr<webrtc::ScreenCapturer> screen_capturer = | |
| 437 client_session_->RequestScreenCapturer(); | |
| 438 screen_capturer->SetMouseShapeObserver(this); | |
| 439 // scoped_ptr<CastVideoCapturer> cast_video_capturer( | |
| 440 // new CastVideoCapturer(capture_task_runner_, screen_capturer.Pass())); | |
|
aiguha
2014/07/29 04:23:45
This is the only bit of code that relies on the ot
| |
| 441 std::string minFrameRate = "3"; | |
| 442 webrtc::FakeConstraints video_constraints; | |
| 443 video_constraints.AddMandatory( | |
| 444 webrtc::MediaConstraintsInterface::kMinFrameRate, minFrameRate); | |
| 445 | |
| 446 talk_base::scoped_refptr<webrtc::VideoTrackInterface> video_track = | |
| 447 peer_conn_factory_->CreateVideoTrack( | |
| 448 kVideoLabel, | |
| 449 peer_conn_factory_->CreateVideoSource(NULL, | |
| 450 &video_constraints)); | |
| 451 | |
| 452 VLOG(1) << "Created VideoTrack successfully."; | |
| 453 stream_ = peer_conn_factory_->CreateLocalMediaStream(kStreamLabel); | |
| 454 | |
| 455 if (!stream_->AddTrack(video_track)) { | |
| 456 LOG(ERROR) << "Failed to add VideoTrack to MediaStream."; | |
| 457 return false; | |
| 458 } else { | |
| 459 VLOG(1) << "Added VideoTrack to MediaStream successfully."; | |
| 460 } | |
| 461 | |
| 462 if (!peer_connection_->AddStream(stream_, NULL)) { | |
| 463 VLOG(1) << "Failed to add MediaStream to PeerConnection."; | |
| 464 return false; | |
| 465 } else { | |
| 466 VLOG(1) << "Added Stream to PeerConnection successfully."; | |
| 467 } | |
| 468 return true; | |
| 469 } | |
| 470 | |
| 471 void CastExtensionSession::PollPeerConnectionStats() { | |
| 472 if (!connection_active()) { | |
| 473 VLOG(1) << "Cannot poll stats while PeerConnection is inactive."; | |
| 474 } | |
| 475 talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface> video_track = | |
| 476 stream_->FindVideoTrack(kVideoLabel); | |
| 477 peer_connection_->GetStats( | |
| 478 stats_observer_, | |
| 479 video_track.release(), | |
| 480 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); | |
| 481 } | |
| 482 | |
| 483 void CastExtensionSession::DeletePeerConnection() { | |
| 484 peer_connection_->Close(); | |
| 485 // peer_connection_ = NULL; | |
| 486 stream_ = NULL; | |
| 487 peer_conn_factory_ = NULL; | |
| 488 } | |
| 489 | |
| 490 bool CastExtensionSession::connection_active() const { | |
| 491 return peer_connection_.get() != NULL; | |
| 492 } | |
| 493 | |
| 494 // MouseShapeObserver implementation ------------------------------------------- | |
| 495 | |
| 496 // TODO(aiguha): To reduce duplication, it would perhaps be | |
| 497 // better to create a single MouseShapeObserver outside of VideoScheduler | |
| 498 // that can be attached to the ScreenCapturer on its creation, in | |
| 499 // ClientSession. | |
| 500 void CastExtensionSession::OnCursorShapeChanged( | |
| 501 webrtc::MouseCursorShape* cursor_shape) { | |
| 502 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 503 VLOG(1) << __FUNCTION__ << " called."; | |
| 504 scoped_ptr<webrtc::MouseCursorShape> owned_cursor(cursor_shape); | |
| 505 | |
| 506 scoped_ptr<protocol::CursorShapeInfo> cursor_proto( | |
| 507 new protocol::CursorShapeInfo()); | |
| 508 cursor_proto->set_width(cursor_shape->size.width()); | |
| 509 cursor_proto->set_height(cursor_shape->size.height()); | |
| 510 cursor_proto->set_hotspot_x(cursor_shape->hotspot.x()); | |
| 511 cursor_proto->set_hotspot_y(cursor_shape->hotspot.y()); | |
| 512 cursor_proto->set_data(cursor_shape->data); | |
| 513 | |
| 514 network_task_runner_->PostTask( | |
| 515 FROM_HERE, | |
| 516 base::Bind(&CastExtensionSession::SendCursorShape, | |
| 517 base::Unretained(this), | |
| 518 base::Passed(&cursor_proto))); | |
| 519 } | |
| 520 | |
| 521 // CreateSessionDescriptionObserver related methods ---------------------------- | |
| 522 | |
| 523 void CastExtensionSession::OnSuccess( | |
| 524 webrtc::SessionDescriptionInterface* desc) { | |
| 525 if (!network_task_runner_->BelongsToCurrentThread()) { | |
| 526 network_task_runner_->PostTask( | |
| 527 FROM_HERE, | |
| 528 base::Bind( | |
| 529 &CastExtensionSession::OnSuccess, base::Unretained(this), desc)); | |
| 530 return; | |
| 531 } | |
| 532 peer_connection_->SetLocalDescription( | |
| 533 CastSetSessionDescriptionObserver::Create(), desc); | |
| 534 scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue()); | |
| 535 json->SetString(kWebRtcSessionDescType, desc->type()); | |
| 536 std::string subject = kWebRtcPrefix + desc->type(); | |
| 537 std::string desc_str; | |
| 538 desc->ToString(&desc_str); | |
| 539 json->SetString(kWebRtcSessionDescSDP, desc_str); | |
| 540 std::string json_str; | |
| 541 base::JSONWriter::Write(json.get(), &json_str); | |
| 542 SendMessageToClient(subject.c_str(), json_str); | |
| 543 } | |
| 544 | |
| 545 void CastExtensionSession::OnFailure(const std::string& error) { | |
| 546 VLOG(1) << __FUNCTION__ << " called with: " << error; | |
| 547 } | |
| 548 | |
| 549 // PeerConnectionObserver implementation --------------------------------------- | |
| 550 | |
| 551 void CastExtensionSession::OnError() { | |
| 552 VLOG(1) << __FUNCTION__; | |
| 553 } | |
| 554 void CastExtensionSession::OnSignalingChange( | |
| 555 webrtc::PeerConnectionInterface::SignalingState new_state) { | |
| 556 VLOG(1) << "Function CastExtensionSession::OnSignalingChange called with " | |
| 557 << new_state; | |
| 558 } | |
| 559 void CastExtensionSession::OnStateChange( | |
| 560 webrtc::PeerConnectionObserver::StateType state_changed) { | |
| 561 VLOG(1) << __FUNCTION__ << " called with input " << state_changed; | |
| 562 } | |
| 563 void CastExtensionSession::OnAddStream(webrtc::MediaStreamInterface* stream) { | |
| 564 VLOG(1) << __FUNCTION__ << " " << stream->label(); | |
| 565 } | |
| 566 void CastExtensionSession::OnRemoveStream( | |
| 567 webrtc::MediaStreamInterface* stream) { | |
| 568 VLOG(1) << __FUNCTION__ << " " << stream->label(); | |
| 569 } | |
| 570 void CastExtensionSession::OnDataChannel( | |
| 571 webrtc::DataChannelInterface* data_channel) { | |
| 572 VLOG(1) << __FUNCTION__ << " called with " << data_channel->label(); | |
| 573 } | |
| 574 void CastExtensionSession::OnRenegotiationNeeded() { | |
| 575 VLOG(1) << __FUNCTION__ << " called."; | |
| 576 } | |
| 577 void CastExtensionSession::OnIceConnectionChange( | |
| 578 webrtc::PeerConnectionInterface::IceConnectionState new_state) { | |
| 579 VLOG(1) << __FUNCTION__ << " called with new IceConnectionState " | |
| 580 << new_state; | |
| 581 } | |
| 582 void CastExtensionSession::OnIceGatheringChange( | |
| 583 webrtc::PeerConnectionInterface::IceGatheringState new_state) { | |
| 584 VLOG(1) << __FUNCTION__ << " called with new IceGatheringState " << new_state; | |
| 585 } | |
| 586 | |
| 587 void CastExtensionSession::OnIceComplete() { | |
| 588 VLOG(1) << __FUNCTION__ << " called."; | |
| 589 // TODO(aiguha): Maybe start timer only if enabled by command-line flag or | |
| 590 // at a particular verbosity level. | |
| 591 stats_polling_timer_.Start(FROM_HERE, | |
| 592 base::TimeDelta::FromSeconds(10), | |
| 593 this, | |
| 594 &CastExtensionSession::PollPeerConnectionStats); | |
| 595 } | |
| 596 | |
| 597 void CastExtensionSession::OnIceCandidate( | |
| 598 const webrtc::IceCandidateInterface* candidate) { | |
| 599 std::string candidate_str; | |
| 600 if (!candidate->ToString(&candidate_str)) { | |
| 601 LOG(ERROR) << __FUNCTION__ << " called, but could not serialize candidate."; | |
| 602 return; | |
| 603 } | |
| 604 VLOG(1) << __FUNCTION__ << " called with " << candidate_str; | |
| 605 scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue()); | |
| 606 json->SetString(kWebRtcSDPMid, candidate->sdp_mid()); | |
| 607 json->SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index()); | |
| 608 json->SetString(kWebRtcCandidate, candidate_str); | |
| 609 std::string json_str; | |
| 610 base::JSONWriter::Write(json.get(), &json_str); | |
| 611 SendMessageToClient(kSubjectNewCandidate, json_str); | |
| 612 } | |
| 613 | |
| 614 } // namespace remoting | |
| 615 | |
| OLD | NEW |