| 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..592239f69e8ca16dab722cb9a150a12d3f309f4a
|
| --- /dev/null
|
| +++ b/extensions/renderer/display_source_custom_bindings.cc
|
| @@ -0,0 +1,292 @@
|
| +// 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::StartSession,
|
| + 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(isolate);
|
| + 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::StartSession(
|
| + 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)));
|
| + return;
|
| + }
|
| + const int sink_id = sink_id_val->ToInt32(isolate)->Value();
|
| + if (GetDisplaySession(sink_id)) {
|
| + isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
|
| + isolate, kSessionAlreadyStarted)));
|
| + return;
|
| + }
|
| +
|
| + 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;
|
| + }
|
| + }
|
| +
|
| + 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
|
|
|