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

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: Addressed imcheng's comments. Removed OnStarted/Failed interface. 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"
miu 2017/06/27 00:23:48 You can `git rm ` this file (.h and .cc and the fu
xjz 2017/06/28 02:09:38 Done. Removed the fuzz tests.
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));
miu 2017/06/27 00:23:48 What if IdForTab() returns -1? Should you not crea
xjz 2017/06/28 02:09:39 Done.
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_ != -1) {
miu 2017/06/27 00:23:48 Hmm...Can we prevent creating instances non-tabs?
xjz 2017/06/28 02:09:39 Done.
161 VLOG(3) << "Register CastRemotingConnector for tab_id = " << tab_id_;
miu 2017/06/27 00:23:48 nit: Suggest VLOG(2) for most of the VLOGs added t
xjz 2017/06/28 02:09:38 Done.
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_ != -1)
177 media_router_->UnregisterRemotingSource(tab_id_);
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 DCHECK_CURRENTLY_ON(BrowserThread::UI);
187 VLOG(3) << __func__;
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 DCHECK_CURRENTLY_ON(BrowserThread::UI);
199 VLOG(3) << __func__;
200
201 if (binding_.is_bound())
202 binding_.Close();
203 remoter_.reset();
204
205 for (RemotingBridge* notifyee : bridges_)
miu 2017/06/27 00:23:48 Before this loop, let's call CastRemotingConnector
xjz 2017/06/28 02:09:39 Done.
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) {
227 DCHECK_CURRENTLY_ON(BrowserThread::UI); 237 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 DCHECK(bridges_.find(bridge) != bridges_.end()); 238 DCHECK(bridges_.find(bridge) != bridges_.end());
239 VLOG(3) << __func__;
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();
252 266
253 // Send a start message to the Cast Provider. 267 // Assumes the remoting session is always started successfully. Once any
miu 2017/06/27 00:23:48 nit: s/Assumes/Assume/
xjz 2017/06/28 02:09:39 Done.
254 ++session_counter_; // New remoting session ID. 268 // failure occurs, OnError() will be called.
255 SendMessageToProvider(base::StringPrintf(
256 Messaging::kStartRemotingMessageFormat, session_counter_));
257
258 bridge->OnStarted(); 269 bridge->OnStarted();
259 } 270 }
260 271
261 void CastRemotingConnector::StartRemotingDataStreams( 272 void CastRemotingConnector::StartRemotingDataStreams(
262 RemotingBridge* bridge, 273 RemotingBridge* bridge,
263 mojo::ScopedDataPipeConsumerHandle audio_pipe, 274 mojo::ScopedDataPipeConsumerHandle audio_pipe,
264 mojo::ScopedDataPipeConsumerHandle video_pipe, 275 mojo::ScopedDataPipeConsumerHandle video_pipe,
265 media::mojom::RemotingDataStreamSenderRequest audio_sender_request, 276 media::mojom::RemotingDataStreamSenderRequest audio_sender_request,
266 media::mojom::RemotingDataStreamSenderRequest video_sender_request) { 277 media::mojom::RemotingDataStreamSenderRequest video_sender_request) {
267 DCHECK_CURRENTLY_ON(BrowserThread::UI); 278 DCHECK_CURRENTLY_ON(BrowserThread::UI);
279 VLOG(3) << __func__;
268 280
269 // Refuse to start if there is no remoting route available, or if remoting is 281 // Refuse to start if there is no remoting route available, or if remoting is
270 // not active for this |bridge|. 282 // not active for this |bridge|.
271 if (!message_observer_ || active_bridge_ != bridge) 283 if (!remoter_ || active_bridge_ != bridge)
272 return; 284 return;
273 // Also, if neither audio nor video pipe was provided, or if a request for a 285 // 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. 286 // RemotingDataStreamSender was not provided for a data pipe, error-out early.
275 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) || 287 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) ||
276 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) || 288 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) ||
277 (video_pipe.is_valid() && !video_sender_request.is_pending())) { 289 (video_pipe.is_valid() && !video_sender_request.is_pending())) {
278 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); 290 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
279 return; 291 return;
280 } 292 }
281 293
282 // Hold on to the data pipe handles and interface requests until one/both 294 // Hold on to the data pipe handles and interface requests until one/both
283 // CastRemotingSenders are created and ready for use. 295 // CastRemotingSenders are created and ready for use.
284 pending_audio_pipe_ = std::move(audio_pipe); 296 pending_audio_pipe_ = std::move(audio_pipe);
285 pending_video_pipe_ = std::move(video_pipe); 297 pending_video_pipe_ = std::move(video_pipe);
286 pending_audio_sender_request_ = std::move(audio_sender_request); 298 pending_audio_sender_request_ = std::move(audio_sender_request);
287 pending_video_sender_request_ = std::move(video_sender_request); 299 pending_video_sender_request_ = std::move(video_sender_request);
288 300
289 // Send a "start streams" message to the Cast Provider. The provider is 301 remoter_->StartDataStreams(pending_audio_sender_request_.is_pending(),
290 // responsible for creating and setting up a remoting Cast Streaming session 302 pending_video_sender_request_.is_pending());
miu 2017/06/27 00:23:48 See my comments in the mojom file (for the MirrorS
xjz 2017/06/28 02:09:38 Done.
291 // that will result in new CastRemotingSender instances being created here in 303 }
292 // the browser process. 304
293 SendMessageToProvider(base::StringPrintf( 305 void CastRemotingConnector::OnDataStreamsStarted(int32_t audio_stream_id,
294 Messaging::kStartStreamsMessageFormat, session_counter_, 306 int32_t video_stream_id) {
295 pending_audio_sender_request_.is_pending() ? 'Y' : 'N', 307 DCHECK_CURRENTLY_ON(BrowserThread::UI);
296 pending_video_sender_request_.is_pending() ? 'Y' : 'N')); 308 VLOG(3) << __func__ << ": audio_stream_id = " << audio_stream_id
309 << " video_stream_id = " << video_stream_id;
310
311 if (!active_bridge_) {
miu 2017/06/27 00:23:48 Since this is asynch, just before this check, we s
xjz 2017/06/28 02:09:39 Done with DCHECK. Whenever remoter_ is set to null
312 remoter_->Stop(media::mojom::RemotingStopReason::SOURCE_GONE);
313 return;
314 }
315
316 if (pending_audio_sender_request_.is_pending()) {
miu 2017/06/27 00:23:48 nit: "&& audio_stream_id > 0" ... and for video t
xjz 2017/06/28 02:09:39 Done.
317 cast::CastRemotingSender::FindAndBind(
318 audio_stream_id, std::move(pending_audio_pipe_),
319 std::move(pending_audio_sender_request_),
320 base::Bind(&CastRemotingConnector::OnDataSendFailed,
321 weak_factory_.GetWeakPtr()));
322 }
323 if (pending_video_sender_request_.is_pending()) {
324 cast::CastRemotingSender::FindAndBind(
325 video_stream_id, std::move(pending_video_pipe_),
326 std::move(pending_video_sender_request_),
327 base::Bind(&CastRemotingConnector::OnDataSendFailed,
328 weak_factory_.GetWeakPtr()));
329 }
297 } 330 }
298 331
299 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, 332 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge,
300 RemotingStopReason reason) { 333 RemotingStopReason reason) {
301 DCHECK_CURRENTLY_ON(BrowserThread::UI); 334 DCHECK_CURRENTLY_ON(BrowserThread::UI);
335 VLOG(3) << __func__ << ": reason = " << reason;
302 336
303 if (active_bridge_ != bridge) 337 if (active_bridge_ != bridge)
304 return; 338 return;
305 339
306 active_bridge_ = nullptr; 340 active_bridge_ = nullptr;
307 341
308 // Explicitly close the data pipes (and related requests) just in case the 342 // Explicitly close the data pipes (and related requests) just in case the
309 // "start streams" operation was interrupted. 343 // "start streams" operation was interrupted.
310 pending_audio_pipe_.reset(); 344 pending_audio_pipe_.reset();
311 pending_video_pipe_.reset(); 345 pending_video_pipe_.reset();
312 pending_audio_sender_request_ = nullptr; 346 pending_audio_sender_request_ = nullptr;
313 pending_video_sender_request_ = nullptr; 347 pending_video_sender_request_ = nullptr;
314 348
315 // Cancel all outstanding callbacks related to the remoting session. 349 // Cancel all outstanding callbacks related to the remoting session.
316 weak_factory_.InvalidateWeakPtrs(); 350 weak_factory_.InvalidateWeakPtrs();
317 351
318 // Prevent the source from trying to start again until the Cast Provider has 352 // Prevent the source from trying to start again until the Cast Provider has
319 // indicated the stop operation has completed. 353 // indicated the stop operation has completed.
320 bridge->OnSinkGone(); 354 bridge->OnSinkGone();
321 // Note: At this point, all sources should think the sink is gone. 355 // Note: At this point, all sources should think the sink is gone.
322 356
323 SendMessageToProvider(base::StringPrintf( 357 if (remoter_)
324 Messaging::kStopRemotingMessageFormat, session_counter_)); 358 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 359
328 bridge->OnStopped(reason); 360 bridge->OnStopped(reason);
329 } 361 }
330 362
363 void CastRemotingConnector::OnStopped(RemotingStopReason reason) {
364 DCHECK_CURRENTLY_ON(BrowserThread::UI);
365 VLOG(3) << __func__ << ": reason = " << reason;
366
367 if (!active_bridge_) {
368 // Notify all the sources that the sink is available again.
369 if (remoter_) {
370 // TODO(xjz): Pass the receiver's capabilities to sources.
371 for (RemotingBridge* notifyee : bridges_) {
372 notifyee->OnSinkAvailable(enabled_features_);
miu 2017/06/27 00:23:48 Instead of this, it seems we should require that M
xjz 2017/06/28 02:09:39 I think OnStopped() call already indicates that Mi
miu 2017/06/29 20:46:50 There is a significant period of time (1-3 seconds
xjz 2017/06/30 02:12:09 Done as discussed offline.
373 }
374 }
375 return;
376 }
377 StopRemoting(active_bridge_, reason);
378 }
379
331 void CastRemotingConnector::SendMessageToSink( 380 void CastRemotingConnector::SendMessageToSink(
332 RemotingBridge* bridge, const std::vector<uint8_t>& message) { 381 RemotingBridge* bridge, const std::vector<uint8_t>& message) {
333 DCHECK_CURRENTLY_ON(BrowserThread::UI); 382 DCHECK_CURRENTLY_ON(BrowserThread::UI);
334 383
335 // During an active remoting session, simply pass all binary messages through 384 // During an active remoting session, simply pass all binary messages through
336 // to the sink. 385 // to the sink.
337 if (!message_observer_ || active_bridge_ != bridge) 386 if (!remoter_ || active_bridge_ != bridge)
338 return; 387 return;
339 media_router::MediaRoutesObserver::router()->SendRouteBinaryMessage( 388 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 } 389 }
345 390
346 void CastRemotingConnector::SendMessageToProvider(const std::string& message) { 391 void CastRemotingConnector::OnMessageFromSink(
392 const std::vector<uint8_t>& message) {
347 DCHECK_CURRENTLY_ON(BrowserThread::UI); 393 DCHECK_CURRENTLY_ON(BrowserThread::UI);
348 394
349 if (!message_observer_) 395 // During an active remoting session, simply pass all binary messages through
396 // to the source.
397 if (!active_bridge_)
398 return;
399 active_bridge_->OnMessageFromSink(message);
400 }
401
402 void CastRemotingConnector::OnSinkAvailable(
403 media::mojom::RemotingSinkCapabilities capabilities) {
404 DCHECK_CURRENTLY_ON(BrowserThread::UI);
405 VLOG(3) << __func__ << ": capabilities = " << capabilities;
406
407 // The receiver's capabilities are supposed unchanged during an active
408 // remoting session.
409 if (active_bridge_)
miu 2017/06/27 00:23:48 I'm trying to think why OnSinkAvailable() would be
xjz 2017/06/28 02:09:39 Yes, I agree. As replied to the comment above, OnS
350 return; 410 return;
351 411
352 if (active_bridge_) { 412 // TODO(xjz): Pass the receiver's capabilities to the sources.
353 media_router::MediaRoutesObserver::router()->SendRouteMessage( 413 for (RemotingBridge* notifyee : bridges_)
354 message_observer_->route_id(), message, 414 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 } 415 }
366 416
367 void CastRemotingConnector::ProcessMessagesFromRoute( 417 void CastRemotingConnector::OnError() {
368 const std::vector<media_router::RouteMessage>& messages) {
369 DCHECK_CURRENTLY_ON(BrowserThread::UI); 418 DCHECK_CURRENTLY_ON(BrowserThread::UI);
419 VLOG(3) << __func__;
370 420
371 // Note: If any calls to message parsing functions are added/changed here, 421 if (active_bridge_)
372 // please update cast_remoting_connector_fuzzertest.cc as well! 422 StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE);
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 } 423 }
465 424
466 void CastRemotingConnector::OnDataSendFailed() { 425 void CastRemotingConnector::OnDataSendFailed() {
467 DCHECK_CURRENTLY_ON(BrowserThread::UI); 426 DCHECK_CURRENTLY_ON(BrowserThread::UI);
427 VLOG(3) << __func__;
428
468 // A single data send failure is treated as fatal to an active remoting 429 // A single data send failure is treated as fatal to an active remoting
469 // session. 430 // session.
470 if (active_bridge_) 431 if (active_bridge_)
471 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); 432 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED);
472 } 433 }
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