Chromium Code Reviews| 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..72854e76a6fc95207c9afa339b6a8fd44a3170b9 |
| --- /dev/null |
| +++ b/extensions/renderer/display_source_custom_bindings.cc |
| @@ -0,0 +1,258 @@ |
| +// 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 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(); |
| + 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); |
| + CHECK(sink_id_val->IsInt32()); |
| + 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; |
| + } |
| + } |
| + |
| + scoped_ptr<DisplaySourceAuthInfo> auth_info; |
| + v8::Local<v8::Value> auth_info_v8_val = |
| + GetChildValue(start_info, "authenticationInfo", isolate); |
| + if (!auth_info_v8_val->IsNull()) { |
| + CHECK(auth_info_v8_val->IsObject()); |
| + scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| + scoped_ptr<base::Value> auth_info_val( |
| + converter->FromV8Value(auth_info_v8_val, context()->v8_context())); |
| + CHECK(auth_info_val); |
| + auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val); |
| + } |
| + |
| + 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(1, args.Length()); |
| + CHECK(args[0]->IsInt32()); |
| + |
| + v8::Isolate* isolate = context()->isolate(); |
| + 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; |
| + } |
| + |
| + session->Terminate(); |
|
asargent_no_longer_on_chrome
2015/12/07 21:47:49
I'm assuming we rely on the concrete implementatio
Mikhail
2015/12/08 07:44:44
Done.
|
| +} |
| + |
| +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); |
| + 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 |