| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
 |    2 // Use of this source code is governed by a BSD-style license that can be | 
 |    3 // found in the LICENSE file. | 
 |    4  | 
 |    5 #include "extensions/renderer/display_source_custom_bindings.h" | 
 |    6  | 
 |    7 #include "base/bind.h" | 
 |    8 #include "content/public/child/v8_value_converter.h" | 
 |    9 #include "extensions/renderer/script_context.h" | 
 |   10 #include "third_party/WebKit/public/platform/WebMediaStream.h" | 
 |   11 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | 
 |   12 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" | 
 |   13 #include "v8/include/v8.h" | 
 |   14  | 
 |   15 namespace extensions { | 
 |   16  | 
 |   17 using content::V8ValueConverter; | 
 |   18  | 
 |   19 namespace { | 
 |   20 const char kErrorNotSupported[] = "Not supported"; | 
 |   21 const char kInvalidSinkIdArg[] = "Invalid sink Id argument"; | 
 |   22 const char kInvalidAuthInfoArg[] = "Invalid authentication info argument"; | 
 |   23 const char kInvalidStreamArgs[] = "Invalid stream arguments"; | 
 |   24 const char kSessionAlreadyStarted[] = "The session has been already started"; | 
 |   25 const char kSessionAlreadyTerminating[] = "The session is already terminating"; | 
 |   26 const char kSessionNotFound[] = "Session not found"; | 
 |   27 }  // namespace | 
 |   28  | 
 |   29 DisplaySourceCustomBindings::DisplaySourceCustomBindings(ScriptContext* context) | 
 |   30     : ObjectBackedNativeHandler(context), | 
 |   31       weak_factory_(this) { | 
 |   32   RouteFunction("StartSession", | 
 |   33                 base::Bind(&DisplaySourceCustomBindings::StartSession, | 
 |   34                            weak_factory_.GetWeakPtr())); | 
 |   35   RouteFunction("TerminateSession", | 
 |   36                 base::Bind(&DisplaySourceCustomBindings::TerminateSession, | 
 |   37                            weak_factory_.GetWeakPtr())); | 
 |   38 } | 
 |   39  | 
 |   40 DisplaySourceCustomBindings::~DisplaySourceCustomBindings() { | 
 |   41 } | 
 |   42  | 
 |   43 void DisplaySourceCustomBindings::Invalidate() { | 
 |   44   session_map_.clear(); | 
 |   45   terminate_callback_map_.clear(); | 
 |   46   weak_factory_.InvalidateWeakPtrs(); | 
 |   47   ObjectBackedNativeHandler::Invalidate(); | 
 |   48 } | 
 |   49  | 
 |   50 namespace { | 
 |   51  | 
 |   52 v8::Local<v8::Value> GetChildValue(v8::Local<v8::Object> value, | 
 |   53                                    const std::string& key_name, | 
 |   54                                    v8::Isolate* isolate) { | 
 |   55   v8::Local<v8::Array> property_names(value->GetOwnPropertyNames()); | 
 |   56   for (uint32 i = 0; i < property_names->Length(); ++i) { | 
 |   57     v8::Local<v8::Value> key(property_names->Get(i)); | 
 |   58     if (key_name == *v8::String::Utf8Value(key)) { | 
 |   59       v8::TryCatch try_catch(isolate); | 
 |   60       v8::Local<v8::Value> child_v8 = value->Get(key); | 
 |   61       if (try_catch.HasCaught()) { | 
 |   62         return v8::Null(isolate); | 
 |   63       } | 
 |   64       return child_v8; | 
 |   65     } | 
 |   66   } | 
 |   67  | 
 |   68   return v8::Null(isolate); | 
 |   69 } | 
 |   70  | 
 |   71 }  // namespace | 
 |   72  | 
 |   73 void DisplaySourceCustomBindings::StartSession( | 
 |   74     const v8::FunctionCallbackInfo<v8::Value>& args) { | 
 |   75   CHECK_EQ(1, args.Length()); | 
 |   76   CHECK(args[0]->IsObject()); | 
 |   77   v8::Isolate* isolate = context()->isolate(); | 
 |   78   v8::Local<v8::Object> start_info = args[0].As<v8::Object>(); | 
 |   79  | 
 |   80   v8::Local<v8::Value> sink_id_val = | 
 |   81       GetChildValue(start_info, "sinkId", isolate); | 
 |   82   if (sink_id_val->IsNull() || sink_id_val->IsUndefined()) { | 
 |   83     isolate->ThrowException(v8::Exception::Error( | 
 |   84         v8::String::NewFromUtf8(isolate, kInvalidSinkIdArg))); | 
 |   85     return; | 
 |   86   } | 
 |   87   const int sink_id = sink_id_val->ToInt32(isolate)->Value(); | 
 |   88   if (GetDisplaySession(sink_id)) { | 
 |   89     isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | 
 |   90         isolate, kSessionAlreadyStarted))); | 
 |   91     return; | 
 |   92   } | 
 |   93  | 
 |   94   v8::Local<v8::Value> video_stream_val = | 
 |   95       GetChildValue(start_info, "videoTrack", isolate); | 
 |   96   v8::Local<v8::Value> audio_stream_val = | 
 |   97       GetChildValue(start_info, "audioTrack", isolate); | 
 |   98  | 
 |   99   if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) && | 
 |  100       (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) { | 
 |  101     isolate->ThrowException(v8::Exception::Error( | 
 |  102         v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | 
 |  103     return; | 
 |  104   } | 
 |  105   blink::WebMediaStreamTrack audio_track, video_track; | 
 |  106  | 
 |  107   if (!video_stream_val->IsNull() && !video_stream_val->IsUndefined()) { | 
 |  108     CHECK(video_stream_val->IsObject()); | 
 |  109     video_track = | 
 |  110         blink::WebDOMMediaStreamTrack::fromV8Value( | 
 |  111             video_stream_val).component(); | 
 |  112     if (video_track.isNull()) { | 
 |  113       isolate->ThrowException(v8::Exception::Error( | 
 |  114           v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | 
 |  115       return; | 
 |  116     } | 
 |  117   } | 
 |  118   if (!audio_stream_val->IsNull() && !audio_stream_val->IsUndefined()) { | 
 |  119     CHECK(audio_stream_val->IsObject()); | 
 |  120     audio_track = | 
 |  121         blink::WebDOMMediaStreamTrack::fromV8Value( | 
 |  122             audio_stream_val).component(); | 
 |  123     if (audio_track.isNull()) { | 
 |  124       isolate->ThrowException(v8::Exception::Error( | 
 |  125           v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | 
 |  126       return; | 
 |  127     } | 
 |  128   } | 
 |  129  | 
 |  130   v8::Local<v8::Value> auth_info_v8_val = | 
 |  131       GetChildValue(start_info, "authenticationInfo", isolate); | 
 |  132   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 
 |  133   scoped_ptr<base::Value> auth_info_val( | 
 |  134       converter->FromV8Value(auth_info_v8_val, context()->v8_context())); | 
 |  135   scoped_ptr<DisplaySourceAuthInfo> auth_info; | 
 |  136   if (auth_info_val) { | 
 |  137     auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val); | 
 |  138     if (!auth_info) { | 
 |  139       isolate->ThrowException(v8::Exception::Error( | 
 |  140           v8::String::NewFromUtf8(isolate, kInvalidAuthInfoArg))); | 
 |  141       return; | 
 |  142     } | 
 |  143   } | 
 |  144  | 
 |  145   scoped_ptr<DisplaySourceSession> session = | 
 |  146       DisplaySourceSessionFactory::CreateSession( | 
 |  147           sink_id, video_track, audio_track, std::move(auth_info)); | 
 |  148   if (!session) { | 
 |  149     isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | 
 |  150         isolate, kErrorNotSupported))); | 
 |  151     return; | 
 |  152   } | 
 |  153  | 
 |  154   auto on_started_callback = base::Bind( | 
 |  155       &DisplaySourceCustomBindings::OnSessionStarted, | 
 |  156       weak_factory_.GetWeakPtr()); | 
 |  157   auto on_terminated_callback = base::Bind( | 
 |  158       &DisplaySourceCustomBindings::OnSessionTerminated, | 
 |  159       weak_factory_.GetWeakPtr()); | 
 |  160   auto on_error_callback = base::Bind( | 
 |  161       &DisplaySourceCustomBindings::OnSessionError, | 
 |  162       weak_factory_.GetWeakPtr()); | 
 |  163   session->SetCallbacks(on_started_callback, | 
 |  164                         on_terminated_callback, | 
 |  165                         on_error_callback); | 
 |  166   session_map_.insert(std::make_pair(sink_id, std::move(session))); | 
 |  167   session->Start(); | 
 |  168 } | 
 |  169  | 
 |  170 void DisplaySourceCustomBindings::TerminateSession( | 
 |  171     const v8::FunctionCallbackInfo<v8::Value>& args) { | 
 |  172   CHECK_EQ(2, args.Length()); | 
 |  173   CHECK(args[0]->IsInt32()); | 
 |  174   CHECK(args[1]->IsNull() || args[1]->IsFunction()); | 
 |  175  | 
 |  176   v8::Isolate* isolate = context()->isolate(); | 
 |  177   v8::Global<v8::Function> terminate_callback; | 
 |  178   if (!args[1]->IsNull()) | 
 |  179     terminate_callback.Reset(isolate, args[1].As<v8::Function>()); | 
 |  180  | 
 |  181   int sink_id = args[0]->ToInt32(args.GetIsolate())->Value(); | 
 |  182   DisplaySourceSession* session = GetDisplaySession(sink_id); | 
 |  183   if (!session) { | 
 |  184     isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | 
 |  185         isolate, kSessionNotFound))); | 
 |  186     return; | 
 |  187   } | 
 |  188  | 
 |  189   if (session->state() == DisplaySourceSession::Terminating) { | 
 |  190     isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | 
 |  191         isolate, kSessionAlreadyTerminating))); | 
 |  192     return; | 
 |  193   } | 
 |  194  | 
 |  195   if (!terminate_callback.IsEmpty()) { | 
 |  196     CHECK(terminate_callback_map_.find(sink_id) == | 
 |  197           terminate_callback_map_.end()); | 
 |  198     terminate_callback_map_.insert( | 
 |  199         std::make_pair(sink_id, std::move(terminate_callback))); | 
 |  200   } | 
 |  201  | 
 |  202   session->Terminate(); | 
 |  203 } | 
 |  204  | 
 |  205 void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const { | 
 |  206   v8::Isolate* isolate = context()->isolate(); | 
 |  207   v8::HandleScope handle_scope(isolate); | 
 |  208   v8::Context::Scope context_scope(context()->v8_context()); | 
 |  209   v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1); | 
 |  210   event_args->Set(0, v8::Integer::New(isolate, sink_id)); | 
 |  211   context()->DispatchEvent("displaySource.onSessionStarted", event_args); | 
 |  212 } | 
 |  213  | 
 |  214 void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const { | 
 |  215   v8::Isolate* isolate = context()->isolate(); | 
 |  216   v8::HandleScope handle_scope(isolate); | 
 |  217   v8::Context::Scope context_scope(context()->v8_context()); | 
 |  218   v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1); | 
 |  219   event_args->Set(0, v8::Integer::New(isolate, sink_id)); | 
 |  220   context()->DispatchEvent("displaySource.onSessionTerminated", event_args); | 
 |  221 } | 
 |  222  | 
 |  223 void DisplaySourceCustomBindings::DispatchSessionError( | 
 |  224     int sink_id, | 
 |  225     DisplaySourceErrorType type, | 
 |  226     const std::string& message) const { | 
 |  227   v8::Isolate* isolate = context()->isolate(); | 
 |  228   v8::HandleScope handle_scope(isolate); | 
 |  229   v8::Context::Scope context_scope(context()->v8_context()); | 
 |  230  | 
 |  231   api::display_source::ErrorInfo error_info; | 
 |  232   error_info.type = type; | 
 |  233   if (!message.empty()) | 
 |  234     error_info.description.reset(new std::string(message)); | 
 |  235  | 
 |  236   scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | 
 |  237   v8::Local<v8::Value> info_arg = | 
 |  238       converter->ToV8Value(error_info.ToValue().get(), | 
 |  239                            context()->v8_context()); | 
 |  240  | 
 |  241   v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2); | 
 |  242   event_args->Set(0, v8::Integer::New(isolate, sink_id)); | 
 |  243   event_args->Set(1, info_arg); | 
 |  244   context()->DispatchEvent("displaySource.onSessionErrorOccured", event_args); | 
 |  245 } | 
 |  246  | 
 |  247 DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession( | 
 |  248     int sink_id) const { | 
 |  249   auto iter = session_map_.find(sink_id); | 
 |  250   if (iter != session_map_.end()) | 
 |  251     return iter->second.get(); | 
 |  252   return nullptr; | 
 |  253 } | 
 |  254  | 
 |  255 void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) { | 
 |  256   DispatchSessionStarted(sink_id); | 
 |  257 } | 
 |  258  | 
 |  259 void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) { | 
 |  260   DisplaySourceSession* session = GetDisplaySession(sink_id); | 
 |  261   CHECK(session); | 
 |  262   session_map_.erase(sink_id); | 
 |  263  | 
 |  264   // Call a termination callback if needed. | 
 |  265   auto iter = terminate_callback_map_.find(sink_id); | 
 |  266   if (iter != terminate_callback_map_.end()) { | 
 |  267     v8::Isolate* isolate = context()->isolate(); | 
 |  268     v8::Local<v8::Value> callback_args[1]; | 
 |  269     callback_args[0] = v8::Integer::New(isolate, sink_id); | 
 |  270     context()->CallFunction( | 
 |  271         v8::Local<v8::Function>::New(isolate, iter->second), 1, | 
 |  272         callback_args); | 
 |  273     terminate_callback_map_.erase(iter); | 
 |  274   } | 
 |  275  | 
 |  276   DispatchSessionTerminated(sink_id); | 
 |  277 } | 
 |  278  | 
 |  279 void DisplaySourceCustomBindings::OnSessionError(int sink_id, | 
 |  280                                                  DisplaySourceErrorType type, | 
 |  281                                                  const std::string& message) { | 
 |  282   DisplaySourceSession* session = GetDisplaySession(sink_id); | 
 |  283   CHECK(session); | 
 |  284   if (session->state() == DisplaySourceSession::Establishing) { | 
 |  285     // Error has occured before the session has actually started. | 
 |  286     session_map_.erase(sink_id); | 
 |  287   } | 
 |  288  | 
 |  289   DispatchSessionError(sink_id, type, message); | 
 |  290 } | 
 |  291  | 
 |  292 }  // extensions | 
| OLD | NEW |