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

Side by Side Diff: chrome/browser/media/cast_remoting_connector.cc

Issue 2951523002: Media Remoting: Add mojo interfaces between browser and extension. (Closed)
Patch Set: Fix compile failure on Android bots. Created 3 years, 6 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "chrome/browser/media/cast_remoting_connector.h" 5 #include "chrome/browser/media/cast_remoting_connector.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/media/cast_remoting_connector_messaging.h"
14 #include "chrome/browser/media/cast_remoting_sender.h" 13 #include "chrome/browser/media/cast_remoting_sender.h"
15 #include "chrome/browser/media/router/media_router.h" 14 #include "chrome/browser/media/router/media_router.h"
16 #include "chrome/browser/media/router/media_router_factory.h" 15 #include "chrome/browser/media/router/media_router_factory.h"
17 #include "chrome/browser/media/router/route_message_observer.h"
18 #include "chrome/browser/sessions/session_tab_helper.h" 16 #include "chrome/browser/sessions/session_tab_helper.h"
19 #include "chrome/common/chrome_features.h" 17 #include "chrome/common/chrome_features.h"
20 #include "chrome/common/media_router/media_source_helper.h"
21 #include "chrome/common/media_router/route_message.h"
22 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/render_frame_host.h" 19 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h" 20 #include "content/public/browser/render_process_host.h"
25 #include "content/public/browser/web_contents.h" 21 #include "content/public/browser/web_contents.h"
26 #include "mojo/public/cpp/bindings/strong_binding.h" 22 #include "mojo/public/cpp/bindings/strong_binding.h"
27 23
28 using content::BrowserThread; 24 using content::BrowserThread;
29 using media::mojom::RemotingSinkCapabilities; 25 using media::mojom::RemotingSinkCapabilities;
30 using media::mojom::RemotingStartFailReason; 26 using media::mojom::RemotingStartFailReason;
31 using media::mojom::RemotingStopReason; 27 using media::mojom::RemotingStopReason;
32 28
33 using Messaging = CastRemotingConnectorMessaging;
34
35 class CastRemotingConnector::RemotingBridge : public media::mojom::Remoter { 29 class CastRemotingConnector::RemotingBridge : public media::mojom::Remoter {
36 public: 30 public:
37 // Constructs a "bridge" to delegate calls between the given |source| and 31 // Constructs a "bridge" to delegate calls between the given |source| and
38 // |connector|. |connector| must be valid at the time of construction, but is 32 // |connector|. |connector| must be valid at the time of construction, but is
39 // otherwise a weak pointer that can become invalid during the lifetime of a 33 // otherwise a weak pointer that can become invalid during the lifetime of a
40 // RemotingBridge. 34 // RemotingBridge.
41 RemotingBridge(media::mojom::RemotingSourcePtr source, 35 RemotingBridge(media::mojom::RemotingSourcePtr source,
42 CastRemotingConnector* connector) 36 CastRemotingConnector* connector)
43 : source_(std::move(source)), connector_(connector) { 37 : source_(std::move(source)), connector_(connector) {
44 DCHECK(connector_); 38 DCHECK(connector_);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 private: 99 private:
106 media::mojom::RemotingSourcePtr source_; 100 media::mojom::RemotingSourcePtr source_;
107 101
108 // Weak pointer. Will be set to nullptr if the CastRemotingConnector is 102 // Weak pointer. Will be set to nullptr if the CastRemotingConnector is
109 // destroyed before this RemotingBridge. 103 // destroyed before this RemotingBridge.
110 CastRemotingConnector* connector_; 104 CastRemotingConnector* connector_;
111 105
112 DISALLOW_COPY_AND_ASSIGN(RemotingBridge); 106 DISALLOW_COPY_AND_ASSIGN(RemotingBridge);
113 }; 107 };
114 108
115 class CastRemotingConnector::MessageObserver
116 : public media_router::RouteMessageObserver {
117 public:
118 MessageObserver(media_router::MediaRouter* router,
119 const media_router::MediaRoute::Id& route_id,
120 CastRemotingConnector* connector)
121 : RouteMessageObserver(router, route_id), connector_(connector) {}
122 ~MessageObserver() final {}
123
124 private:
125 void OnMessagesReceived(
126 const std::vector<media_router::RouteMessage>& messages) final {
127 connector_->ProcessMessagesFromRoute(messages);
128 }
129
130 CastRemotingConnector* const connector_;
131 };
132
133 // static 109 // static
134 const void* const CastRemotingConnector::kUserDataKey = &kUserDataKey; 110 const void* const CastRemotingConnector::kUserDataKey = &kUserDataKey;
135 111
136 // static 112 // static
137 CastRemotingConnector* CastRemotingConnector::Get( 113 CastRemotingConnector* CastRemotingConnector::Get(
138 content::WebContents* contents) { 114 content::WebContents* contents) {
139 DCHECK(contents); 115 DCHECK(contents);
140 CastRemotingConnector* connector = 116 CastRemotingConnector* connector =
141 static_cast<CastRemotingConnector*>(contents->GetUserData(kUserDataKey)); 117 static_cast<CastRemotingConnector*>(contents->GetUserData(kUserDataKey));
142 if (!connector) { 118 if (!connector) {
143 connector = new CastRemotingConnector( 119 connector = new CastRemotingConnector(
144 media_router::MediaRouterFactory::GetApiForBrowserContext( 120 media_router::MediaRouterFactory::GetApiForBrowserContext(
145 contents->GetBrowserContext()), 121 contents->GetBrowserContext()),
146 media_router::MediaSourceForTabContentRemoting( 122 SessionTabHelper::IdForTab(contents));
147 SessionTabHelper::IdForTab(contents))
148 .id());
149 contents->SetUserData(kUserDataKey, base::WrapUnique(connector)); 123 contents->SetUserData(kUserDataKey, base::WrapUnique(connector));
150 } 124 }
151 return connector; 125 return connector;
152 } 126 }
153 127
154 // static 128 // static
155 void CastRemotingConnector::CreateMediaRemoter( 129 void CastRemotingConnector::CreateMediaRemoter(
156 content::RenderFrameHost* host, 130 content::RenderFrameHost* host,
157 media::mojom::RemotingSourcePtr source, 131 media::mojom::RemotingSourcePtr source,
158 media::mojom::RemoterRequest request) { 132 media::mojom::RemoterRequest request) {
159 DCHECK(host); 133 DCHECK(host);
160 auto* const contents = content::WebContents::FromRenderFrameHost(host); 134 auto* const contents = content::WebContents::FromRenderFrameHost(host);
161 if (!contents) 135 if (!contents)
162 return; 136 return;
163 CastRemotingConnector::Get(contents)->CreateBridge(std::move(source), 137 CastRemotingConnector::Get(contents)->CreateBridge(std::move(source),
164 std::move(request)); 138 std::move(request));
165 } 139 }
166 140
167 namespace { 141 namespace {
168 RemotingSinkCapabilities GetFeatureEnabledCapabilities() { 142 RemotingSinkCapabilities GetFeatureEnabledCapabilities() {
169 #if !defined(OS_ANDROID) && !defined(OS_IOS) 143 #if !defined(OS_ANDROID) && !defined(OS_IOS)
170 if (base::FeatureList::IsEnabled(features::kMediaRemoting)) { 144 if (base::FeatureList::IsEnabled(features::kMediaRemoting)) {
171 return RemotingSinkCapabilities::RENDERING_ONLY; 145 return RemotingSinkCapabilities::RENDERING_ONLY;
172 } 146 }
173 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 147 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
174 return RemotingSinkCapabilities::NONE; 148 return RemotingSinkCapabilities::NONE;
175 } 149 }
176 } // namespace 150 } // namespace
177 151
178 CastRemotingConnector::CastRemotingConnector( 152 CastRemotingConnector::CastRemotingConnector(media_router::MediaRouter* router,
179 media_router::MediaRouter* router, 153 int32_t tab_id)
180 const media_router::MediaSource::Id& media_source_id) 154 : media_router_(router),
181 : media_router::MediaRoutesObserver(router), 155 tab_id_(tab_id),
182 media_source_id_(media_source_id),
183 enabled_features_(GetFeatureEnabledCapabilities()), 156 enabled_features_(GetFeatureEnabledCapabilities()),
184 session_counter_(0),
185 active_bridge_(nullptr), 157 active_bridge_(nullptr),
186 weak_factory_(this) {} 158 binding_(this),
159 weak_factory_(this) {
160 if (tab_id_ > 0) {
imcheng 2017/06/22 01:13:27 So it seems this class doesn't do much if tab_id_
xjz 2017/06/23 19:02:40 Changes the condition to (tab_id_ != -1). Currentl
161 VLOG(3) << "Register CastRemotingConnector for tab_id = " << tab_id_;
162 media_router_->RegisterRemotingSource(tab_id_, this);
163 }
164 }
187 165
188 CastRemotingConnector::~CastRemotingConnector() { 166 CastRemotingConnector::~CastRemotingConnector() {
189 // Assume nothing about destruction/shutdown sequence of a tab. For example, 167 // Assume nothing about destruction/shutdown sequence of a tab. For example,
190 // it's possible the owning WebContents will be destroyed before the Mojo 168 // it's possible the owning WebContents will be destroyed before the Mojo
191 // message pipes to the RemotingBridges have been closed. 169 // message pipes to the RemotingBridges have been closed.
192 if (active_bridge_) 170 if (active_bridge_)
193 StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED); 171 StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED);
194 for (RemotingBridge* notifyee : bridges_) { 172 for (RemotingBridge* notifyee : bridges_) {
195 notifyee->OnSinkGone(); 173 notifyee->OnSinkGone();
196 notifyee->OnCastRemotingConnectorDestroyed(); 174 notifyee->OnCastRemotingConnectorDestroyed();
197 } 175 }
176 if (tab_id_ > 0)
177 media_router_->UnRegisterRemotingSource(tab_id_, this);
178 }
179
180 void CastRemotingConnector::ConnectToService(
181 media::mojom::MirrorServiceRemotingSourceRequest source_request,
182 media::mojom::MirrorServiceRemoterPtr remoter) {
183 DCHECK(!binding_.is_bound());
184 DCHECK(!remoter_);
185 DCHECK(remoter);
186 VLOG(3) << __func__;
imcheng 2017/06/22 01:13:27 nit: move the VLOG either above or below all DCHEC
xjz 2017/06/23 19:02:40 Done.
187 DCHECK_CURRENTLY_ON(BrowserThread::UI);
188
189 binding_.Bind(std::move(source_request));
190 binding_.set_connection_error_handler(base::Bind(
191 &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this)));
192 remoter_ = std::move(remoter);
193 remoter_.set_connection_error_handler(base::Bind(
194 &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this)));
195 }
196
197 void CastRemotingConnector::OnMirrorServiceStopped() {
198 VLOG(3) << __func__;
199 DCHECK_CURRENTLY_ON(BrowserThread::UI);
200
201 if (binding_.is_bound())
202 binding_.Close();
203 remoter_.reset();
204
205 for (RemotingBridge* notifyee : bridges_)
206 notifyee->OnSinkGone();
198 } 207 }
199 208
200 void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source, 209 void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source,
201 media::mojom::RemoterRequest request) { 210 media::mojom::RemoterRequest request) {
202 mojo::MakeStrongBinding( 211 mojo::MakeStrongBinding(
203 base::MakeUnique<RemotingBridge>(std::move(source), this), 212 base::MakeUnique<RemotingBridge>(std::move(source), this),
204 std::move(request)); 213 std::move(request));
205 } 214 }
206 215
207 void CastRemotingConnector::RegisterBridge(RemotingBridge* bridge) { 216 void CastRemotingConnector::RegisterBridge(RemotingBridge* bridge) {
208 DCHECK_CURRENTLY_ON(BrowserThread::UI); 217 DCHECK_CURRENTLY_ON(BrowserThread::UI);
209 DCHECK(bridges_.find(bridge) == bridges_.end()); 218 DCHECK(bridges_.find(bridge) == bridges_.end());
210 219
211 bridges_.insert(bridge); 220 bridges_.insert(bridge);
212 if (message_observer_ && !active_bridge_) 221 // TODO(xjz): Pass the receiver's capabilities to the source.
222 if (remoter_ && !active_bridge_)
213 bridge->OnSinkAvailable(enabled_features_); 223 bridge->OnSinkAvailable(enabled_features_);
214 } 224 }
215 225
216 void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge, 226 void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge,
217 RemotingStopReason reason) { 227 RemotingStopReason reason) {
218 DCHECK_CURRENTLY_ON(BrowserThread::UI); 228 DCHECK_CURRENTLY_ON(BrowserThread::UI);
219 DCHECK(bridges_.find(bridge) != bridges_.end()); 229 DCHECK(bridges_.find(bridge) != bridges_.end());
220 230
221 if (bridge == active_bridge_) 231 if (bridge == active_bridge_)
222 StopRemoting(bridge, reason); 232 StopRemoting(bridge, reason);
223 bridges_.erase(bridge); 233 bridges_.erase(bridge);
224 } 234 }
225 235
226 void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { 236 void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) {
237 VLOG(3) << __func__;
227 DCHECK_CURRENTLY_ON(BrowserThread::UI); 238 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 DCHECK(bridges_.find(bridge) != bridges_.end()); 239 DCHECK(bridges_.find(bridge) != bridges_.end());
229 240
230 // Refuse to start if there is no remoting route available, or if remoting is 241 // Refuse to start if there is no remoting route available, or if remoting is
231 // already active. 242 // already active.
232 if (!message_observer_) { 243 if (!remoter_) {
233 bridge->OnStartFailed(RemotingStartFailReason::ROUTE_TERMINATED); 244 VLOG(3) << "Remoting start failed: No mirror service connected.";
245 bridge->OnStartFailed(RemotingStartFailReason::SERVICE_NOT_CONNECTED);
234 return; 246 return;
235 } 247 }
236 if (active_bridge_) { 248 if (active_bridge_) {
249 VLOG(3) << "Remoting start failed: Cannot start multiple.";
237 bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE); 250 bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE);
238 return; 251 return;
239 } 252 }
240 253
241 // Notify all other sources that the sink is no longer available for remoting. 254 // Notify all other sources that the sink is no longer available for remoting.
242 // A race condition is possible, where one of the other sources will try to 255 // A race condition is possible, where one of the other sources will try to
243 // start remoting before receiving this notification; but that attempt will 256 // start remoting before receiving this notification; but that attempt will
244 // just fail later on. 257 // just fail later on.
245 for (RemotingBridge* notifyee : bridges_) { 258 for (RemotingBridge* notifyee : bridges_) {
246 if (notifyee == bridge) 259 if (notifyee == bridge)
247 continue; 260 continue;
248 notifyee->OnSinkGone(); 261 notifyee->OnSinkGone();
249 } 262 }
250 263
251 active_bridge_ = bridge; 264 active_bridge_ = bridge;
265 remoter_->Start();
266 }
252 267
253 // Send a start message to the Cast Provider. 268 void CastRemotingConnector::OnStarted() {
254 ++session_counter_; // New remoting session ID. 269 VLOG(3) << __func__;
255 SendMessageToProvider(base::StringPrintf( 270 DCHECK_CURRENTLY_ON(BrowserThread::UI);
256 Messaging::kStartRemotingMessageFormat, session_counter_));
257 271
258 bridge->OnStarted(); 272 if (!active_bridge_) {
273 remoter_->Stop(media::mojom::RemotingStopReason::SOURCE_GONE);
274 return;
275 }
276 active_bridge_->OnStarted();
277 }
278
279 void CastRemotingConnector::OnStartFailed(
280 media::mojom::RemotingStartFailReason reason) {
281 VLOG(3) << __func__ << ": reason = " << reason;
282 DCHECK_CURRENTLY_ON(BrowserThread::UI);
283
284 if (!active_bridge_)
285 return;
286 active_bridge_->OnStartFailed(reason);
287 active_bridge_ = nullptr;
259 } 288 }
260 289
261 void CastRemotingConnector::StartRemotingDataStreams( 290 void CastRemotingConnector::StartRemotingDataStreams(
262 RemotingBridge* bridge, 291 RemotingBridge* bridge,
263 mojo::ScopedDataPipeConsumerHandle audio_pipe, 292 mojo::ScopedDataPipeConsumerHandle audio_pipe,
264 mojo::ScopedDataPipeConsumerHandle video_pipe, 293 mojo::ScopedDataPipeConsumerHandle video_pipe,
265 media::mojom::RemotingDataStreamSenderRequest audio_sender_request, 294 media::mojom::RemotingDataStreamSenderRequest audio_sender_request,
266 media::mojom::RemotingDataStreamSenderRequest video_sender_request) { 295 media::mojom::RemotingDataStreamSenderRequest video_sender_request) {
296 VLOG(3) << __func__;
267 DCHECK_CURRENTLY_ON(BrowserThread::UI); 297 DCHECK_CURRENTLY_ON(BrowserThread::UI);
268 298
269 // Refuse to start if there is no remoting route available, or if remoting is 299 // Refuse to start if there is no remoting route available, or if remoting is
270 // not active for this |bridge|. 300 // not active for this |bridge|.
271 if (!message_observer_ || active_bridge_ != bridge) 301 if (!remoter_ || active_bridge_ != bridge)
272 return; 302 return;
273 // Also, if neither audio nor video pipe was provided, or if a request for a 303 // Also, if neither audio nor video pipe was provided, or if a request for a
274 // RemotingDataStreamSender was not provided for a data pipe, error-out early. 304 // RemotingDataStreamSender was not provided for a data pipe, error-out early.
275 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) || 305 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) ||
276 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) || 306 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) ||
277 (video_pipe.is_valid() && !video_sender_request.is_pending())) { 307 (video_pipe.is_valid() && !video_sender_request.is_pending())) {
278 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); 308 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
279 return; 309 return;
280 } 310 }
281 311
282 // Hold on to the data pipe handles and interface requests until one/both 312 // Hold on to the data pipe handles and interface requests until one/both
283 // CastRemotingSenders are created and ready for use. 313 // CastRemotingSenders are created and ready for use.
284 pending_audio_pipe_ = std::move(audio_pipe); 314 pending_audio_pipe_ = std::move(audio_pipe);
285 pending_video_pipe_ = std::move(video_pipe); 315 pending_video_pipe_ = std::move(video_pipe);
286 pending_audio_sender_request_ = std::move(audio_sender_request); 316 pending_audio_sender_request_ = std::move(audio_sender_request);
287 pending_video_sender_request_ = std::move(video_sender_request); 317 pending_video_sender_request_ = std::move(video_sender_request);
288 318
289 // Send a "start streams" message to the Cast Provider. The provider is 319 remoter_->StartDataStreams(pending_audio_sender_request_.is_pending(),
290 // responsible for creating and setting up a remoting Cast Streaming session 320 pending_video_sender_request_.is_pending());
291 // that will result in new CastRemotingSender instances being created here in 321 }
292 // the browser process. 322
293 SendMessageToProvider(base::StringPrintf( 323 void CastRemotingConnector::OnDataStreamsStarted(int32_t audio_stream_id,
294 Messaging::kStartStreamsMessageFormat, session_counter_, 324 int32_t video_stream_id) {
295 pending_audio_sender_request_.is_pending() ? 'Y' : 'N', 325 VLOG(3) << __func__ << ": audio_stream_id = " << audio_stream_id
296 pending_video_sender_request_.is_pending() ? 'Y' : 'N')); 326 << " video_stream_id = " << video_stream_id;
327 DCHECK_CURRENTLY_ON(BrowserThread::UI);
328
329 if (!active_bridge_)
330 return;
331
332 if (pending_audio_sender_request_.is_pending()) {
333 cast::CastRemotingSender::FindAndBind(
334 audio_stream_id, std::move(pending_audio_pipe_),
335 std::move(pending_audio_sender_request_),
336 base::Bind(&CastRemotingConnector::OnDataSendFailed,
337 weak_factory_.GetWeakPtr()));
338 }
339 if (pending_video_sender_request_.is_pending()) {
340 cast::CastRemotingSender::FindAndBind(
341 video_stream_id, std::move(pending_video_pipe_),
342 std::move(pending_video_sender_request_),
343 base::Bind(&CastRemotingConnector::OnDataSendFailed,
344 weak_factory_.GetWeakPtr()));
345 }
297 } 346 }
298 347
299 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, 348 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge,
300 RemotingStopReason reason) { 349 RemotingStopReason reason) {
350 VLOG(3) << __func__ << ": reason = " << reason;
301 DCHECK_CURRENTLY_ON(BrowserThread::UI); 351 DCHECK_CURRENTLY_ON(BrowserThread::UI);
302 352
303 if (active_bridge_ != bridge) 353 if (active_bridge_ != bridge)
304 return; 354 return;
305 355
306 active_bridge_ = nullptr; 356 active_bridge_ = nullptr;
307 357
308 // Explicitly close the data pipes (and related requests) just in case the 358 // Explicitly close the data pipes (and related requests) just in case the
309 // "start streams" operation was interrupted. 359 // "start streams" operation was interrupted.
310 pending_audio_pipe_.reset(); 360 pending_audio_pipe_.reset();
311 pending_video_pipe_.reset(); 361 pending_video_pipe_.reset();
312 pending_audio_sender_request_ = nullptr; 362 pending_audio_sender_request_ = nullptr;
313 pending_video_sender_request_ = nullptr; 363 pending_video_sender_request_ = nullptr;
314 364
315 // Cancel all outstanding callbacks related to the remoting session. 365 // Cancel all outstanding callbacks related to the remoting session.
316 weak_factory_.InvalidateWeakPtrs(); 366 weak_factory_.InvalidateWeakPtrs();
317 367
318 // Prevent the source from trying to start again until the Cast Provider has 368 // Prevent the source from trying to start again until the Cast Provider has
319 // indicated the stop operation has completed. 369 // indicated the stop operation has completed.
320 bridge->OnSinkGone(); 370 bridge->OnSinkGone();
321 // Note: At this point, all sources should think the sink is gone. 371 // Note: At this point, all sources should think the sink is gone.
322 372
323 SendMessageToProvider(base::StringPrintf( 373 if (remoter_)
324 Messaging::kStopRemotingMessageFormat, session_counter_)); 374 remoter_->Stop(reason);
325 // Note: Once the Cast Provider sends back an acknowledgement message, all
326 // sources will be notified that the remoting sink is available again.
327 375
328 bridge->OnStopped(reason); 376 bridge->OnStopped(reason);
329 } 377 }
330 378
379 void CastRemotingConnector::OnStopped(RemotingStopReason reason) {
380 VLOG(3) << __func__ << ": reason = " << reason;
381 DCHECK_CURRENTLY_ON(BrowserThread::UI);
382 if (!active_bridge_) {
383 // Notify all the sources that the sink is available again.
384 if (remoter_) {
385 // TODO(xjz): Pass the receiver's capabilities to sources.
386 for (RemotingBridge* notifyee : bridges_) {
387 notifyee->OnSinkAvailable(enabled_features_);
imcheng 2017/06/22 01:13:27 Should we notify the other bridges with OnSinkAvai
xjz 2017/06/23 19:02:40 When |active_bridge_| is not null, it indicates th
388 }
389 }
390 return;
391 }
392 StopRemoting(active_bridge_, reason);
393 }
394
331 void CastRemotingConnector::SendMessageToSink( 395 void CastRemotingConnector::SendMessageToSink(
332 RemotingBridge* bridge, const std::vector<uint8_t>& message) { 396 RemotingBridge* bridge, const std::vector<uint8_t>& message) {
333 DCHECK_CURRENTLY_ON(BrowserThread::UI); 397 DCHECK_CURRENTLY_ON(BrowserThread::UI);
334 398
335 // During an active remoting session, simply pass all binary messages through 399 // During an active remoting session, simply pass all binary messages through
336 // to the sink. 400 // to the sink.
337 if (!message_observer_ || active_bridge_ != bridge) 401 if (!remoter_ || active_bridge_ != bridge)
338 return; 402 return;
339 media_router::MediaRoutesObserver::router()->SendRouteBinaryMessage( 403 remoter_->SendMessageToSink(message);
340 message_observer_->route_id(),
341 base::MakeUnique<std::vector<uint8_t>>(message),
342 base::Bind(&CastRemotingConnector::HandleSendMessageResult,
343 weak_factory_.GetWeakPtr()));
344 } 404 }
345 405
346 void CastRemotingConnector::SendMessageToProvider(const std::string& message) { 406 void CastRemotingConnector::OnMessageFromSink(
407 const std::vector<uint8_t>& message) {
347 DCHECK_CURRENTLY_ON(BrowserThread::UI); 408 DCHECK_CURRENTLY_ON(BrowserThread::UI);
348 409
349 if (!message_observer_) 410 // During an active remoting session, simply pass all binary messages through
411 // to the source.
412 if (!active_bridge_)
413 return;
414 active_bridge_->OnMessageFromSink(message);
415 }
416
417 void CastRemotingConnector::OnSinkAvailable(
418 media::mojom::RemotingSinkCapabilities capabilities) {
419 VLOG(3) << __func__ << ": capabilities = " << capabilities;
420 DCHECK_CURRENTLY_ON(BrowserThread::UI);
421
422 // The receiver's capabilities are supposed unchanged during an active
423 // remoting session.
424 if (active_bridge_)
350 return; 425 return;
351 426
352 if (active_bridge_) { 427 // TODO(xjz): Pass the receiver's capabilities to the sources.
353 media_router::MediaRoutesObserver::router()->SendRouteMessage( 428 for (RemotingBridge* notifyee : bridges_)
354 message_observer_->route_id(), message, 429 notifyee->OnSinkAvailable(enabled_features_);
355 base::Bind(&CastRemotingConnector::HandleSendMessageResult,
356 weak_factory_.GetWeakPtr()));
357 } else {
358 struct Helper {
359 static void IgnoreSendMessageResult(bool ignored) {}
360 };
361 media_router::MediaRoutesObserver::router()->SendRouteMessage(
362 message_observer_->route_id(), message,
363 base::Bind(&Helper::IgnoreSendMessageResult));
364 }
365 } 430 }
366 431
367 void CastRemotingConnector::ProcessMessagesFromRoute( 432 void CastRemotingConnector::OnError() {
368 const std::vector<media_router::RouteMessage>& messages) { 433 VLOG(3) << __func__;
369 DCHECK_CURRENTLY_ON(BrowserThread::UI); 434 DCHECK_CURRENTLY_ON(BrowserThread::UI);
370 435 if (active_bridge_)
371 // Note: If any calls to message parsing functions are added/changed here, 436 StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE);
372 // please update cast_remoting_connector_fuzzertest.cc as well!
373
374 for (const media_router::RouteMessage& message : messages) {
375 switch (message.type) {
376 case media_router::RouteMessage::TEXT:
377 // This is a notification message from the Cast Provider, about the
378 // execution state of the media remoting session between Chrome and the
379 // remote device.
380 DCHECK(message.text);
381
382 // If this is a "start streams" acknowledgement message, the
383 // CastRemotingSenders should now be available to begin consuming from
384 // the data pipes.
385 if (active_bridge_ &&
386 Messaging::IsMessageForSession(
387 *message.text,
388 Messaging::kStartedStreamsMessageFormatPartial,
389 session_counter_)) {
390 if (pending_audio_sender_request_.is_pending()) {
391 cast::CastRemotingSender::FindAndBind(
392 Messaging::GetStreamIdFromStartedMessage(
393 *message.text,
394 Messaging::kStartedStreamsMessageAudioIdSpecifier),
395 std::move(pending_audio_pipe_),
396 std::move(pending_audio_sender_request_),
397 base::Bind(&CastRemotingConnector::OnDataSendFailed,
398 weak_factory_.GetWeakPtr()));
399 }
400 if (pending_video_sender_request_.is_pending()) {
401 cast::CastRemotingSender::FindAndBind(
402 Messaging::GetStreamIdFromStartedMessage(
403 *message.text,
404 Messaging::kStartedStreamsMessageVideoIdSpecifier),
405 std::move(pending_video_pipe_),
406 std::move(pending_video_sender_request_),
407 base::Bind(&CastRemotingConnector::OnDataSendFailed,
408 weak_factory_.GetWeakPtr()));
409 }
410 break;
411 }
412
413 // If this is a failure message, call StopRemoting().
414 if (active_bridge_ &&
415 Messaging::IsMessageForSession(*message.text,
416 Messaging::kFailedMessageFormat,
417 session_counter_)) {
418 StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE);
419 break;
420 }
421
422 // If this is a stop acknowledgement message, indicating that the last
423 // session was stopped, notify all sources that the sink is once again
424 // available.
425 if (Messaging::IsMessageForSession(*message.text,
426 Messaging::kStoppedMessageFormat,
427 session_counter_)) {
428 if (active_bridge_) {
429 // Hmm...The Cast Provider was in a state that disagrees with this
430 // connector. Attempt to resolve this by shutting everything down to
431 // effectively reset to a known state.
432 LOG(WARNING) << "BUG: Cast Provider sent 'stopped' message during "
433 "an active remoting session.";
434 StopRemoting(active_bridge_,
435 RemotingStopReason::UNEXPECTED_FAILURE);
436 }
437 for (RemotingBridge* notifyee : bridges_)
438 notifyee->OnSinkAvailable(enabled_features_);
439 break;
440 }
441
442 LOG(WARNING) << "BUG: Unexpected message from Cast Provider: "
443 << *message.text;
444 break;
445
446 case media_router::RouteMessage::BINARY: // This is for the source.
447 DCHECK(message.binary);
448
449 // All binary messages are passed through to the source during an active
450 // remoting session.
451 if (active_bridge_)
452 active_bridge_->OnMessageFromSink(*message.binary);
453 break;
454 }
455 }
456 }
457
458 void CastRemotingConnector::HandleSendMessageResult(bool success) {
459 DCHECK_CURRENTLY_ON(BrowserThread::UI);
460 // A single message send failure is treated as fatal to an active remoting
461 // session.
462 if (!success && active_bridge_)
463 StopRemoting(active_bridge_, RemotingStopReason::MESSAGE_SEND_FAILED);
464 } 437 }
465 438
466 void CastRemotingConnector::OnDataSendFailed() { 439 void CastRemotingConnector::OnDataSendFailed() {
440 VLOG(3) << __func__;
467 DCHECK_CURRENTLY_ON(BrowserThread::UI); 441 DCHECK_CURRENTLY_ON(BrowserThread::UI);
468 // A single data send failure is treated as fatal to an active remoting 442 // A single data send failure is treated as fatal to an active remoting
469 // session. 443 // session.
470 if (active_bridge_) 444 if (active_bridge_)
471 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); 445 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
472 } 446 }
473
474 void CastRemotingConnector::OnRoutesUpdated(
475 const std::vector<media_router::MediaRoute>& routes,
476 const std::vector<media_router::MediaRoute::Id>& joinable_route_ids) {
477 DCHECK_CURRENTLY_ON(BrowserThread::UI);
478
479 // If a remoting route has already been identified, check that it still
480 // exists. Otherwise, shut down messaging and any active remoting, and notify
481 // the sources that remoting is no longer available.
482 if (message_observer_) {
483 for (const media_router::MediaRoute& route : routes) {
484 if (message_observer_->route_id() == route.media_route_id())
485 return; // Remoting route still exists. Take no further action.
486 }
487 message_observer_.reset();
488 if (active_bridge_)
489 StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED);
490 for (RemotingBridge* notifyee : bridges_)
491 notifyee->OnSinkGone();
492 }
493
494 // There shouldn't be an active RemotingBridge at this point, since there is
495 // currently no known remoting route.
496 DCHECK(!active_bridge_);
497
498 // Scan |routes| for a new remoting route. If one is found, begin processing
499 // messages on the route, and notify the sources that remoting is now
500 // available.
501 for (const media_router::MediaRoute& route : routes) {
502 if (route.media_source().id() != media_source_id_)
503 continue;
504 message_observer_.reset(new MessageObserver(
505 media_router::MediaRoutesObserver::router(), route.media_route_id(),
506 this));
507 // TODO(miu): In the future, scan the route ID for sink capabilities
508 // properties and pass these to the source in the OnSinkAvailable()
509 // notification.
510 for (RemotingBridge* notifyee : bridges_)
511 notifyee->OnSinkAvailable(enabled_features_);
512 break;
513 }
514 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698