Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(656)

Side by Side Diff: remoting/host/cast_extension_session.cc

Issue 399253002: CastExtension Impl for Chromoting Host (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Incorporated New HostExtension Flow Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/cast_video_capturer.h"
aiguha 2014/08/04 17:45:36 As mentioned earlier: The CastVideoCapturer CL sho
Wez 2014/08/07 01:25:32 when you have dependent CLs, just keep them in dep
aiguha 2014/08/12 01:42:36 Thanks for the advice. Done!
16 #include "remoting/host/chromium_port_allocator_factory.h"
17 #include "remoting/host/client_session.h"
18 #include "remoting/proto/control.pb.h"
19 #include "remoting/protocol/client_stub.h"
20 #include "third_party/libjingle/source/talk/app/webrtc/peerconnectioninterface.h "
21 #include "third_party/libjingle/source/talk/app/webrtc/test/fakeconstraints.h"
22 #include "third_party/libjingle/source/talk/app/webrtc/videosourceinterface.h"
23 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_shape.h"
24
25 namespace remoting {
26
27 // Constant keys used in JSON messages to the host.
28 // Must keep synced with webapp.
29 const char kMessageData[] = "data"; // Use chromoting_data for CCv2.
Wez 2014/08/07 01:25:33 What is CCv2?
aiguha 2014/08/12 01:42:37 This comment shouldn't have made it in, I'll remov
30 const char kMessageSubject[] = "subject";
31 const char kMessageType[] = "cast_message";
32
33 const char kSubjectNewCandidate[] = "webrtc_candidate";
34 const char kSubjectReady[] = "ready";
35 // const char kSubjectSDP[] = "webrtc_sdp";
Wez 2014/08/07 01:25:31 Why is this commented out?
aiguha 2014/08/12 01:42:37 Not used anymore, removed!
36 const char kSubjectTest[] = "test";
37 const char kSubjectOffer[] = "webrtc_offer";
38 const char kSubjectAnswer[] = "webrtc_answer";
39
40 const char kWebRtcPrefix[] = "webrtc_";
Wez 2014/08/07 01:25:31 What's this used for?
aiguha 2014/08/12 01:42:38 It was being used to construct the subject of a me
41
42 // WebRTC Headers inside cast extension messages.
Wez 2014/08/07 01:25:30 s/Headers/headers
aiguha 2014/08/12 01:42:36 Done.
43 const char kWebRtcCandidate[] = "candidate";
44 const char kWebRtcSessionDescType[] = "type";
45 const char kWebRtcSessionDescSDP[] = "sdp";
46 const char kWebRtcSDPMid[] = "sdpMid";
47 const char kWebRtcSDPMLineIndex[] = "sdpMLineIndex";
48
49 // Constants used by PeerConnection.
Wez 2014/08/07 01:25:33 You mean "over the PeerConnection"?
aiguha 2014/08/12 01:42:36 The constants are used by the related objects, but
Wez 2014/08/12 22:14:59 Well, it depends - are these things that get sent
aiguha 2014/08/13 18:33:27 The labels are used over the connection and the St
50 const char kVideoLabel[] = "cast_video_label";
51 const char kStreamLabel[] = "stream_label";
52 const char kDefaultStunURI[] = "stun:stun.l.google.com:19302";
Wez 2014/08/07 01:25:33 Where does this come from?
aiguha 2014/08/12 01:42:38 I believe this is Google's public STUN server. The
53
54 const char kWorkerThreadName[] = "CastExtensionSessionWorkerThread";
55
56 static const int kStatsLogIntervalSec = 10;
57
58 //------------------------------------------------------------------------------
Wez 2014/08/07 01:25:30 Suggest getting rid of this separator comment.
aiguha 2014/08/12 01:42:36 Done.
59
60 // webrtc::SetSessionDescriptionObserver implementation.
Wez 2014/08/07 01:25:30 Suggest replacing this with a short description of
aiguha 2014/08/12 01:42:39 Done.
61 class CastSetSessionDescriptionObserver
62 : public webrtc::SetSessionDescriptionObserver {
63 public:
64 static CastSetSessionDescriptionObserver* Create() {
65 return new talk_base::RefCountedObject<CastSetSessionDescriptionObserver>();
66 }
67 virtual void OnSuccess() OVERRIDE {
68 VLOG(1) << "SetSessionDescriptionObserver success.";
Wez 2014/08/07 01:25:32 Don't you mean "SetSessionDescription succeeded."?
aiguha 2014/08/12 01:42:38 Yes, changed!
69 }
70 virtual void OnFailure(const std::string& error) OVERRIDE {
71 LOG(ERROR) << "CastSetSessionDescriptionObserver" << __FUNCTION__ << " "
72 << error;
Wez 2014/08/07 01:25:33 And "SetSessionDescription failed: <error>"?
aiguha 2014/08/12 01:42:36 Done.
73 }
74
75 protected:
76 CastSetSessionDescriptionObserver() {}
77 virtual ~CastSetSessionDescriptionObserver() {}
78 };
Wez 2014/08/07 01:25:32 DISALLOW_COPY_AND_ASSIGN()
aiguha 2014/08/12 01:42:36 Done.
79
80 // webrtc::CreateSessionDescriptionObserver implementation.
81 class CastCreateSessionDescriptionObserver
82 : public webrtc::CreateSessionDescriptionObserver {
83 public:
84 static CastCreateSessionDescriptionObserver* Create(
85 CastExtensionSession* session) {
86 return new talk_base::RefCountedObject<
87 CastCreateSessionDescriptionObserver>(session);
88 }
89 virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE {
90 if (session_ == NULL) {
91 LOG(ERROR) << "No Session, cannot create session description.";
Wez 2014/08/07 01:25:33 How can session_ ever be NULL?
aiguha 2014/08/12 01:42:37 Since this is ref-counted and owned by PeerConnect
Wez 2014/08/12 22:14:59 Nothing ever sets it to NULL, though...? If |sess
aiguha 2014/08/13 18:33:27 Oops, I was mixing up dangling and null pointers,
92 return;
93 }
94 session_->OnSuccess(desc);
95 }
96 virtual void OnFailure(const std::string& error) OVERRIDE {
97 if (session_ == NULL) {
98 LOG(ERROR) << "No Session, cannot create session description.";
99 return;
100 }
101 session_->OnFailure(error);
102 }
103
104 protected:
105 CastCreateSessionDescriptionObserver(CastExtensionSession* session)
106 : session_(session) {}
107 virtual ~CastCreateSessionDescriptionObserver() {}
108
109 private:
110 CastExtensionSession* session_;
111 };
Wez 2014/08/07 01:25:32 DISALLOW_COPY_AND_ASSIGN()
aiguha 2014/08/12 01:42:37 Done.
112
113 // webrtc::StatsObserver implementation.
114 class CastStatsObserver : public webrtc::StatsObserver {
115 public:
116 static CastStatsObserver* Create() {
117 return new talk_base::RefCountedObject<CastStatsObserver>();
118 }
119
120 virtual void OnComplete(
121 const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
122 if (reports.empty()) {
Wez 2014/08/07 01:25:30 Remove this special-case.
aiguha 2014/08/12 01:42:38 Done.
123 VLOG(1) << "Received 0 StatsReports.";
124 }
125 VLOG(1) << "Received " << reports.size() << " new StatsReports.";
126 std::vector<webrtc::StatsReport>::const_iterator it;
127 for (it = reports.begin(); it != reports.end(); ++it) {
128 LogStatsReport(*it);
129 }
130 }
131
132 protected:
133 CastStatsObserver() {}
134 virtual ~CastStatsObserver() {}
135
136 void LogStatsReport(const webrtc::StatsReport& report) {
Wez 2014/08/07 01:25:30 This seems simple enough to leave in-line on OnCom
aiguha 2014/08/12 01:42:37 Done.
137 typedef webrtc::StatsReport StatsReport;
Wez 2014/08/07 01:25:32 You don't use this typedef?
aiguha 2014/08/12 01:42:37 Acknowledged.
138 typedef webrtc::StatsReport::Values::iterator ValuesIterator;
139 webrtc::StatsReport::Values v = report.values;
140 for (ValuesIterator it = v.begin(); it != v.end(); ++it) {
141 VLOG(1) << "Param: " << it->name << "; Value: " << it->value << ".";
142 }
143 }
144 };
Wez 2014/08/07 01:25:31 DISALLOW_COPY_AND_ASSIGN()
aiguha 2014/08/12 01:42:37 Done.
145
146 //------------------------------------------------------------------------------
Wez 2014/08/07 01:25:30 No need for this.
aiguha 2014/08/12 01:42:38 Acknowledged.
147
148 // static
149 CastExtensionSession* CastExtensionSession::Create(
Wez 2014/08/07 01:25:31 Generally speaking it's best if you can order the
aiguha 2014/08/12 01:42:36 Done. Only the PeerConnectionObserver impl is stil
150 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
151 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
152 const protocol::NetworkSettings& network_settings,
153 ClientSessionControl* client_session_control,
154 protocol::ClientStub* client_stub) {
155 scoped_ptr<CastExtensionSession> cast_extension_session(
156 new CastExtensionSession(network_task_runner,
157 url_request_context_getter,
158 network_settings,
159 client_session_control,
160 client_stub));
161 bool success = cast_extension_session->WrapTasksAndSave();
162 success = cast_extension_session->InitializePeerConnection();
Wez 2014/08/07 01:25:31 You're overwriting the result of WrapTasksAndSave(
aiguha 2014/08/12 01:42:37 Done.
163 return (success ? cast_extension_session.release() : NULL);
164 }
165
166 CastExtensionSession::CastExtensionSession(
167 scoped_refptr<base::SingleThreadTaskRunner> network_task_runner,
168 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
169 const protocol::NetworkSettings& network_settings,
170 ClientSessionControl* client_session_control,
171 protocol::ClientStub* client_stub)
172 : network_task_runner_(network_task_runner),
173 url_request_context_getter_(url_request_context_getter),
174 network_settings_(network_settings),
175 client_session_control_(client_session_control),
176 client_stub_(client_stub),
177 stats_observer_(CastStatsObserver::Create()),
178 received_offer_(false),
179 has_grabbed_capturer_(false),
180 network_thread_wrapper_(NULL),
181 worker_thread_wrapper_(NULL) {
182 DCHECK(network_task_runner_);
Wez 2014/08/07 01:25:31 nit: if you're going to -> this on the next line,
aiguha 2014/08/12 01:42:38 Done.
183 DCHECK(network_task_runner_->BelongsToCurrentThread());
184 DCHECK(url_request_context_getter_);
185 DCHECK(client_session_control_);
186 DCHECK(client_stub_);
187
188 // Launch the worker thread.
Wez 2014/08/07 01:25:33 nit: This comment adds nothing ;)
aiguha 2014/08/12 01:42:38 Acknowledged.
189 worker_thread_.reset(new AutoThread(kWorkerThreadName));
190 worker_task_runner_ =
191 worker_thread_->StartWithType(base::MessageLoop::TYPE_IO);
Wez 2014/08/07 01:25:32 AutoThread is really intended to be created with A
aiguha 2014/08/12 01:42:38 Done.
192
193 DCHECK(worker_task_runner_);
194 }
195
196 CastExtensionSession::~CastExtensionSession() {
197 DCHECK(network_task_runner_->BelongsToCurrentThread());
198 VLOG(1) << "CastExtensionSession::DTOR";
Wez 2014/08/07 01:25:32 nit: Clean up this logging.
aiguha 2014/08/12 01:42:37 Done.
199 DeletePeerConnection();
200 worker_task_runner_ = NULL;
201 }
202
203 std::string append_path(const char* first, const char* second) {
Wez 2014/08/07 01:25:30 AppendPath
aiguha 2014/08/12 01:42:38 Removed altogether.
204 std::string path(first);
205 path.append(".");
206 path.append(second);
207 return path;
208 }
209
210 bool CastExtensionSession::ParseAndSetRemoteDescription(
211 base::DictionaryValue* message) {
212 DCHECK(peer_connection_.get() != NULL);
213 std::string webrtc_type;
214 std::string sdp;
Wez 2014/08/07 01:25:32 Why not just pull out the kMessageData dictionary
aiguha 2014/08/12 01:42:38 Done.
215 if (!message->GetString(append_path(kMessageData, kWebRtcSessionDescType),
216 &webrtc_type)) {
217 LOG(ERROR)
218 << "Invalid Cast Extension Message (missing webrtc type header).";
219 return false;
220 }
221 if (!message->GetString(append_path(kMessageData, kWebRtcSessionDescSDP),
222 &sdp)) {
223 LOG(ERROR) << "Invalid Cast Extension Message (missing webrtc sdp header).";
224 return false;
225 }
226 webrtc::SdpParseError error;
227 webrtc::SessionDescriptionInterface* session_description(
228 webrtc::CreateSessionDescription(webrtc_type, sdp, &error));
229
230 if (!session_description) {
231 LOG(ERROR) << "Invalid Cast Extension Message (could not parse sdp).";
232 VLOG(1) << "SdpParseError was: " << error.description;
233 return false;
234 }
235
236 VLOG(1) << "Setting Remote Description.";
237 peer_connection_->SetRemoteDescription(
238 CastSetSessionDescriptionObserver::Create(), session_description);
239 return true;
240 }
241
242 bool CastExtensionSession::ParseAndAddICECandidate(
243 base::DictionaryValue* message) {
244 std::string candidate_str;
245 std::string sdp_mid;
246 int sdp_mlineindex = 0;
247 if (!message->GetString(append_path(kMessageData, kWebRtcSDPMid), &sdp_mid) ||
248 !message->GetInteger(append_path(kMessageData, kWebRtcSDPMLineIndex),
249 &sdp_mlineindex) ||
250 !message->GetString(append_path(kMessageData, kWebRtcCandidate),
251 &candidate_str)) {
252 LOG(ERROR) << "Invalid Cast Extension Message (could not parse).";
253 return false;
254 }
255 talk_base::scoped_ptr<webrtc::IceCandidateInterface> candidate(
256 webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, candidate_str));
257 if (!candidate.get()) {
258 LOG(ERROR)
259 << "Invalid Cast Extension Message (could not create candidate).";
260 return false;
261 }
262 if (!peer_connection_->AddIceCandidate(candidate.get())) {
263 LOG(ERROR) << "Failed to apply received ICE Candidate to PeerConnection.";
264 return false;
265 }
266
267 VLOG(1) << "Received and Added ICE Candidate: " << candidate_str;
268
269 return true;
270 }
271
272 // Returns true if the ExtensionMessage was of type |kMessageType|, even if
273 // it was badly formed or a resulting action failed. This is done so that
274 // the host does not continue to attempt to pass |message| to other
275 // HostExtensionSessions.
276 bool CastExtensionSession::OnExtensionMessage(
277 ClientSessionControl* client_session_control,
278 protocol::ClientStub* client_stub,
279 const protocol::ExtensionMessage& message) {
280 if (!message.has_type() || message.type().compare(kMessageType) != 0) {
Wez 2014/08/07 01:25:33 Doesn't the HostExtensionSessionManager already ch
aiguha 2014/08/12 01:42:36 That was my Java mind talking. Fixed!
aiguha 2014/08/12 01:42:38 Acknowledged.
281 return false;
282 }
283
284 scoped_ptr<base::Value> value(base::JSONReader::Read(message.data()));
285 base::DictionaryValue* client_message;
286 if (!(value && value->GetAsDictionary(&client_message))) {
287 LOG(ERROR) << "Could not read cast extension message.";
288 return true;
289 }
290
291 std::string subject;
292 if (!client_message->GetString(kMessageSubject, &subject)) {
293 LOG(ERROR) << "Invalid Cast Extension Message (missing subject header).";
294 return true;
295 }
296
297 if (subject == kSubjectOffer && !received_offer_) {
298 if (ParseAndSetRemoteDescription(client_message)) {
299 // Reset the video pipeline so we can grab the screen capturer and setup
300 // a video stream.
301 received_offer_ = true;
302 client_session_control_->ResetVideoPipeline();
303 }
304 } else if (subject == kSubjectAnswer) {
305 ParseAndSetRemoteDescription(client_message);
306 } else if (subject == kSubjectNewCandidate) {
307 ParseAndAddICECandidate(client_message);
308 } else {
309 VLOG(1) << "Unexpected CastExtension Message: " << message.data();
310 }
311 return true;
312 }
313
314 bool CastExtensionSession::ModifiesVideoPipeline() const {
315 return true;
316 }
317
318 scoped_ptr<webrtc::ScreenCapturer> CastExtensionSession::OnCreateVideoCapturer(
319 scoped_ptr<webrtc::ScreenCapturer> capturer) {
320 // TODO(aiguha): Support the case(s) where we've grabbed the capturer already,
321 // but another extension reset the video pipeline. We should remove the
322 // stream from the peer connection here, and then attempt to re-setup the
323 // peer connection in the OnRenegotiationNeeded() callback.
324 if (has_grabbed_capturer_) {
325 LOG(ERROR) << "The video pipeline was reset unexpectedly.";
326 has_grabbed_capturer_ = false;
327 peer_connection_->RemoveStream(stream_.release());
328 return capturer.Pass();
329 }
330
331 if (received_offer_) {
332 has_grabbed_capturer_ = true;
333 if (SetupVideoStream(capturer.Pass())) {
334 peer_connection_->CreateAnswer(
335 CastCreateSessionDescriptionObserver::Create(this), NULL);
336 } else {
337 has_grabbed_capturer_ = false;
338 // Ignore the received offer, since we failed to setup a video stream.
339 received_offer_ = false;
340 }
341 return scoped_ptr<webrtc::ScreenCapturer>();
342 }
343
344 return capturer.Pass();
345 }
346
347 // Private Methods -------------------------------------------------------------
348
349 bool CastExtensionSession::SendMessageToClient(const char* subject,
350 const std::string& data) {
351 DCHECK(network_task_runner_->BelongsToCurrentThread());
352 if (client_stub_ == NULL) {
353 LOG(ERROR) << "No Client Stub. Cannot send message to client.";
354 return false;
355 }
356
357 base::DictionaryValue message_dict;
358 message_dict.SetString(kMessageSubject, subject);
359 message_dict.SetString(kMessageData, data);
360 std::string message_json;
361
362 if (!base::JSONWriter::Write(&message_dict, &message_json)) {
363 LOG(ERROR) << "Failed to create message json.";
364 return false;
365 }
366
367 protocol::ExtensionMessage message;
368 message.set_type(kMessageType);
369 message.set_data(message_json);
370 client_stub_->DeliverHostMessage(message);
371 return true;
372 }
373
374 void CastExtensionSession::SendCursorShape(
375 scoped_ptr<protocol::CursorShapeInfo> cursor_shape) {
376 DCHECK(network_task_runner_->BelongsToCurrentThread());
377 if (!client_stub_)
378 return;
379
380 client_stub_->SetCursorShape(*cursor_shape);
381 }
382
383 void CastExtensionSession::EnsureTaskAndSetSend(talk_base::Thread** ptr,
384 base::WaitableEvent* event) {
385 jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
386 jingle_glue::JingleThreadWrapper::current()->set_send_allowed(true);
387 *ptr = jingle_glue::JingleThreadWrapper::current();
388
389 if (event != NULL) {
390 event->Signal();
391 }
392 }
393
394 bool CastExtensionSession::WrapTasksAndSave() {
395 DCHECK(network_task_runner_->BelongsToCurrentThread());
396 EnsureTaskAndSetSend(&network_thread_wrapper_);
397
398 if (network_thread_wrapper_ == NULL)
399 return false;
400 base::WaitableEvent wrap_worker_thread_event(true, false);
401 worker_task_runner_->PostTask(
402 FROM_HERE,
403 base::Bind(&CastExtensionSession::EnsureTaskAndSetSend,
404 base::Unretained(this),
405 &worker_thread_wrapper_,
406 &wrap_worker_thread_event));
407 wrap_worker_thread_event.Wait();
408
409 return (worker_thread_wrapper_ != NULL);
410 }
411
412 bool CastExtensionSession::InitializePeerConnection() {
413 DCHECK(network_task_runner_->BelongsToCurrentThread());
414 DCHECK(peer_conn_factory_.get() == NULL);
415 DCHECK(peer_connection_.get() == NULL);
416 DCHECK(worker_thread_wrapper_ != NULL);
417 DCHECK(network_thread_wrapper_ != NULL);
418
419 peer_conn_factory_ = webrtc::CreatePeerConnectionFactory(
420 worker_thread_wrapper_, network_thread_wrapper_, NULL, NULL, NULL);
421
422 if (!peer_conn_factory_.get()) {
423 LOG(ERROR) << "Failed to initialize PeerConnectionFactory";
424 DeletePeerConnection();
425 return false;
426 }
427
428 VLOG(1) << "Created PeerConnectionFactory successfully.";
429
430 webrtc::PeerConnectionInterface::IceServers servers;
431 webrtc::PeerConnectionInterface::IceServer server;
432 server.uri = kDefaultStunURI;
433 servers.push_back(server);
434 webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
435 rtc_config.servers = servers;
436 webrtc::FakeConstraints constraints;
437
438 // DTLS-SRTP is the preferred encryption method. If set to kValueFalse, the
439 // peer connection uses SDES. Disabling SDES as well will cause the peer
440 // connection to fail to connect.
441 // Note: For protection and unprotection of SRTP packets, the libjingle
442 // ENABLE_EXTERNAL_AUTH flag must not be set.
443 constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
444 webrtc::MediaConstraintsInterface::kValueTrue);
445
446 peer_connection_ = peer_conn_factory_->CreatePeerConnection(
447 rtc_config,
448 &constraints,
449 ChromiumPortAllocatorFactory::Create(network_settings_,
450 url_request_context_getter_),
451 NULL,
452 this);
453
454 if (!peer_connection_.get()) {
455 LOG(ERROR) << "Failed to initialize PeerConnection.";
456 DeletePeerConnection();
457 return false;
458 }
459
460 VLOG(1) << "Created PeerConnection successfully.";
461
462 if (!SendMessageToClient(kSubjectTest, "Hello, client.")) {
463 LOG(ERROR) << "Failed to send test message to client.";
464 return false;
465 }
466 // Sending this message triggers the client to start the peer connection
467 // offer/answer negotiation.
468 if (!SendMessageToClient(kSubjectReady, "Host ready to receive offers.")) {
469 LOG(ERROR) << "Failed to send ready message to client.";
470 return false;
471 }
472
473 return true;
474 }
475
476 bool CastExtensionSession::SetupVideoStream(
477 scoped_ptr<webrtc::ScreenCapturer> screen_capturer) {
478 DCHECK(network_task_runner_->BelongsToCurrentThread());
479 DCHECK(screen_capturer);
480
481 if (stream_) {
482 VLOG(1) << "Already added MediaStream. Aborting Setup.";
483 return false; // Already added.
484 }
485
486 // scoped_ptr<CastVideoCapturer> cast_video_capturer(
487 // new CastVideoCapturer(screen_capturer.Pass()));
488
489 // Set video stream constraints.
490 std::string minFrameRate = "5";
491 webrtc::FakeConstraints video_constraints;
492 video_constraints.AddMandatory(
493 webrtc::MediaConstraintsInterface::kMinFrameRate, minFrameRate);
494
495 talk_base::scoped_refptr<webrtc::VideoTrackInterface> video_track =
496 peer_conn_factory_->CreateVideoTrack(
497 kVideoLabel,
498 peer_conn_factory_->CreateVideoSource(NULL,
499 &video_constraints));
500
501 stream_ = peer_conn_factory_->CreateLocalMediaStream(kStreamLabel);
502
503 if (!stream_->AddTrack(video_track))
504 return false;
505
506 if (!peer_connection_->AddStream(stream_, NULL))
507 return false;
508
509 VLOG(1) << "Setup video stream successfully.";
510
511 return true;
512 }
513
514 void CastExtensionSession::PollPeerConnectionStats() {
515 if (!connection_active()) {
516 VLOG(1) << "Cannot poll stats while PeerConnection is inactive.";
517 }
518 talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface> video_track =
519 stream_->FindVideoTrack(kVideoLabel);
520 peer_connection_->GetStats(
521 stats_observer_,
522 video_track.release(),
523 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard);
524 }
525
526 void CastExtensionSession::DeletePeerConnection() {
527 VLOG(1) << "DeletePeerConnection called.";
528 peer_connection_->Close();
529 peer_connection_ = NULL;
530 stream_ = NULL;
531 peer_conn_factory_ = NULL;
532 }
533
534 bool CastExtensionSession::connection_active() const {
535 return peer_connection_.get() != NULL;
536 }
537
538 // MouseShapeObserver implementation -------------------------------------------
539
540 // TODO(aiguha): To reduce duplication, it would perhaps be
541 // better to create a single MouseShapeObserver outside of VideoScheduler
542 // that can be attached to the ScreenCapturer on its creation in
543 // ClientSession.
544 void CastExtensionSession::OnCursorShapeChanged(
545 webrtc::MouseCursorShape* cursor_shape) {
546 DCHECK(worker_task_runner_->BelongsToCurrentThread());
547 scoped_ptr<webrtc::MouseCursorShape> owned_cursor(cursor_shape);
548
549 scoped_ptr<protocol::CursorShapeInfo> cursor_proto(
550 new protocol::CursorShapeInfo());
551 cursor_proto->set_width(cursor_shape->size.width());
552 cursor_proto->set_height(cursor_shape->size.height());
553 cursor_proto->set_hotspot_x(cursor_shape->hotspot.x());
554 cursor_proto->set_hotspot_y(cursor_shape->hotspot.y());
555 cursor_proto->set_data(cursor_shape->data);
556
557 network_task_runner_->PostTask(
558 FROM_HERE,
559 base::Bind(&CastExtensionSession::SendCursorShape,
560 base::Unretained(this),
561 base::Passed(&cursor_proto)));
562 }
563
564 // CreateSessionDescriptionObserver related methods ----------------------------
565
566 void CastExtensionSession::OnSuccess(
567 webrtc::SessionDescriptionInterface* desc) {
568 if (!network_task_runner_->BelongsToCurrentThread()) {
569 network_task_runner_->PostTask(
570 FROM_HERE,
571 base::Bind(
572 &CastExtensionSession::OnSuccess, base::Unretained(this), desc));
573 return;
574 }
575 peer_connection_->SetLocalDescription(
576 CastSetSessionDescriptionObserver::Create(), desc);
577 scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
578 json->SetString(kWebRtcSessionDescType, desc->type());
579 std::string subject = kWebRtcPrefix + desc->type();
580 std::string desc_str;
581 desc->ToString(&desc_str);
582 json->SetString(kWebRtcSessionDescSDP, desc_str);
583 std::string json_str;
584 base::JSONWriter::Write(json.get(), &json_str);
585 SendMessageToClient(subject.c_str(), json_str);
586 }
587
588 void CastExtensionSession::OnFailure(const std::string& error) {
589 VLOG(1) << __FUNCTION__ << " called with: " << error;
590 }
591
592 // PeerConnectionObserver implementation ---------------------------------------
593
594 void CastExtensionSession::OnError() {
595 VLOG(1) << __FUNCTION__;
596 }
597 void CastExtensionSession::OnSignalingChange(
598 webrtc::PeerConnectionInterface::SignalingState new_state) {
599 VLOG(1) << "Function CastExtensionSession::OnSignalingChange called with "
600 << new_state;
601 }
602 void CastExtensionSession::OnStateChange(
603 webrtc::PeerConnectionObserver::StateType state_changed) {
604 VLOG(1) << __FUNCTION__ << " called with input " << state_changed;
605 }
606 void CastExtensionSession::OnAddStream(webrtc::MediaStreamInterface* stream) {
607 VLOG(1) << __FUNCTION__ << " " << stream->label();
608 }
609 void CastExtensionSession::OnRemoveStream(
610 webrtc::MediaStreamInterface* stream) {
611 VLOG(1) << __FUNCTION__ << " " << stream->label();
612 }
613 void CastExtensionSession::OnDataChannel(
614 webrtc::DataChannelInterface* data_channel) {
615 VLOG(1) << __FUNCTION__ << " called with " << data_channel->label();
616 }
617 void CastExtensionSession::OnRenegotiationNeeded() {
618 VLOG(1) << __FUNCTION__ << " called.";
619 }
620 void CastExtensionSession::OnIceConnectionChange(
621 webrtc::PeerConnectionInterface::IceConnectionState new_state) {
622 VLOG(1) << __FUNCTION__ << " called with new IceConnectionState "
623 << new_state;
624 }
625 void CastExtensionSession::OnIceGatheringChange(
626 webrtc::PeerConnectionInterface::IceGatheringState new_state) {
627 VLOG(1) << __FUNCTION__ << " called with new IceGatheringState " << new_state;
628 }
629
630 void CastExtensionSession::OnIceComplete() {
631 // TODO(aiguha): Maybe start timer only if enabled by command-line flag or
632 // at a particular verbosity level.
633 stats_polling_timer_.Start(FROM_HERE,
634 base::TimeDelta::FromSeconds(kStatsLogIntervalSec),
635 this,
636 &CastExtensionSession::PollPeerConnectionStats);
637 }
638
639 void CastExtensionSession::OnIceCandidate(
640 const webrtc::IceCandidateInterface* candidate) {
641 std::string candidate_str;
642 if (!candidate->ToString(&candidate_str)) {
643 LOG(ERROR) << __FUNCTION__ << " called, but could not serialize candidate.";
644 return;
645 }
646 VLOG(1) << __FUNCTION__ << " called with " << candidate_str;
647 scoped_ptr<base::DictionaryValue> json(new base::DictionaryValue());
648 json->SetString(kWebRtcSDPMid, candidate->sdp_mid());
649 json->SetInteger(kWebRtcSDPMLineIndex, candidate->sdp_mline_index());
650 json->SetString(kWebRtcCandidate, candidate_str);
651 std::string json_str;
652 base::JSONWriter::Write(json.get(), &json_str);
653 SendMessageToClient(kSubjectNewCandidate, json_str);
654 }
655
656 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698