| 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) { |
| 119 const SessionID::id_type tab_id = SessionTabHelper::IdForTab(contents); |
| 120 if (tab_id == -1) |
| 121 return nullptr; |
| 143 connector = new CastRemotingConnector( | 122 connector = new CastRemotingConnector( |
| 144 media_router::MediaRouterFactory::GetApiForBrowserContext( | 123 media_router::MediaRouterFactory::GetApiForBrowserContext( |
| 145 contents->GetBrowserContext()), | 124 contents->GetBrowserContext()), |
| 146 media_router::MediaSourceForTabContentRemoting( | 125 tab_id); |
| 147 SessionTabHelper::IdForTab(contents)) | |
| 148 .id()); | |
| 149 contents->SetUserData(kUserDataKey, base::WrapUnique(connector)); | 126 contents->SetUserData(kUserDataKey, base::WrapUnique(connector)); |
| 150 } | 127 } |
| 151 return connector; | 128 return connector; |
| 152 } | 129 } |
| 153 | 130 |
| 154 // static | 131 // static |
| 155 void CastRemotingConnector::CreateMediaRemoter( | 132 void CastRemotingConnector::CreateMediaRemoter( |
| 156 content::RenderFrameHost* host, | 133 content::RenderFrameHost* host, |
| 157 media::mojom::RemotingSourcePtr source, | 134 media::mojom::RemotingSourcePtr source, |
| 158 media::mojom::RemoterRequest request) { | 135 media::mojom::RemoterRequest request) { |
| 159 DCHECK(host); | 136 DCHECK(host); |
| 160 auto* const contents = content::WebContents::FromRenderFrameHost(host); | 137 auto* const contents = content::WebContents::FromRenderFrameHost(host); |
| 161 if (!contents) | 138 if (!contents) |
| 162 return; | 139 return; |
| 163 CastRemotingConnector::Get(contents)->CreateBridge(std::move(source), | 140 CastRemotingConnector* const connector = CastRemotingConnector::Get(contents); |
| 164 std::move(request)); | 141 if (!connector) |
| 142 return; |
| 143 connector->CreateBridge(std::move(source), std::move(request)); |
| 165 } | 144 } |
| 166 | 145 |
| 167 namespace { | 146 namespace { |
| 168 RemotingSinkCapabilities GetFeatureEnabledCapabilities() { | 147 RemotingSinkCapabilities GetFeatureEnabledCapabilities() { |
| 169 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 148 #if !defined(OS_ANDROID) && !defined(OS_IOS) |
| 170 if (base::FeatureList::IsEnabled(features::kMediaRemoting)) { | 149 if (base::FeatureList::IsEnabled(features::kMediaRemoting)) { |
| 171 return RemotingSinkCapabilities::RENDERING_ONLY; | 150 return RemotingSinkCapabilities::RENDERING_ONLY; |
| 172 } | 151 } |
| 173 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) | 152 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) |
| 174 return RemotingSinkCapabilities::NONE; | 153 return RemotingSinkCapabilities::NONE; |
| 175 } | 154 } |
| 176 } // namespace | 155 } // namespace |
| 177 | 156 |
| 178 CastRemotingConnector::CastRemotingConnector( | 157 CastRemotingConnector::CastRemotingConnector(media_router::MediaRouter* router, |
| 179 media_router::MediaRouter* router, | 158 int32_t tab_id) |
| 180 const media_router::MediaSource::Id& media_source_id) | 159 : media_router_(router), |
| 181 : media_router::MediaRoutesObserver(router), | 160 tab_id_(tab_id), |
| 182 media_source_id_(media_source_id), | |
| 183 enabled_features_(GetFeatureEnabledCapabilities()), | 161 enabled_features_(GetFeatureEnabledCapabilities()), |
| 184 session_counter_(0), | |
| 185 active_bridge_(nullptr), | 162 active_bridge_(nullptr), |
| 186 weak_factory_(this) {} | 163 binding_(this), |
| 164 weak_factory_(this) { |
| 165 VLOG(2) << "Register CastRemotingConnector for tab_id = " << tab_id_; |
| 166 media_router_->RegisterRemotingSource(tab_id_, this); |
| 167 } |
| 187 | 168 |
| 188 CastRemotingConnector::~CastRemotingConnector() { | 169 CastRemotingConnector::~CastRemotingConnector() { |
| 189 // Assume nothing about destruction/shutdown sequence of a tab. For example, | 170 // Assume nothing about destruction/shutdown sequence of a tab. For example, |
| 190 // it's possible the owning WebContents will be destroyed before the Mojo | 171 // it's possible the owning WebContents will be destroyed before the Mojo |
| 191 // message pipes to the RemotingBridges have been closed. | 172 // message pipes to the RemotingBridges have been closed. |
| 192 if (active_bridge_) | 173 if (active_bridge_) |
| 193 StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED); | 174 StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED); |
| 194 for (RemotingBridge* notifyee : bridges_) { | 175 for (RemotingBridge* notifyee : bridges_) { |
| 195 notifyee->OnSinkGone(); | 176 notifyee->OnSinkGone(); |
| 196 notifyee->OnCastRemotingConnectorDestroyed(); | 177 notifyee->OnCastRemotingConnectorDestroyed(); |
| 197 } | 178 } |
| 179 media_router_->UnregisterRemotingSource(tab_id_); |
| 180 } |
| 181 |
| 182 void CastRemotingConnector::ConnectToService( |
| 183 media::mojom::MirrorServiceRemotingSourceRequest source_request, |
| 184 media::mojom::MirrorServiceRemoterPtr remoter) { |
| 185 DCHECK(!binding_.is_bound()); |
| 186 DCHECK(!remoter_); |
| 187 DCHECK(remoter); |
| 188 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 189 VLOG(2) << __func__; |
| 190 |
| 191 binding_.Bind(std::move(source_request)); |
| 192 binding_.set_connection_error_handler(base::Bind( |
| 193 &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this))); |
| 194 remoter_ = std::move(remoter); |
| 195 remoter_.set_connection_error_handler(base::Bind( |
| 196 &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this))); |
| 197 } |
| 198 |
| 199 void CastRemotingConnector::OnMirrorServiceStopped() { |
| 200 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 201 VLOG(2) << __func__; |
| 202 |
| 203 if (binding_.is_bound()) |
| 204 binding_.Close(); |
| 205 remoter_.reset(); |
| 206 |
| 207 if (active_bridge_) |
| 208 StopRemoting(active_bridge_, RemotingStopReason::SERVICE_GONE); |
| 209 for (RemotingBridge* notifyee : bridges_) |
| 210 notifyee->OnSinkGone(); |
| 198 } | 211 } |
| 199 | 212 |
| 200 void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source, | 213 void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source, |
| 201 media::mojom::RemoterRequest request) { | 214 media::mojom::RemoterRequest request) { |
| 202 mojo::MakeStrongBinding( | 215 mojo::MakeStrongBinding( |
| 203 base::MakeUnique<RemotingBridge>(std::move(source), this), | 216 base::MakeUnique<RemotingBridge>(std::move(source), this), |
| 204 std::move(request)); | 217 std::move(request)); |
| 205 } | 218 } |
| 206 | 219 |
| 207 void CastRemotingConnector::RegisterBridge(RemotingBridge* bridge) { | 220 void CastRemotingConnector::RegisterBridge(RemotingBridge* bridge) { |
| 208 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 221 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 209 DCHECK(bridges_.find(bridge) == bridges_.end()); | 222 DCHECK(bridges_.find(bridge) == bridges_.end()); |
| 210 | 223 |
| 211 bridges_.insert(bridge); | 224 bridges_.insert(bridge); |
| 212 if (message_observer_ && !active_bridge_) | 225 // TODO(xjz): Pass the receiver's capabilities to the source. |
| 226 if (remoter_ && !active_bridge_) |
| 213 bridge->OnSinkAvailable(enabled_features_); | 227 bridge->OnSinkAvailable(enabled_features_); |
| 214 } | 228 } |
| 215 | 229 |
| 216 void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge, | 230 void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge, |
| 217 RemotingStopReason reason) { | 231 RemotingStopReason reason) { |
| 218 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 232 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 219 DCHECK(bridges_.find(bridge) != bridges_.end()); | 233 DCHECK(bridges_.find(bridge) != bridges_.end()); |
| 220 | 234 |
| 221 if (bridge == active_bridge_) | 235 if (bridge == active_bridge_) |
| 222 StopRemoting(bridge, reason); | 236 StopRemoting(bridge, reason); |
| 223 bridges_.erase(bridge); | 237 bridges_.erase(bridge); |
| 224 } | 238 } |
| 225 | 239 |
| 226 void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { | 240 void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { |
| 227 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 241 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 228 DCHECK(bridges_.find(bridge) != bridges_.end()); | 242 DCHECK(bridges_.find(bridge) != bridges_.end()); |
| 243 VLOG(2) << __func__; |
| 229 | 244 |
| 230 // Refuse to start if there is no remoting route available, or if remoting is | 245 // Refuse to start if there is no remoting route available, or if remoting is |
| 231 // already active. | 246 // already active. |
| 232 if (!message_observer_) { | 247 if (!remoter_) { |
| 233 bridge->OnStartFailed(RemotingStartFailReason::ROUTE_TERMINATED); | 248 VLOG(2) << "Remoting start failed: No mirror service connected."; |
| 249 bridge->OnStartFailed(RemotingStartFailReason::SERVICE_NOT_CONNECTED); |
| 234 return; | 250 return; |
| 235 } | 251 } |
| 236 if (active_bridge_) { | 252 if (active_bridge_) { |
| 253 VLOG(2) << "Remoting start failed: Cannot start multiple."; |
| 237 bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE); | 254 bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE); |
| 238 return; | 255 return; |
| 239 } | 256 } |
| 240 | 257 |
| 241 // Notify all other sources that the sink is no longer available for remoting. | 258 // 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 | 259 // 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 | 260 // start remoting before receiving this notification; but that attempt will |
| 244 // just fail later on. | 261 // just fail later on. |
| 245 for (RemotingBridge* notifyee : bridges_) { | 262 for (RemotingBridge* notifyee : bridges_) { |
| 246 if (notifyee == bridge) | 263 if (notifyee == bridge) |
| 247 continue; | 264 continue; |
| 248 notifyee->OnSinkGone(); | 265 notifyee->OnSinkGone(); |
| 249 } | 266 } |
| 250 | 267 |
| 251 active_bridge_ = bridge; | 268 active_bridge_ = bridge; |
| 269 remoter_->Start(); |
| 252 | 270 |
| 253 // Send a start message to the Cast Provider. | 271 // Assume the remoting session is always started successfully. If any failure |
| 254 ++session_counter_; // New remoting session ID. | 272 // occurs, OnError() will be called. |
| 255 SendMessageToProvider(base::StringPrintf( | |
| 256 Messaging::kStartRemotingMessageFormat, session_counter_)); | |
| 257 | |
| 258 bridge->OnStarted(); | 273 bridge->OnStarted(); |
| 259 } | 274 } |
| 260 | 275 |
| 261 void CastRemotingConnector::StartRemotingDataStreams( | 276 void CastRemotingConnector::StartRemotingDataStreams( |
| 262 RemotingBridge* bridge, | 277 RemotingBridge* bridge, |
| 263 mojo::ScopedDataPipeConsumerHandle audio_pipe, | 278 mojo::ScopedDataPipeConsumerHandle audio_pipe, |
| 264 mojo::ScopedDataPipeConsumerHandle video_pipe, | 279 mojo::ScopedDataPipeConsumerHandle video_pipe, |
| 265 media::mojom::RemotingDataStreamSenderRequest audio_sender_request, | 280 media::mojom::RemotingDataStreamSenderRequest audio_sender_request, |
| 266 media::mojom::RemotingDataStreamSenderRequest video_sender_request) { | 281 media::mojom::RemotingDataStreamSenderRequest video_sender_request) { |
| 267 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 282 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 283 VLOG(2) << __func__; |
| 268 | 284 |
| 269 // Refuse to start if there is no remoting route available, or if remoting is | 285 // Refuse to start if there is no remoting route available, or if remoting is |
| 270 // not active for this |bridge|. | 286 // not active for this |bridge|. |
| 271 if (!message_observer_ || active_bridge_ != bridge) | 287 if (!remoter_ || active_bridge_ != bridge) |
| 272 return; | 288 return; |
| 273 // Also, if neither audio nor video pipe was provided, or if a request for a | 289 // 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. | 290 // RemotingDataStreamSender was not provided for a data pipe, error-out early. |
| 275 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) || | 291 if ((!audio_pipe.is_valid() && !video_pipe.is_valid()) || |
| 276 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) || | 292 (audio_pipe.is_valid() && !audio_sender_request.is_pending()) || |
| 277 (video_pipe.is_valid() && !video_sender_request.is_pending())) { | 293 (video_pipe.is_valid() && !video_sender_request.is_pending())) { |
| 278 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); | 294 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); |
| 279 return; | 295 return; |
| 280 } | 296 } |
| 281 | 297 |
| 282 // Hold on to the data pipe handles and interface requests until one/both | 298 const bool want_audio = audio_sender_request.is_pending(); |
| 283 // CastRemotingSenders are created and ready for use. | 299 const bool want_video = video_sender_request.is_pending(); |
| 284 pending_audio_pipe_ = std::move(audio_pipe); | 300 remoter_->StartDataStreams( |
| 285 pending_video_pipe_ = std::move(video_pipe); | 301 want_audio, want_video, |
| 286 pending_audio_sender_request_ = std::move(audio_sender_request); | 302 base::BindOnce(&CastRemotingConnector::OnDataStreamsStarted, |
| 287 pending_video_sender_request_ = std::move(video_sender_request); | 303 weak_factory_.GetWeakPtr(), std::move(audio_pipe), |
| 304 std::move(video_pipe), std::move(audio_sender_request), |
| 305 std::move(video_sender_request))); |
| 306 } |
| 288 | 307 |
| 289 // Send a "start streams" message to the Cast Provider. The provider is | 308 void CastRemotingConnector::OnDataStreamsStarted( |
| 290 // responsible for creating and setting up a remoting Cast Streaming session | 309 mojo::ScopedDataPipeConsumerHandle audio_pipe, |
| 291 // that will result in new CastRemotingSender instances being created here in | 310 mojo::ScopedDataPipeConsumerHandle video_pipe, |
| 292 // the browser process. | 311 media::mojom::RemotingDataStreamSenderRequest audio_sender_request, |
| 293 SendMessageToProvider(base::StringPrintf( | 312 media::mojom::RemotingDataStreamSenderRequest video_sender_request, |
| 294 Messaging::kStartStreamsMessageFormat, session_counter_, | 313 int32_t audio_stream_id, |
| 295 pending_audio_sender_request_.is_pending() ? 'Y' : 'N', | 314 int32_t video_stream_id) { |
| 296 pending_video_sender_request_.is_pending() ? 'Y' : 'N')); | 315 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 316 DCHECK(remoter_); |
| 317 VLOG(2) << __func__ << ": audio_stream_id = " << audio_stream_id |
| 318 << " video_stream_id = " << video_stream_id; |
| 319 |
| 320 if (!active_bridge_) { |
| 321 remoter_->Stop(media::mojom::RemotingStopReason::SOURCE_GONE); |
| 322 return; |
| 323 } |
| 324 |
| 325 if (audio_sender_request.is_pending() && audio_stream_id > -1) { |
| 326 cast::CastRemotingSender::FindAndBind( |
| 327 audio_stream_id, std::move(audio_pipe), std::move(audio_sender_request), |
| 328 base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| 329 weak_factory_.GetWeakPtr())); |
| 330 } |
| 331 if (video_sender_request.is_pending() && video_stream_id > -1) { |
| 332 cast::CastRemotingSender::FindAndBind( |
| 333 video_stream_id, std::move(video_pipe), std::move(video_sender_request), |
| 334 base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| 335 weak_factory_.GetWeakPtr())); |
| 336 } |
| 297 } | 337 } |
| 298 | 338 |
| 299 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, | 339 void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, |
| 300 RemotingStopReason reason) { | 340 RemotingStopReason reason) { |
| 301 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 341 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 342 VLOG(2) << __func__ << ": reason = " << reason; |
| 302 | 343 |
| 303 if (active_bridge_ != bridge) | 344 if (active_bridge_ != bridge) |
| 304 return; | 345 return; |
| 305 | 346 |
| 306 active_bridge_ = nullptr; | 347 active_bridge_ = nullptr; |
| 307 | 348 |
| 308 // Explicitly close the data pipes (and related requests) just in case the | |
| 309 // "start streams" operation was interrupted. | |
| 310 pending_audio_pipe_.reset(); | |
| 311 pending_video_pipe_.reset(); | |
| 312 pending_audio_sender_request_ = nullptr; | |
| 313 pending_video_sender_request_ = nullptr; | |
| 314 | |
| 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(2) << __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_); |
| 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_) |
| 350 return; | 398 return; |
| 351 | 399 active_bridge_->OnMessageFromSink(message); |
| 352 if (active_bridge_) { | |
| 353 media_router::MediaRoutesObserver::router()->SendRouteMessage( | |
| 354 message_observer_->route_id(), message, | |
| 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 } | 400 } |
| 366 | 401 |
| 367 void CastRemotingConnector::ProcessMessagesFromRoute( | 402 void CastRemotingConnector::OnSinkAvailable( |
| 368 const std::vector<media_router::RouteMessage>& messages) { | 403 const std::vector<media::mojom::RemotingSinkCapabilities>& capabilities) { |
| 369 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 404 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 405 VLOG(2) << __func__; |
| 370 | 406 |
| 371 // Note: If any calls to message parsing functions are added/changed here, | 407 // The receiver's capabilities are supposed unchanged during an active |
| 372 // please update cast_remoting_connector_fuzzertest.cc as well! | 408 // remoting session. |
| 409 if (active_bridge_) { |
| 410 LOG(WARNING) << "Unexpected OnSinkAvailable() call during an active" |
| 411 << "remoting session."; |
| 412 return; |
| 413 } |
| 373 | 414 |
| 374 for (const media_router::RouteMessage& message : messages) { | 415 // TODO(xjz): Pass the receiver's capabilities to the sources. |
| 375 switch (message.type) { | 416 for (RemotingBridge* notifyee : bridges_) |
| 376 case media_router::RouteMessage::TEXT: | 417 notifyee->OnSinkAvailable(enabled_features_); |
| 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 } | 418 } |
| 457 | 419 |
| 458 void CastRemotingConnector::HandleSendMessageResult(bool success) { | 420 void CastRemotingConnector::OnError() { |
| 459 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 421 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 460 // A single message send failure is treated as fatal to an active remoting | 422 VLOG(2) << __func__; |
| 461 // session. | 423 |
| 462 if (!success && active_bridge_) | 424 if (active_bridge_) |
| 463 StopRemoting(active_bridge_, RemotingStopReason::MESSAGE_SEND_FAILED); | 425 StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE); |
| 464 } | 426 } |
| 465 | 427 |
| 466 void CastRemotingConnector::OnDataSendFailed() { | 428 void CastRemotingConnector::OnDataSendFailed() { |
| 467 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 429 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 430 VLOG(2) << __func__; |
| 431 |
| 468 // A single data send failure is treated as fatal to an active remoting | 432 // A single data send failure is treated as fatal to an active remoting |
| 469 // session. | 433 // session. |
| 470 if (active_bridge_) | 434 if (active_bridge_) |
| 471 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); | 435 StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); |
| 472 } | 436 } |
| 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 |