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 |