Chromium Code Reviews| Index: chrome/browser/media/cast_remoting_connector.cc |
| diff --git a/chrome/browser/media/cast_remoting_connector.cc b/chrome/browser/media/cast_remoting_connector.cc |
| index 6b52d3f22a15f3051a635d7f5b322e686f0aea22..c83c905dfa3ce380c39a632fb795ed22800acbb4 100644 |
| --- a/chrome/browser/media/cast_remoting_connector.cc |
| +++ b/chrome/browser/media/cast_remoting_connector.cc |
| @@ -10,15 +10,11 @@ |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/strings/stringprintf.h" |
| -#include "chrome/browser/media/cast_remoting_connector_messaging.h" |
| #include "chrome/browser/media/cast_remoting_sender.h" |
| #include "chrome/browser/media/router/media_router.h" |
| #include "chrome/browser/media/router/media_router_factory.h" |
| -#include "chrome/browser/media/router/route_message_observer.h" |
| #include "chrome/browser/sessions/session_tab_helper.h" |
| #include "chrome/common/chrome_features.h" |
| -#include "chrome/common/media_router/media_source_helper.h" |
| -#include "chrome/common/media_router/route_message.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| @@ -30,8 +26,6 @@ using media::mojom::RemotingSinkCapabilities; |
| using media::mojom::RemotingStartFailReason; |
| using media::mojom::RemotingStopReason; |
| -using Messaging = CastRemotingConnectorMessaging; |
| - |
| class CastRemotingConnector::RemotingBridge : public media::mojom::Remoter { |
| public: |
| // Constructs a "bridge" to delegate calls between the given |source| and |
| @@ -112,24 +106,6 @@ class CastRemotingConnector::RemotingBridge : public media::mojom::Remoter { |
| DISALLOW_COPY_AND_ASSIGN(RemotingBridge); |
| }; |
| -class CastRemotingConnector::MessageObserver |
| - : public media_router::RouteMessageObserver { |
| - public: |
| - MessageObserver(media_router::MediaRouter* router, |
| - const media_router::MediaRoute::Id& route_id, |
| - CastRemotingConnector* connector) |
| - : RouteMessageObserver(router, route_id), connector_(connector) {} |
| - ~MessageObserver() final {} |
| - |
| - private: |
| - void OnMessagesReceived( |
| - const std::vector<media_router::RouteMessage>& messages) final { |
| - connector_->ProcessMessagesFromRoute(messages); |
| - } |
| - |
| - CastRemotingConnector* const connector_; |
| -}; |
| - |
| // static |
| const void* const CastRemotingConnector::kUserDataKey = &kUserDataKey; |
| @@ -143,9 +119,7 @@ CastRemotingConnector* CastRemotingConnector::Get( |
| connector = new CastRemotingConnector( |
| media_router::MediaRouterFactory::GetApiForBrowserContext( |
| contents->GetBrowserContext()), |
| - media_router::MediaSourceForTabContentRemoting( |
| - SessionTabHelper::IdForTab(contents)) |
| - .id()); |
| + SessionTabHelper::IdForTab(contents)); |
| contents->SetUserData(kUserDataKey, base::WrapUnique(connector)); |
| } |
| return connector; |
| @@ -175,15 +149,19 @@ RemotingSinkCapabilities GetFeatureEnabledCapabilities() { |
| } |
| } // namespace |
| -CastRemotingConnector::CastRemotingConnector( |
| - media_router::MediaRouter* router, |
| - const media_router::MediaSource::Id& media_source_id) |
| - : media_router::MediaRoutesObserver(router), |
| - media_source_id_(media_source_id), |
| +CastRemotingConnector::CastRemotingConnector(media_router::MediaRouter* router, |
| + int32_t tab_id) |
| + : media_router_(router), |
| + tab_id_(tab_id), |
| enabled_features_(GetFeatureEnabledCapabilities()), |
| - session_counter_(0), |
| active_bridge_(nullptr), |
| - weak_factory_(this) {} |
| + binding_(this), |
| + weak_factory_(this) { |
| + 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
|
| + VLOG(3) << "Register CastRemotingConnector for tab_id = " << tab_id_; |
| + media_router_->RegisterRemotingSource(tab_id_, this); |
| + } |
| +} |
| CastRemotingConnector::~CastRemotingConnector() { |
| // Assume nothing about destruction/shutdown sequence of a tab. For example, |
| @@ -195,6 +173,37 @@ CastRemotingConnector::~CastRemotingConnector() { |
| notifyee->OnSinkGone(); |
| notifyee->OnCastRemotingConnectorDestroyed(); |
| } |
| + if (tab_id_ > 0) |
| + media_router_->UnRegisterRemotingSource(tab_id_, this); |
| +} |
| + |
| +void CastRemotingConnector::ConnectToService( |
| + media::mojom::MirrorServiceRemotingSourceRequest source_request, |
| + media::mojom::MirrorServiceRemoterPtr remoter) { |
| + DCHECK(!binding_.is_bound()); |
| + DCHECK(!remoter_); |
| + DCHECK(remoter); |
| + 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.
|
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + binding_.Bind(std::move(source_request)); |
| + binding_.set_connection_error_handler(base::Bind( |
| + &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this))); |
| + remoter_ = std::move(remoter); |
| + remoter_.set_connection_error_handler(base::Bind( |
| + &CastRemotingConnector::OnMirrorServiceStopped, base::Unretained(this))); |
| +} |
| + |
| +void CastRemotingConnector::OnMirrorServiceStopped() { |
| + VLOG(3) << __func__; |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + if (binding_.is_bound()) |
| + binding_.Close(); |
| + remoter_.reset(); |
| + |
| + for (RemotingBridge* notifyee : bridges_) |
| + notifyee->OnSinkGone(); |
| } |
| void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source, |
| @@ -209,7 +218,8 @@ void CastRemotingConnector::RegisterBridge(RemotingBridge* bridge) { |
| DCHECK(bridges_.find(bridge) == bridges_.end()); |
| bridges_.insert(bridge); |
| - if (message_observer_ && !active_bridge_) |
| + // TODO(xjz): Pass the receiver's capabilities to the source. |
| + if (remoter_ && !active_bridge_) |
| bridge->OnSinkAvailable(enabled_features_); |
| } |
| @@ -224,16 +234,19 @@ void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge, |
| } |
| void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { |
| + VLOG(3) << __func__; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| DCHECK(bridges_.find(bridge) != bridges_.end()); |
| // Refuse to start if there is no remoting route available, or if remoting is |
| // already active. |
| - if (!message_observer_) { |
| - bridge->OnStartFailed(RemotingStartFailReason::ROUTE_TERMINATED); |
| + if (!remoter_) { |
| + VLOG(3) << "Remoting start failed: No mirror service connected."; |
| + bridge->OnStartFailed(RemotingStartFailReason::SERVICE_NOT_CONNECTED); |
| return; |
| } |
| if (active_bridge_) { |
| + VLOG(3) << "Remoting start failed: Cannot start multiple."; |
| bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE); |
| return; |
| } |
| @@ -249,13 +262,29 @@ void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { |
| } |
| active_bridge_ = bridge; |
| + remoter_->Start(); |
| +} |
| - // Send a start message to the Cast Provider. |
| - ++session_counter_; // New remoting session ID. |
| - SendMessageToProvider(base::StringPrintf( |
| - Messaging::kStartRemotingMessageFormat, session_counter_)); |
| +void CastRemotingConnector::OnStarted() { |
| + VLOG(3) << __func__; |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - bridge->OnStarted(); |
| + if (!active_bridge_) { |
| + remoter_->Stop(media::mojom::RemotingStopReason::SOURCE_GONE); |
| + return; |
| + } |
| + active_bridge_->OnStarted(); |
| +} |
| + |
| +void CastRemotingConnector::OnStartFailed( |
| + media::mojom::RemotingStartFailReason reason) { |
| + VLOG(3) << __func__ << ": reason = " << reason; |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + if (!active_bridge_) |
| + return; |
| + active_bridge_->OnStartFailed(reason); |
| + active_bridge_ = nullptr; |
| } |
| void CastRemotingConnector::StartRemotingDataStreams( |
| @@ -264,11 +293,12 @@ void CastRemotingConnector::StartRemotingDataStreams( |
| mojo::ScopedDataPipeConsumerHandle video_pipe, |
| media::mojom::RemotingDataStreamSenderRequest audio_sender_request, |
| media::mojom::RemotingDataStreamSenderRequest video_sender_request) { |
| + VLOG(3) << __func__; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| // Refuse to start if there is no remoting route available, or if remoting is |
| // not active for this |bridge|. |
| - if (!message_observer_ || active_bridge_ != bridge) |
| + if (!remoter_ || active_bridge_ != bridge) |
| return; |
| // Also, if neither audio nor video pipe was provided, or if a request for a |
| // RemotingDataStreamSender was not provided for a data pipe, error-out early. |
| @@ -286,18 +316,38 @@ void CastRemotingConnector::StartRemotingDataStreams( |
| pending_audio_sender_request_ = std::move(audio_sender_request); |
| pending_video_sender_request_ = std::move(video_sender_request); |
| - // Send a "start streams" message to the Cast Provider. The provider is |
| - // responsible for creating and setting up a remoting Cast Streaming session |
| - // that will result in new CastRemotingSender instances being created here in |
| - // the browser process. |
| - SendMessageToProvider(base::StringPrintf( |
| - Messaging::kStartStreamsMessageFormat, session_counter_, |
| - pending_audio_sender_request_.is_pending() ? 'Y' : 'N', |
| - pending_video_sender_request_.is_pending() ? 'Y' : 'N')); |
| + remoter_->StartDataStreams(pending_audio_sender_request_.is_pending(), |
| + pending_video_sender_request_.is_pending()); |
| +} |
| + |
| +void CastRemotingConnector::OnDataStreamsStarted(int32_t audio_stream_id, |
| + int32_t video_stream_id) { |
| + VLOG(3) << __func__ << ": audio_stream_id = " << audio_stream_id |
| + << " video_stream_id = " << video_stream_id; |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + |
| + if (!active_bridge_) |
| + return; |
| + |
| + if (pending_audio_sender_request_.is_pending()) { |
| + cast::CastRemotingSender::FindAndBind( |
| + audio_stream_id, std::move(pending_audio_pipe_), |
| + std::move(pending_audio_sender_request_), |
| + base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| + weak_factory_.GetWeakPtr())); |
| + } |
| + if (pending_video_sender_request_.is_pending()) { |
| + cast::CastRemotingSender::FindAndBind( |
| + video_stream_id, std::move(pending_video_pipe_), |
| + std::move(pending_video_sender_request_), |
| + base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| + weak_factory_.GetWeakPtr())); |
| + } |
| } |
| void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, |
| RemotingStopReason reason) { |
| + VLOG(3) << __func__ << ": reason = " << reason; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (active_bridge_ != bridge) |
| @@ -320,195 +370,77 @@ void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, |
| bridge->OnSinkGone(); |
| // Note: At this point, all sources should think the sink is gone. |
| - SendMessageToProvider(base::StringPrintf( |
| - Messaging::kStopRemotingMessageFormat, session_counter_)); |
| - // Note: Once the Cast Provider sends back an acknowledgement message, all |
| - // sources will be notified that the remoting sink is available again. |
| + if (remoter_) |
| + remoter_->Stop(reason); |
| bridge->OnStopped(reason); |
| } |
| +void CastRemotingConnector::OnStopped(RemotingStopReason reason) { |
| + VLOG(3) << __func__ << ": reason = " << reason; |
| + DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| + if (!active_bridge_) { |
| + // Notify all the sources that the sink is available again. |
| + if (remoter_) { |
| + // TODO(xjz): Pass the receiver's capabilities to sources. |
| + for (RemotingBridge* notifyee : bridges_) { |
| + 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
|
| + } |
| + } |
| + return; |
| + } |
| + StopRemoting(active_bridge_, reason); |
| +} |
| + |
| void CastRemotingConnector::SendMessageToSink( |
| RemotingBridge* bridge, const std::vector<uint8_t>& message) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| // During an active remoting session, simply pass all binary messages through |
| // to the sink. |
| - if (!message_observer_ || active_bridge_ != bridge) |
| + if (!remoter_ || active_bridge_ != bridge) |
| return; |
| - media_router::MediaRoutesObserver::router()->SendRouteBinaryMessage( |
| - message_observer_->route_id(), |
| - base::MakeUnique<std::vector<uint8_t>>(message), |
| - base::Bind(&CastRemotingConnector::HandleSendMessageResult, |
| - weak_factory_.GetWeakPtr())); |
| + remoter_->SendMessageToSink(message); |
| } |
| -void CastRemotingConnector::SendMessageToProvider(const std::string& message) { |
| +void CastRemotingConnector::OnMessageFromSink( |
| + const std::vector<uint8_t>& message) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - if (!message_observer_) |
| + // During an active remoting session, simply pass all binary messages through |
| + // to the source. |
| + if (!active_bridge_) |
| return; |
| - |
| - if (active_bridge_) { |
| - media_router::MediaRoutesObserver::router()->SendRouteMessage( |
| - message_observer_->route_id(), message, |
| - base::Bind(&CastRemotingConnector::HandleSendMessageResult, |
| - weak_factory_.GetWeakPtr())); |
| - } else { |
| - struct Helper { |
| - static void IgnoreSendMessageResult(bool ignored) {} |
| - }; |
| - media_router::MediaRoutesObserver::router()->SendRouteMessage( |
| - message_observer_->route_id(), message, |
| - base::Bind(&Helper::IgnoreSendMessageResult)); |
| - } |
| + active_bridge_->OnMessageFromSink(message); |
| } |
| -void CastRemotingConnector::ProcessMessagesFromRoute( |
| - const std::vector<media_router::RouteMessage>& messages) { |
| +void CastRemotingConnector::OnSinkAvailable( |
| + media::mojom::RemotingSinkCapabilities capabilities) { |
| + VLOG(3) << __func__ << ": capabilities = " << capabilities; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - // Note: If any calls to message parsing functions are added/changed here, |
| - // please update cast_remoting_connector_fuzzertest.cc as well! |
| - |
| - for (const media_router::RouteMessage& message : messages) { |
| - switch (message.type) { |
| - case media_router::RouteMessage::TEXT: |
| - // This is a notification message from the Cast Provider, about the |
| - // execution state of the media remoting session between Chrome and the |
| - // remote device. |
| - DCHECK(message.text); |
| - |
| - // If this is a "start streams" acknowledgement message, the |
| - // CastRemotingSenders should now be available to begin consuming from |
| - // the data pipes. |
| - if (active_bridge_ && |
| - Messaging::IsMessageForSession( |
| - *message.text, |
| - Messaging::kStartedStreamsMessageFormatPartial, |
| - session_counter_)) { |
| - if (pending_audio_sender_request_.is_pending()) { |
| - cast::CastRemotingSender::FindAndBind( |
| - Messaging::GetStreamIdFromStartedMessage( |
| - *message.text, |
| - Messaging::kStartedStreamsMessageAudioIdSpecifier), |
| - std::move(pending_audio_pipe_), |
| - std::move(pending_audio_sender_request_), |
| - base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| - weak_factory_.GetWeakPtr())); |
| - } |
| - if (pending_video_sender_request_.is_pending()) { |
| - cast::CastRemotingSender::FindAndBind( |
| - Messaging::GetStreamIdFromStartedMessage( |
| - *message.text, |
| - Messaging::kStartedStreamsMessageVideoIdSpecifier), |
| - std::move(pending_video_pipe_), |
| - std::move(pending_video_sender_request_), |
| - base::Bind(&CastRemotingConnector::OnDataSendFailed, |
| - weak_factory_.GetWeakPtr())); |
| - } |
| - break; |
| - } |
| - |
| - // If this is a failure message, call StopRemoting(). |
| - if (active_bridge_ && |
| - Messaging::IsMessageForSession(*message.text, |
| - Messaging::kFailedMessageFormat, |
| - session_counter_)) { |
| - StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE); |
| - break; |
| - } |
| - |
| - // If this is a stop acknowledgement message, indicating that the last |
| - // session was stopped, notify all sources that the sink is once again |
| - // available. |
| - if (Messaging::IsMessageForSession(*message.text, |
| - Messaging::kStoppedMessageFormat, |
| - session_counter_)) { |
| - if (active_bridge_) { |
| - // Hmm...The Cast Provider was in a state that disagrees with this |
| - // connector. Attempt to resolve this by shutting everything down to |
| - // effectively reset to a known state. |
| - LOG(WARNING) << "BUG: Cast Provider sent 'stopped' message during " |
| - "an active remoting session."; |
| - StopRemoting(active_bridge_, |
| - RemotingStopReason::UNEXPECTED_FAILURE); |
| - } |
| - for (RemotingBridge* notifyee : bridges_) |
| - notifyee->OnSinkAvailable(enabled_features_); |
| - break; |
| - } |
| - |
| - LOG(WARNING) << "BUG: Unexpected message from Cast Provider: " |
| - << *message.text; |
| - break; |
| - |
| - case media_router::RouteMessage::BINARY: // This is for the source. |
| - DCHECK(message.binary); |
| - |
| - // All binary messages are passed through to the source during an active |
| - // remoting session. |
| - if (active_bridge_) |
| - active_bridge_->OnMessageFromSink(*message.binary); |
| - break; |
| - } |
| - } |
| + // The receiver's capabilities are supposed unchanged during an active |
| + // remoting session. |
| + if (active_bridge_) |
| + return; |
| + |
| + // TODO(xjz): Pass the receiver's capabilities to the sources. |
| + for (RemotingBridge* notifyee : bridges_) |
| + notifyee->OnSinkAvailable(enabled_features_); |
| } |
| -void CastRemotingConnector::HandleSendMessageResult(bool success) { |
| +void CastRemotingConnector::OnError() { |
| + VLOG(3) << __func__; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - // A single message send failure is treated as fatal to an active remoting |
| - // session. |
| - if (!success && active_bridge_) |
| - StopRemoting(active_bridge_, RemotingStopReason::MESSAGE_SEND_FAILED); |
| + if (active_bridge_) |
| + StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE); |
| } |
| void CastRemotingConnector::OnDataSendFailed() { |
| + VLOG(3) << __func__; |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| // A single data send failure is treated as fatal to an active remoting |
| // session. |
| if (active_bridge_) |
| StopRemoting(active_bridge_, RemotingStopReason::DATA_SEND_FAILED); |
| } |
| - |
| -void CastRemotingConnector::OnRoutesUpdated( |
| - const std::vector<media_router::MediaRoute>& routes, |
| - const std::vector<media_router::MediaRoute::Id>& joinable_route_ids) { |
| - DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| - |
| - // If a remoting route has already been identified, check that it still |
| - // exists. Otherwise, shut down messaging and any active remoting, and notify |
| - // the sources that remoting is no longer available. |
| - if (message_observer_) { |
| - for (const media_router::MediaRoute& route : routes) { |
| - if (message_observer_->route_id() == route.media_route_id()) |
| - return; // Remoting route still exists. Take no further action. |
| - } |
| - message_observer_.reset(); |
| - if (active_bridge_) |
| - StopRemoting(active_bridge_, RemotingStopReason::ROUTE_TERMINATED); |
| - for (RemotingBridge* notifyee : bridges_) |
| - notifyee->OnSinkGone(); |
| - } |
| - |
| - // There shouldn't be an active RemotingBridge at this point, since there is |
| - // currently no known remoting route. |
| - DCHECK(!active_bridge_); |
| - |
| - // Scan |routes| for a new remoting route. If one is found, begin processing |
| - // messages on the route, and notify the sources that remoting is now |
| - // available. |
| - for (const media_router::MediaRoute& route : routes) { |
| - if (route.media_source().id() != media_source_id_) |
| - continue; |
| - message_observer_.reset(new MessageObserver( |
| - media_router::MediaRoutesObserver::router(), route.media_route_id(), |
| - this)); |
| - // TODO(miu): In the future, scan the route ID for sink capabilities |
| - // properties and pass these to the source in the OnSinkAvailable() |
| - // notification. |
| - for (RemotingBridge* notifyee : bridges_) |
| - notifyee->OnSinkAvailable(enabled_features_); |
| - break; |
| - } |
| -} |