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

Unified Diff: chrome/browser/media/cast_remoting_connector.cc

Issue 2951523002: Media Remoting: Add mojo interfaces between browser and extension. (Closed)
Patch Set: Fix unittests. Created 3 years, 5 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 side-by-side diff with in-line comments
Download patch
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;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698