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

Unified Diff: extensions/renderer/display_source_custom_bindings.cc

Issue 1471243002: chrome.displaySource custom bindings (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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: extensions/renderer/display_source_custom_bindings.cc
diff --git a/extensions/renderer/display_source_custom_bindings.cc b/extensions/renderer/display_source_custom_bindings.cc
new file mode 100644
index 0000000000000000000000000000000000000000..637dd2788d1266a3fed44cfddf97dcecd946d152
--- /dev/null
+++ b/extensions/renderer/display_source_custom_bindings.cc
@@ -0,0 +1,293 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/renderer/display_source_custom_bindings.h"
+
+#include "base/bind.h"
+#include "content/public/child/v8_value_converter.h"
+#include "extensions/renderer/script_context.h"
+#include "third_party/WebKit/public/platform/WebMediaStream.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+
+using content::V8ValueConverter;
+
+namespace {
+const char kErrorNotSupported[] = "Not supported";
+const char kInvalidSinkIdArg[] = "Invalid sink Id argument";
+const char kInvalidAuthInfoArg[] = "Invalid authentication info argument";
+const char kInvalidStreamArgs[] = "Invalid stream arguments";
+const char kSessionAlreadyStarted[] = "The session has been already started";
+const char kSessionAlreadyTerminating[] = "The session is already terminating";
+const char kSessionNotFound[] = "Session not found";
+} // namespace
+
+DisplaySourceCustomBindings::DisplaySourceCustomBindings(ScriptContext* context)
+ : ObjectBackedNativeHandler(context),
+ weak_factory_(this) {
+ RouteFunction("StartSession",
+ base::Bind(&DisplaySourceCustomBindings::CreateSession,
asargent_no_longer_on_chrome 2015/11/26 00:50:07 nit: any reason for the name mismatch between the
Mikhail 2015/11/26 13:00:47 Not really. Renamed.
+ weak_factory_.GetWeakPtr()));
+ RouteFunction("TerminateSession",
+ base::Bind(&DisplaySourceCustomBindings::TerminateSession,
+ weak_factory_.GetWeakPtr()));
+}
+
+DisplaySourceCustomBindings::~DisplaySourceCustomBindings() {
+}
+
+void DisplaySourceCustomBindings::Invalidate() {
+ session_map_.clear();
+ terminate_callback_map_.clear();
+ weak_factory_.InvalidateWeakPtrs();
+ ObjectBackedNativeHandler::Invalidate();
+}
+
+namespace {
+
+v8::Local<v8::Value> GetChildValue(v8::Local<v8::Object> value,
+ const std::string& key_name,
+ v8::Isolate* isolate) {
+ v8::Local<v8::Array> property_names(value->GetOwnPropertyNames());
+ for (uint32 i = 0; i < property_names->Length(); ++i) {
+ v8::Local<v8::Value> key(property_names->Get(i));
+ if (key_name == *v8::String::Utf8Value(key)) {
+ v8::TryCatch try_catch;
asargent_no_longer_on_chrome 2015/11/26 00:50:07 nit: according to the comment at https://code.goog
Mikhail 2015/11/26 13:00:47 Done.
+ v8::Local<v8::Value> child_v8 = value->Get(key);
+ if (try_catch.HasCaught()) {
+ return v8::Null(isolate);
+ }
+ return child_v8;
+ }
+ }
+
+ return v8::Null(isolate);
+}
+
+} // namespace
+
+void DisplaySourceCustomBindings::CreateSession(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ CHECK_EQ(1, args.Length());
+ CHECK(args[0]->IsObject());
+ v8::Isolate* isolate = context()->isolate();
+ v8::Local<v8::Object> start_info = args[0].As<v8::Object>();
+
+ v8::Local<v8::Value> sink_id_val =
+ GetChildValue(start_info, "sinkId", isolate);
+ if (sink_id_val->IsNull() || sink_id_val->IsUndefined()) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidSinkIdArg)));
asargent_no_longer_on_chrome 2015/11/26 00:50:07 The typical pattern for returning errors from exte
Mikhail 2015/11/26 13:00:47 These are just the arguments sanity checks that ca
asargent_no_longer_on_chrome 2015/12/01 01:54:23 If some errors are reported as exceptions and some
Devlin 2015/12/01 17:48:37 The standard we should be using is chrome.runtime.
+ return;
+ }
+ const int sink_id = sink_id_val->ToInt32(isolate)->Value();
+
+ v8::Local<v8::Value> video_stream_val =
+ GetChildValue(start_info, "videoTrack", isolate);
+ v8::Local<v8::Value> audio_stream_val =
+ GetChildValue(start_info, "audioTrack", isolate);
+
+ if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) &&
+ (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+ return;
+ }
+ blink::WebMediaStreamTrack audio_track, video_track;
+
+ if (!video_stream_val->IsNull() && !video_stream_val->IsUndefined()) {
+ CHECK(video_stream_val->IsObject());
+ video_track =
+ blink::WebDOMMediaStreamTrack::fromV8Value(
+ video_stream_val).component();
+ if (video_track.isNull()) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+ return;
+ }
+ }
+ if (!audio_stream_val->IsNull() && !audio_stream_val->IsUndefined()) {
+ CHECK(audio_stream_val->IsObject());
+ audio_track =
+ blink::WebDOMMediaStreamTrack::fromV8Value(
+ audio_stream_val).component();
+ if (audio_track.isNull()) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+ return;
+ }
+ }
+
+ v8::Local<v8::Value> auth_info_v8_val =
+ GetChildValue(start_info, "authenticationInfo", isolate);
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ scoped_ptr<base::Value> auth_info_val(
+ converter->FromV8Value(auth_info_v8_val, context()->v8_context()));
+ scoped_ptr<DisplaySourceAuthInfo> auth_info;
+ if (auth_info_val) {
+ auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val);
+ if (!auth_info) {
+ isolate->ThrowException(v8::Exception::Error(
+ v8::String::NewFromUtf8(isolate, kInvalidAuthInfoArg)));
+ return;
+ }
+ }
+
+ if (GetDisplaySession(sink_id)) {
asargent_no_longer_on_chrome 2015/11/26 00:50:07 optional: would it make sense to move this check u
Mikhail 2015/11/26 13:00:47 Makes sense, thus we'll be able to avoid unnecessa
+ isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+ isolate, kSessionAlreadyStarted)));
+ return;
+ }
+
+ scoped_ptr<DisplaySourceSession> session =
+ DisplaySourceSessionFactory::CreateSession(
+ sink_id, video_track, audio_track, std::move(auth_info));
+ if (!session) {
+ isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+ isolate, kErrorNotSupported)));
+ return;
+ }
+
+ auto on_started_callback = base::Bind(
+ &DisplaySourceCustomBindings::OnSessionStarted,
+ weak_factory_.GetWeakPtr());
+ auto on_terminated_callback = base::Bind(
+ &DisplaySourceCustomBindings::OnSessionTerminated,
+ weak_factory_.GetWeakPtr());
+ auto on_error_callback = base::Bind(
+ &DisplaySourceCustomBindings::OnSessionError,
+ weak_factory_.GetWeakPtr());
+ session->SetCallbacks(on_started_callback,
+ on_terminated_callback,
+ on_error_callback);
+ session_map_.insert(std::make_pair(sink_id, std::move(session)));
+ session->Start();
+}
+
+void DisplaySourceCustomBindings::TerminateSession(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ CHECK_EQ(2, args.Length());
+ CHECK(args[0]->IsInt32());
+ CHECK(args[1]->IsNull() || args[1]->IsFunction());
+
+ v8::Isolate* isolate = context()->isolate();
+ v8::Global<v8::Function> terminate_callback;
+ if (!args[1]->IsNull())
+ terminate_callback.Reset(isolate, args[1].As<v8::Function>());
+
+ int sink_id = args[0]->ToInt32(args.GetIsolate())->Value();
+ DisplaySourceSession* session = GetDisplaySession(sink_id);
+ if (!session) {
+ isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+ isolate, kSessionNotFound)));
+ return;
+ }
+
+ if (session->state() == DisplaySourceSession::Terminating) {
+ isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
+ isolate, kSessionAlreadyTerminating)));
+ return;
+ }
+
+ if (!terminate_callback.IsEmpty()) {
+ CHECK(terminate_callback_map_.find(sink_id) ==
+ terminate_callback_map_.end());
+ terminate_callback_map_.insert(
+ std::make_pair(sink_id, std::move(terminate_callback)));
+ }
+
+ session->Terminate();
+}
+
+void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const {
+ v8::Isolate* isolate = context()->isolate();
+ 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);
+}
+
+void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const {
+ v8::Isolate* isolate = context()->isolate();
+ 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.onSessionTerminated", event_args);
+}
+
+void DisplaySourceCustomBindings::DispatchSessionError(
+ int sink_id,
+ DisplaySourceErrorType type,
+ const std::string& message) const {
+ v8::Isolate* isolate = context()->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Context::Scope context_scope(context()->v8_context());
+
+ api::display_source::ErrorInfo error_info;
+ error_info.type = type;
+ if (!message.empty())
+ error_info.description.reset(new std::string(message));
+
+ scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
+ v8::Local<v8::Value> info_arg =
+ converter->ToV8Value(error_info.ToValue().get(),
+ context()->v8_context());
+
+ v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2);
+ event_args->Set(0, v8::Integer::New(isolate, sink_id));
+ event_args->Set(1, info_arg);
+ context()->DispatchEvent("displaySource.onSessionErrorOccured", event_args);
+}
+
+DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession(
+ int sink_id) const {
+ auto iter = session_map_.find(sink_id);
+ if (iter != session_map_.end())
+ return iter->second.get();
+ return nullptr;
+}
+
+void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) {
+ DispatchSessionStarted(sink_id);
+}
+
+void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) {
+ DisplaySourceSession* session = GetDisplaySession(sink_id);
+ CHECK(session);
+ session_map_.erase(sink_id);
+
+ // Call a termination callback if needed.
+ auto iter = terminate_callback_map_.find(sink_id);
+ if (iter != terminate_callback_map_.end()) {
+ v8::Isolate* isolate = context()->isolate();
+ v8::Local<v8::Value> callback_args[1];
+ callback_args[0] = v8::Integer::New(isolate, sink_id);
+ context()->CallFunction(
+ v8::Local<v8::Function>::New(isolate, iter->second), 1,
+ callback_args);
+ terminate_callback_map_.erase(iter);
+ }
+
+ DispatchSessionTerminated(sink_id);
+}
+
+void DisplaySourceCustomBindings::OnSessionError(int sink_id,
+ DisplaySourceErrorType type,
+ const std::string& message) {
+ DisplaySourceSession* session = GetDisplaySession(sink_id);
+ CHECK(session);
+ if (session->state() == DisplaySourceSession::Establishing) {
+ // Error has occured before the session has actually started.
+ session_map_.erase(sink_id);
+ }
+
+ DispatchSessionError(sink_id, type, message);
+}
+
+} // extensions

Powered by Google App Engine
This is Rietveld 408576698