diff options
9 files changed, 197 insertions, 116 deletions
diff --git a/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.cc b/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.cc index 59dfda1..015eca3 100644 --- a/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.cc +++ b/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.cc @@ -23,20 +23,15 @@ WiFiDisplaySessionServiceImpl::WiFiDisplaySessionServiceImpl( mojo::InterfaceRequest<WiFiDisplaySessionService> request) : binding_(this, std::move(request)), delegate_(delegate), - last_connected_sink_(DisplaySourceConnectionDelegate::kInvalidSinkId), - own_sink_(DisplaySourceConnectionDelegate::kInvalidSinkId), + sink_state_(SINK_STATE_NONE), + sink_id_(DisplaySourceConnectionDelegate::kInvalidSinkId), weak_factory_(this) { delegate_->AddObserver(this); - - auto connection = delegate_->connection(); - if (connection) - last_connected_sink_ = connection->GetConnectedSink()->id; } WiFiDisplaySessionServiceImpl::~WiFiDisplaySessionServiceImpl() { delegate_->RemoveObserver(this); - if (own_sink_ != DisplaySourceConnectionDelegate::kInvalidSinkId) - Disconnect(); + Disconnect(); } // static @@ -67,7 +62,7 @@ void WiFiDisplaySessionServiceImpl::Connect(int32_t sink_id, DCHECK(client_); // We support only one Wi-Fi Display session at a time. if (delegate_->connection()) { - client_->OnError(sink_id, ERROR_TYPE_EXCEEDED_SESSION_LIMIT_ERROR, + client_->OnError(ERROR_TYPE_EXCEEDED_SESSION_LIMIT_ERROR, kErrorCannotHaveMultipleSessions); return; } @@ -77,7 +72,7 @@ void WiFiDisplaySessionServiceImpl::Connect(int32_t sink_id, sinks.begin(), sinks.end(), [sink_id](DisplaySourceSinkInfoPtr ptr) { return ptr->id == sink_id; }); if (found == sinks.end() || (*found)->state != SINK_STATE_DISCONNECTED) { - client_->OnError(sink_id, ERROR_TYPE_ESTABLISH_CONNECTION_ERROR, + client_->OnError(ERROR_TYPE_ESTABLISH_CONNECTION_ERROR, kErrorSinkNotAvailable); return; } @@ -90,86 +85,113 @@ void WiFiDisplaySessionServiceImpl::Connect(int32_t sink_id, auto on_error = base::Bind(&WiFiDisplaySessionServiceImpl::OnConnectFailed, weak_factory_.GetWeakPtr(), sink_id); delegate_->Connect(sink_id, auth_info, on_error); - own_sink_ = sink_id; + sink_id_ = sink_id; + sink_state_ = (*found)->state; + DCHECK(sink_state_ == SINK_STATE_CONNECTING); } void WiFiDisplaySessionServiceImpl::Disconnect() { - if (own_sink_ == DisplaySourceConnectionDelegate::kInvalidSinkId) { + if (sink_id_ == DisplaySourceConnectionDelegate::kInvalidSinkId) { // The connection might drop before this call has arrived. // Renderer should have been notified already. return; } - DCHECK(delegate_->connection()); - DCHECK_EQ(own_sink_, delegate_->connection()->GetConnectedSink()->id); + + const DisplaySourceSinkInfoList& sinks = delegate_->last_found_sinks(); + auto found = std::find_if( + sinks.begin(), sinks.end(), + [this](DisplaySourceSinkInfoPtr ptr) { return ptr->id == sink_id_; }); + DCHECK(found != sinks.end()); + DCHECK((*found)->state == SINK_STATE_CONNECTED || + (*found)->state == SINK_STATE_CONNECTING); + auto on_error = base::Bind(&WiFiDisplaySessionServiceImpl::OnDisconnectFailed, - weak_factory_.GetWeakPtr(), own_sink_); + weak_factory_.GetWeakPtr(), sink_id_); delegate_->Disconnect(on_error); } void WiFiDisplaySessionServiceImpl::SendMessage(const mojo::String& message) { - if (own_sink_ == DisplaySourceConnectionDelegate::kInvalidSinkId) { + if (sink_id_ == DisplaySourceConnectionDelegate::kInvalidSinkId) { // The connection might drop before this call has arrived. return; } auto connection = delegate_->connection(); DCHECK(connection); - DCHECK_EQ(own_sink_, connection->GetConnectedSink()->id); + DCHECK_EQ(sink_id_, connection->GetConnectedSink()->id); connection->SendMessage(message); } void WiFiDisplaySessionServiceImpl::OnSinkMessage(const std::string& message) { DCHECK(delegate_->connection()); - DCHECK_NE(own_sink_, DisplaySourceConnectionDelegate::kInvalidSinkId); + DCHECK_NE(sink_id_, DisplaySourceConnectionDelegate::kInvalidSinkId); DCHECK(client_); client_->OnMessage(message); } void WiFiDisplaySessionServiceImpl::OnSinksUpdated( const DisplaySourceSinkInfoList& sinks) { - auto connection = delegate_->connection(); - if (!connection && - last_connected_sink_ != DisplaySourceConnectionDelegate::kInvalidSinkId) { - if (last_connected_sink_ == own_sink_) - own_sink_ = DisplaySourceConnectionDelegate::kInvalidSinkId; - if (client_) - client_->OnDisconnected(last_connected_sink_); - last_connected_sink_ = DisplaySourceConnectionDelegate::kInvalidSinkId; + if (sink_id_ == DisplaySourceConnectionDelegate::kInvalidSinkId) + return; + // The initialized sink id means that the client should have + // been initialized as well. + DCHECK(client_); + auto found = std::find_if( + sinks.begin(), sinks.end(), + [this](DisplaySourceSinkInfoPtr ptr) { return ptr->id == sink_id_; }); + if (found == sinks.end()) { + client_->OnError(ERROR_TYPE_CONNECTION_ERROR, "The sink has disappeared"); + client_->OnTerminated(); + sink_id_ = DisplaySourceConnectionDelegate::kInvalidSinkId; } - if (connection && - last_connected_sink_ != connection->GetConnectedSink()->id) { - last_connected_sink_ = connection->GetConnectedSink()->id; - if (client_) - client_->OnConnected(last_connected_sink_, connection->GetLocalAddress()); - if (last_connected_sink_ == own_sink_) { - auto on_message = - base::Bind(&WiFiDisplaySessionServiceImpl::OnSinkMessage, - weak_factory_.GetWeakPtr()); - connection->SetMessageReceivedCallback(on_message); - } + + SinkState actual_state = (*found)->state; + + if (actual_state == sink_state_) + return; + + if (actual_state == SINK_STATE_CONNECTED) { + auto connection = delegate_->connection(); + DCHECK(connection); + auto on_message = base::Bind(&WiFiDisplaySessionServiceImpl::OnSinkMessage, + weak_factory_.GetWeakPtr()); + connection->SetMessageReceivedCallback(on_message); + client_->OnEstablished(connection->GetLocalAddress()); } + + if (actual_state == SINK_STATE_DISCONNECTED) { + client_->OnTerminated(); + sink_id_ = DisplaySourceConnectionDelegate::kInvalidSinkId; + } + + sink_state_ = actual_state; } void WiFiDisplaySessionServiceImpl::OnConnectionError( int sink_id, DisplaySourceErrorType type, const std::string& description) { + if (sink_id != sink_id_) + return; DCHECK(client_); - client_->OnError(sink_id, type, description); + client_->OnError(type, description); } void WiFiDisplaySessionServiceImpl::OnConnectFailed( int sink_id, const std::string& message) { + if (sink_id != sink_id_) + return; DCHECK(client_); - client_->OnError(sink_id, ERROR_TYPE_ESTABLISH_CONNECTION_ERROR, message); - own_sink_ = DisplaySourceConnectionDelegate::kInvalidSinkId; + client_->OnError(ERROR_TYPE_ESTABLISH_CONNECTION_ERROR, message); } void WiFiDisplaySessionServiceImpl::OnDisconnectFailed( int sink_id, const std::string& message) { + if (sink_id != sink_id_) + return; DCHECK(client_); - client_->OnError(sink_id, ERROR_TYPE_CONNECTION_ERROR, message); + client_->OnError(ERROR_TYPE_CONNECTION_ERROR, message); } void WiFiDisplaySessionServiceImpl::OnClientConnectionError() { diff --git a/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h b/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h index e50237c..6639871 100644 --- a/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h +++ b/extensions/browser/api/display_source/wifi_display/wifi_display_session_service_impl.h @@ -61,11 +61,9 @@ class WiFiDisplaySessionServiceImpl WiFiDisplaySessionServiceClientPtr client_; DisplaySourceConnectionDelegate* delegate_; - // Id of the currenty connected sink (if any), obtained from connection - // delegate. Keep it so that we know if a session has been ended. - int last_connected_sink_; + api::display_source::SinkState sink_state_; // Id of the sink of the session this object is associated with. - int own_sink_; + int sink_id_; base::WeakPtrFactory<WiFiDisplaySessionServiceImpl> weak_factory_; diff --git a/extensions/common/api/display_source.idl b/extensions/common/api/display_source.idl index f65a82a..83cfa0d 100644 --- a/extensions/common/api/display_source.idl +++ b/extensions/common/api/display_source.idl @@ -144,9 +144,6 @@ namespace displaySource { // or properties) // |sinks| the list of all currently available sinks static void onSinksUpdated(SinkInfo[] sinks); - // Event fired when the Display session is started. - // |sinkId| Id of the peer sink - [nocompile] static void onSessionStarted(long sinkId); // Event fired when the Display session is terminated. // |sinkId| Id of the peer sink [nocompile] static void onSessionTerminated(long sinkId); diff --git a/extensions/common/mojo/wifi_display_session_service.mojom b/extensions/common/mojo/wifi_display_session_service.mojom index e302256..637a1f0 100644 --- a/extensions/common/mojo/wifi_display_session_service.mojom +++ b/extensions/common/mojo/wifi_display_session_service.mojom @@ -21,13 +21,13 @@ interface WiFiDisplaySessionService { interface WiFiDisplaySessionServiceClient { // Notification of a successfull connection to a sink. - OnConnected(int32 sink_id, string ip_address); + OnEstablished(string ip_address); - // Notification of a connection termination. - OnDisconnected(int32 sink_id); + // Notification of a session termination. + OnTerminated(); // Notification of an error occurred during the session. - OnError(int32 sink_id, int32 type, string description); + OnError(int32 type, string description); // Invoked to transmit a controlling message from // the connected sink. diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc index 67edf4b..f6d1104 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_session.cc @@ -42,6 +42,8 @@ void WiFiDisplaySession::Start() { DCHECK(state_ == DisplaySourceSession::Idle); service_->Connect(params_.sink_id, params_.auth_method, params_.auth_data); state_ = DisplaySourceSession::Establishing; + if (!started_callback_.is_null()) + started_callback_.Run(params_.sink_id); } void WiFiDisplaySession::Terminate() { @@ -61,35 +63,26 @@ void WiFiDisplaySession::Terminate() { } } -void WiFiDisplaySession::OnConnected( - int32_t sink_id, const mojo::String& ip_address) { - if (sink_id == params_.sink_id) { - DCHECK(state_ != DisplaySourceSession::Established); - ip_address_ = ip_address; - state_ = DisplaySourceSession::Established; - } - - if (!started_callback_.is_null()) - started_callback_.Run(sink_id); +void WiFiDisplaySession::OnEstablished(const mojo::String& ip_address) { + DCHECK(state_ != DisplaySourceSession::Established); + ip_address_ = ip_address; + state_ = DisplaySourceSession::Established; } -void WiFiDisplaySession::OnDisconnected(int32_t sink_id) { - if (sink_id == params_.sink_id) { - DCHECK(state_ == DisplaySourceSession::Established || - state_ == DisplaySourceSession::Terminating); - state_ = DisplaySourceSession::Idle; - } - +void WiFiDisplaySession::OnTerminated() { + DCHECK(state_ != DisplaySourceSession::Idle); + state_ = DisplaySourceSession::Idle; if (!terminated_callback_.is_null()) - terminated_callback_.Run(sink_id); + terminated_callback_.Run(params_.sink_id); } -void WiFiDisplaySession::OnError( - int32_t sink_id, int32_t type, const mojo::String& description) { +void WiFiDisplaySession::OnError(int32_t type, + const mojo::String& description) { DCHECK(type > api::display_source::ERROR_TYPE_NONE && type <= api::display_source::ERROR_TYPE_LAST); if (!error_callback_.is_null()) - error_callback_.Run(sink_id, static_cast<ErrorType>(type), description); + error_callback_.Run(params_.sink_id, static_cast<ErrorType>(type), + description); } void WiFiDisplaySession::OnMessage(const mojo::String& data) { @@ -103,8 +96,7 @@ void WiFiDisplaySession::OnConnectionError() { kErrorInternal); } - if (state_ == DisplaySourceSession::Established || - state_ == DisplaySourceSession::Terminating) { + if (state_ != DisplaySourceSession::Idle) { // We must explicitly notify the session termination as it will never // arrive from browser process (IPC is broken). if (!terminated_callback_.is_null()) diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_session.h b/extensions/renderer/api/display_source/wifi_display/wifi_display_session.h index b807993..5d10308 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_session.h +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_session.h @@ -26,12 +26,9 @@ class WiFiDisplaySession: public DisplaySourceSession, void Terminate() override; // WiFiDisplaySessionServiceClient overrides. - void OnConnected(int32_t sink_id, - const mojo::String& ip_address) override; - void OnDisconnected(int32_t sink_id) override; - void OnError(int32_t sink_id, - int32_t type, - const mojo::String& description) override; + void OnEstablished(const mojo::String& ip_address) override; + void OnTerminated() override; + void OnError(int32_t type, const mojo::String& description) override; void OnMessage(const mojo::String& data) override; // A connection error handler for the mojo objects used in this class. diff --git a/extensions/renderer/display_source_custom_bindings.cc b/extensions/renderer/display_source_custom_bindings.cc index 50752c0..ab68553 100644 --- a/extensions/renderer/display_source_custom_bindings.cc +++ b/extensions/renderer/display_source_custom_bindings.cc @@ -71,8 +71,10 @@ v8::Local<v8::Value> GetChildValue(v8::Local<v8::Object> value, void DisplaySourceCustomBindings::StartSession( const v8::FunctionCallbackInfo<v8::Value>& args) { - CHECK_EQ(1, args.Length()); + CHECK_EQ(2, args.Length()); CHECK(args[0]->IsObject()); + CHECK(args[1]->IsFunction()); + v8::Isolate* isolate = context()->isolate(); v8::Local<v8::Object> start_info = args[0].As<v8::Object>(); @@ -164,14 +166,20 @@ void DisplaySourceCustomBindings::StartSession( session->SetCallbacks(on_started_callback, on_terminated_callback, on_error_callback); + + CallbackInfo cb_info = GetCallbackInfo(kStarted, sink_id); + args.GetReturnValue().Set(static_cast<int32_t>(cb_info.call_id)); + callbacks_.push_back(cb_info); + session->Start(); session_map_.insert(std::make_pair(sink_id, std::move(session))); } void DisplaySourceCustomBindings::TerminateSession( const v8::FunctionCallbackInfo<v8::Value>& args) { - CHECK_EQ(1, args.Length()); + CHECK_EQ(2, args.Length()); CHECK(args[0]->IsInt32()); + CHECK(args[1]->IsFunction()); v8::Isolate* isolate = context()->isolate(); int sink_id = args[0]->ToInt32(args.GetIsolate())->Value(); @@ -187,17 +195,40 @@ void DisplaySourceCustomBindings::TerminateSession( isolate, kSessionAlreadyTerminating))); return; } + + CallbackInfo cb_info = GetCallbackInfo(kTerminated, sink_id); + args.GetReturnValue().Set(static_cast<int32_t>(cb_info.call_id)); + callbacks_.push_back(cb_info); + // The session will get removed from session_map_ in OnSessionTerminated. session->Terminate(); } -void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const { +void DisplaySourceCustomBindings::CallCompletionCallback( + int sink_id, + CallbackType type, + const std::string& error_message) { + auto predicate = [sink_id, type](const CallbackInfo& info) -> bool { + return info.sink_id == sink_id && info.type == type; + }; + auto it = std::find_if(callbacks_.begin(), callbacks_.end(), predicate); + if (it == callbacks_.end()) + return; + v8::Isolate* isolate = context()->isolate(); + ModuleSystem* module_system = context()->module_system(); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context()->v8_context()); - v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1); - event_args->Set(0, v8::Integer::New(isolate, sink_id)); - context()->DispatchEvent("displaySource.onSessionStarted", event_args); + + v8::Local<v8::Value> callback_args[2]; + callback_args[0] = v8::Integer::New(isolate, it->call_id); + if (error_message.empty()) + callback_args[1] = v8::Null(isolate); + else + callback_args[1] = v8::String::NewFromUtf8(isolate, error_message.c_str()); + + module_system->CallModuleMethod("displaySource", "callCompletionCallback", 2, + callback_args); } void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const { @@ -242,7 +273,7 @@ DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession( } void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) { - DispatchSessionStarted(sink_id); + CallCompletionCallback(sink_id, kStarted); } void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) { @@ -250,6 +281,7 @@ void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) { CHECK(session); session_map_.erase(sink_id); DispatchSessionTerminated(sink_id); + CallCompletionCallback(sink_id, kTerminated); } void DisplaySourceCustomBindings::OnSessionError(int sink_id, @@ -257,14 +289,15 @@ void DisplaySourceCustomBindings::OnSessionError(int sink_id, const std::string& message) { DisplaySourceSession* session = GetDisplaySession(sink_id); CHECK(session); - if (session->state() != DisplaySourceSession::Established && - session->state() != DisplaySourceSession::Terminating) { - // Error has occured before the session has actually started, - // no need to wait for session termination notification. - session_map_.erase(sink_id); - } - DispatchSessionError(sink_id, type, message); } +DisplaySourceCustomBindings::CallbackInfo +DisplaySourceCustomBindings::GetCallbackInfo( + DisplaySourceCustomBindings::CallbackType type, + int sink_id) const { + static int sCallId = 0; + return {type, sink_id, ++sCallId}; +} + } // extensions diff --git a/extensions/renderer/display_source_custom_bindings.h b/extensions/renderer/display_source_custom_bindings.h index 199f199..2a65445 100644 --- a/extensions/renderer/display_source_custom_bindings.h +++ b/extensions/renderer/display_source_custom_bindings.h @@ -29,8 +29,12 @@ class DisplaySourceCustomBindings : public ObjectBackedNativeHandler { const v8::FunctionCallbackInfo<v8::Value>& args); void TerminateSession( const v8::FunctionCallbackInfo<v8::Value>& args); - - void DispatchSessionStarted(int sink_id) const; + // Call completion callbacks. + enum CallbackType { kStarted, kTerminated }; + void CallCompletionCallback(int sink_id, + CallbackType type, + const std::string& error_message = ""); + // Dispatch events void DispatchSessionTerminated(int sink_id) const; void DispatchSessionError(int sink_id, DisplaySourceErrorType type, @@ -46,6 +50,16 @@ class DisplaySourceCustomBindings : public ObjectBackedNativeHandler { DisplaySourceSession* GetDisplaySession(int sink_id) const; std::map<int, scoped_ptr<DisplaySourceSession>> session_map_; + // Data of a call completion callback. + struct CallbackInfo { + CallbackType type; + int sink_id; + int call_id; // Each call has a unique Id. + }; + + CallbackInfo GetCallbackInfo(CallbackType type, int sink_id) const; + + std::vector<CallbackInfo> callbacks_; base::WeakPtrFactory<DisplaySourceCustomBindings> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DisplaySourceCustomBindings); diff --git a/extensions/renderer/resources/display_source_custom_bindings.js b/extensions/renderer/resources/display_source_custom_bindings.js index 13e8167..a1345ff 100644 --- a/extensions/renderer/resources/display_source_custom_bindings.js +++ b/extensions/renderer/resources/display_source_custom_bindings.js @@ -8,34 +8,62 @@ var binding = require('binding').Binding.create('displaySource'); var chrome = requireNative('chrome').GetChrome(); var lastError = require('lastError'); var natives = requireNative('display_source'); +var logging = requireNative('logging'); + +var callbacksInfo = {}; + +function callbackWrapper(callback, method, message) { + if (callback == undefined) + return; + + try { + if (message !== null) + lastError.set('displaySource.startSession', message, null, chrome); + callback(); + } finally { + lastError.clear(chrome); + } +} + +function callCompletionCallback(callbackId, error_message) { + try { + var callbackInfo = callbacksInfo[callbackId]; + logging.DCHECK(callbackInfo != null); + callbackWrapper(callbackInfo.callback, callbackInfo.method, error_message); + } finally { + delete callbacksInfo[callbackId]; + } +} binding.registerCustomHook(function(bindingsAPI, extensionId) { var apiFunctions = bindingsAPI.apiFunctions; - apiFunctions.setHandleRequest('startSession', - function(sessionInfo, callback) { + apiFunctions.setHandleRequest( + 'startSession', function(sessionInfo, callback) { try { - natives.StartSession(sessionInfo); + var callId = natives.StartSession(sessionInfo, callbackWrapper); + callbacksInfo[callId] = { + callback: callback, + method: 'displaySource.startSession' + }; } catch (e) { - lastError.set('displaySource.startSession', e.message, null, chrome); - } finally { - if (callback !== undefined) - callback(); - lastError.clear(chrome); + callbackWrapper(callback, 'displaySource.startSession', e.message); } - }); - apiFunctions.setHandleRequest('terminateSession', - function(sink_id, callback) { + }); + apiFunctions.setHandleRequest( + 'terminateSession', function(sink_id, callback) { try { - natives.TerminateSession(sink_id); + var callId = natives.TerminateSession(sink_id, callbackWrapper); + callbacksInfo[callId] = { + callback: callback, + method: 'displaySource.terminateSession' + }; } catch (e) { - lastError.set( - 'displaySource.terminateSession', e.message, null, chrome); - } finally { - if (callback !== undefined) - callback(); - lastError.clear(chrome); + callbackWrapper( + callback, 'displaySource.terminateSession', e.message); } - }); + }); }); exports.$set('binding', binding.generate()); +// Called by C++. +exports.$set('callCompletionCallback', callCompletionCallback); |