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..d63994bc26672db18e9c8eaa418e16fb491a48cc 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; |
@@ -140,12 +116,13 @@ CastRemotingConnector* CastRemotingConnector::Get( |
CastRemotingConnector* connector = |
static_cast<CastRemotingConnector*>(contents->GetUserData(kUserDataKey)); |
if (!connector) { |
+ const SessionID::id_type tab_id = SessionTabHelper::IdForTab(contents); |
imcheng
2017/07/05 18:53:08
FYI: MediaRouterAndroid use TabAndroid::GetAndroid
xjz
2017/07/06 22:03:44
Done.
|
+ if (tab_id == -1) |
+ return nullptr; |
connector = new CastRemotingConnector( |
media_router::MediaRouterFactory::GetApiForBrowserContext( |
contents->GetBrowserContext()), |
- media_router::MediaSourceForTabContentRemoting( |
- SessionTabHelper::IdForTab(contents)) |
- .id()); |
+ tab_id); |
contents->SetUserData(kUserDataKey, base::WrapUnique(connector)); |
} |
return connector; |
@@ -160,8 +137,10 @@ void CastRemotingConnector::CreateMediaRemoter( |
auto* const contents = content::WebContents::FromRenderFrameHost(host); |
if (!contents) |
return; |
- CastRemotingConnector::Get(contents)->CreateBridge(std::move(source), |
- std::move(request)); |
+ CastRemotingConnector* const connector = CastRemotingConnector::Get(contents); |
+ if (!connector) |
+ return; |
+ connector->CreateBridge(std::move(source), std::move(request)); |
} |
namespace { |
@@ -175,15 +154,17 @@ 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) { |
+ VLOG(2) << "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 +176,38 @@ CastRemotingConnector::~CastRemotingConnector() { |
notifyee->OnSinkGone(); |
notifyee->OnCastRemotingConnectorDestroyed(); |
} |
+ media_router_->UnregisterRemotingSource(tab_id_); |
+} |
+ |
+void CastRemotingConnector::ConnectToService( |
+ media::mojom::MirrorServiceRemotingSourceRequest source_request, |
+ media::mojom::MirrorServiceRemoterPtr remoter) { |
+ DCHECK(!binding_.is_bound()); |
+ DCHECK(!remoter_); |
+ DCHECK(remoter); |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__; |
+ |
+ 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() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__; |
+ |
+ if (binding_.is_bound()) |
+ binding_.Close(); |
+ remoter_.reset(); |
+ |
+ if (active_bridge_) |
+ StopRemoting(active_bridge_, RemotingStopReason::SERVICE_GONE); |
+ for (RemotingBridge* notifyee : bridges_) |
+ notifyee->OnSinkGone(); |
} |
void CastRemotingConnector::CreateBridge(media::mojom::RemotingSourcePtr source, |
@@ -209,7 +222,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_); |
} |
@@ -226,14 +240,17 @@ void CastRemotingConnector::DeregisterBridge(RemotingBridge* bridge, |
void CastRemotingConnector::StartRemoting(RemotingBridge* bridge) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
DCHECK(bridges_.find(bridge) != bridges_.end()); |
+ VLOG(2) << __func__; |
// 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(2) << "Remoting start failed: No mirror service connected."; |
+ bridge->OnStartFailed(RemotingStartFailReason::SERVICE_NOT_CONNECTED); |
return; |
} |
if (active_bridge_) { |
+ VLOG(2) << "Remoting start failed: Cannot start multiple."; |
bridge->OnStartFailed(RemotingStartFailReason::CANNOT_START_MULTIPLE); |
return; |
} |
@@ -249,12 +266,10 @@ 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_)); |
- |
+ // Assume the remoting session is always started successfully. If any failure |
+ // occurs, OnError() will be called. |
bridge->OnStarted(); |
} |
@@ -265,10 +280,11 @@ void CastRemotingConnector::StartRemotingDataStreams( |
media::mojom::RemotingDataStreamSenderRequest audio_sender_request, |
media::mojom::RemotingDataStreamSenderRequest video_sender_request) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__; |
// 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. |
@@ -279,39 +295,57 @@ void CastRemotingConnector::StartRemotingDataStreams( |
return; |
} |
- // Hold on to the data pipe handles and interface requests until one/both |
- // CastRemotingSenders are created and ready for use. |
- pending_audio_pipe_ = std::move(audio_pipe); |
- pending_video_pipe_ = std::move(video_pipe); |
- 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')); |
+ const bool want_audio = audio_sender_request.is_pending(); |
+ const bool want_video = video_sender_request.is_pending(); |
+ remoter_->StartDataStreams( |
+ want_audio, want_video, |
+ base::BindOnce(&CastRemotingConnector::OnDataStreamsStarted, |
+ weak_factory_.GetWeakPtr(), std::move(audio_pipe), |
+ std::move(video_pipe), std::move(audio_sender_request), |
+ std::move(video_sender_request))); |
+} |
+ |
+void CastRemotingConnector::OnDataStreamsStarted( |
+ mojo::ScopedDataPipeConsumerHandle audio_pipe, |
+ mojo::ScopedDataPipeConsumerHandle video_pipe, |
+ media::mojom::RemotingDataStreamSenderRequest audio_sender_request, |
+ media::mojom::RemotingDataStreamSenderRequest video_sender_request, |
+ int32_t audio_stream_id, |
+ int32_t video_stream_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ DCHECK(remoter_); |
+ VLOG(2) << __func__ << ": audio_stream_id = " << audio_stream_id |
+ << " video_stream_id = " << video_stream_id; |
+ |
+ if (!active_bridge_) { |
+ remoter_->Stop(media::mojom::RemotingStopReason::SOURCE_GONE); |
+ return; |
+ } |
+ |
+ if (audio_sender_request.is_pending() && audio_stream_id > -1) { |
+ cast::CastRemotingSender::FindAndBind( |
+ audio_stream_id, std::move(audio_pipe), std::move(audio_sender_request), |
+ base::Bind(&CastRemotingConnector::OnDataSendFailed, |
+ weak_factory_.GetWeakPtr())); |
+ } |
+ if (video_sender_request.is_pending() && video_stream_id > -1) { |
+ cast::CastRemotingSender::FindAndBind( |
+ video_stream_id, std::move(video_pipe), std::move(video_sender_request), |
+ base::Bind(&CastRemotingConnector::OnDataSendFailed, |
+ weak_factory_.GetWeakPtr())); |
+ } |
} |
void CastRemotingConnector::StopRemoting(RemotingBridge* bridge, |
RemotingStopReason reason) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__ << ": reason = " << reason; |
if (active_bridge_ != bridge) |
return; |
active_bridge_ = nullptr; |
- // Explicitly close the data pipes (and related requests) just in case the |
- // "start streams" operation was interrupted. |
- pending_audio_pipe_.reset(); |
- pending_video_pipe_.reset(); |
- pending_audio_sender_request_ = nullptr; |
- pending_video_sender_request_ = nullptr; |
- |
// Cancel all outstanding callbacks related to the remoting session. |
weak_factory_.InvalidateWeakPtrs(); |
@@ -320,195 +354,75 @@ 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) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__ << ": reason = " << reason; |
+ |
+ if (!active_bridge_) |
+ 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::SinkCapabilitiesPtr capabilities) { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__; |
- // 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 |
imcheng
2017/07/05 18:53:08
s/are supposed/should be
xjz
2017/07/06 22:03:44
Done.
|
+ // remoting session. |
+ if (active_bridge_) { |
+ LOG(WARNING) << "Unexpected OnSinkAvailable() call during an active" |
+ << "remoting session."; |
+ 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() { |
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); |
+ VLOG(2) << __func__; |
+ |
+ if (active_bridge_) |
+ StopRemoting(active_bridge_, RemotingStopReason::UNEXPECTED_FAILURE); |
} |
void CastRemotingConnector::OnDataSendFailed() { |
DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ VLOG(2) << __func__; |
+ |
// 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; |
- } |
-} |