OLD | NEW |
---|---|
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 Loading... | |
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 } | |
OLD | NEW |