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

Side by Side 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 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 unified diff | Download patch
OLDNEW
(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::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.
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;
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.
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::CreateSession(
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)));
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.
85 return;
86 }
87 const int sink_id = sink_id_val->ToInt32(isolate)->Value();
88
89 v8::Local<v8::Value> video_stream_val =
90 GetChildValue(start_info, "videoTrack", isolate);
91 v8::Local<v8::Value> audio_stream_val =
92 GetChildValue(start_info, "audioTrack", isolate);
93
94 if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) &&
95 (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) {
96 isolate->ThrowException(v8::Exception::Error(
97 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
98 return;
99 }
100 blink::WebMediaStreamTrack audio_track, video_track;
101
102 if (!video_stream_val->IsNull() && !video_stream_val->IsUndefined()) {
103 CHECK(video_stream_val->IsObject());
104 video_track =
105 blink::WebDOMMediaStreamTrack::fromV8Value(
106 video_stream_val).component();
107 if (video_track.isNull()) {
108 isolate->ThrowException(v8::Exception::Error(
109 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
110 return;
111 }
112 }
113 if (!audio_stream_val->IsNull() && !audio_stream_val->IsUndefined()) {
114 CHECK(audio_stream_val->IsObject());
115 audio_track =
116 blink::WebDOMMediaStreamTrack::fromV8Value(
117 audio_stream_val).component();
118 if (audio_track.isNull()) {
119 isolate->ThrowException(v8::Exception::Error(
120 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
121 return;
122 }
123 }
124
125 v8::Local<v8::Value> auth_info_v8_val =
126 GetChildValue(start_info, "authenticationInfo", isolate);
127 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
128 scoped_ptr<base::Value> auth_info_val(
129 converter->FromV8Value(auth_info_v8_val, context()->v8_context()));
130 scoped_ptr<DisplaySourceAuthInfo> auth_info;
131 if (auth_info_val) {
132 auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val);
133 if (!auth_info) {
134 isolate->ThrowException(v8::Exception::Error(
135 v8::String::NewFromUtf8(isolate, kInvalidAuthInfoArg)));
136 return;
137 }
138 }
139
140 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
141 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
142 isolate, kSessionAlreadyStarted)));
143 return;
144 }
145
146 scoped_ptr<DisplaySourceSession> session =
147 DisplaySourceSessionFactory::CreateSession(
148 sink_id, video_track, audio_track, std::move(auth_info));
149 if (!session) {
150 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
151 isolate, kErrorNotSupported)));
152 return;
153 }
154
155 auto on_started_callback = base::Bind(
156 &DisplaySourceCustomBindings::OnSessionStarted,
157 weak_factory_.GetWeakPtr());
158 auto on_terminated_callback = base::Bind(
159 &DisplaySourceCustomBindings::OnSessionTerminated,
160 weak_factory_.GetWeakPtr());
161 auto on_error_callback = base::Bind(
162 &DisplaySourceCustomBindings::OnSessionError,
163 weak_factory_.GetWeakPtr());
164 session->SetCallbacks(on_started_callback,
165 on_terminated_callback,
166 on_error_callback);
167 session_map_.insert(std::make_pair(sink_id, std::move(session)));
168 session->Start();
169 }
170
171 void DisplaySourceCustomBindings::TerminateSession(
172 const v8::FunctionCallbackInfo<v8::Value>& args) {
173 CHECK_EQ(2, args.Length());
174 CHECK(args[0]->IsInt32());
175 CHECK(args[1]->IsNull() || args[1]->IsFunction());
176
177 v8::Isolate* isolate = context()->isolate();
178 v8::Global<v8::Function> terminate_callback;
179 if (!args[1]->IsNull())
180 terminate_callback.Reset(isolate, args[1].As<v8::Function>());
181
182 int sink_id = args[0]->ToInt32(args.GetIsolate())->Value();
183 DisplaySourceSession* session = GetDisplaySession(sink_id);
184 if (!session) {
185 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
186 isolate, kSessionNotFound)));
187 return;
188 }
189
190 if (session->state() == DisplaySourceSession::Terminating) {
191 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
192 isolate, kSessionAlreadyTerminating)));
193 return;
194 }
195
196 if (!terminate_callback.IsEmpty()) {
197 CHECK(terminate_callback_map_.find(sink_id) ==
198 terminate_callback_map_.end());
199 terminate_callback_map_.insert(
200 std::make_pair(sink_id, std::move(terminate_callback)));
201 }
202
203 session->Terminate();
204 }
205
206 void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const {
207 v8::Isolate* isolate = context()->isolate();
208 v8::HandleScope handle_scope(isolate);
209 v8::Context::Scope context_scope(context()->v8_context());
210 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
211 event_args->Set(0, v8::Integer::New(isolate, sink_id));
212 context()->DispatchEvent("displaySource.onSessionStarted", event_args);
213 }
214
215 void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const {
216 v8::Isolate* isolate = context()->isolate();
217 v8::HandleScope handle_scope(isolate);
218 v8::Context::Scope context_scope(context()->v8_context());
219 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1);
220 event_args->Set(0, v8::Integer::New(isolate, sink_id));
221 context()->DispatchEvent("displaySource.onSessionTerminated", event_args);
222 }
223
224 void DisplaySourceCustomBindings::DispatchSessionError(
225 int sink_id,
226 DisplaySourceErrorType type,
227 const std::string& message) const {
228 v8::Isolate* isolate = context()->isolate();
229 v8::HandleScope handle_scope(isolate);
230 v8::Context::Scope context_scope(context()->v8_context());
231
232 api::display_source::ErrorInfo error_info;
233 error_info.type = type;
234 if (!message.empty())
235 error_info.description.reset(new std::string(message));
236
237 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
238 v8::Local<v8::Value> info_arg =
239 converter->ToV8Value(error_info.ToValue().get(),
240 context()->v8_context());
241
242 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2);
243 event_args->Set(0, v8::Integer::New(isolate, sink_id));
244 event_args->Set(1, info_arg);
245 context()->DispatchEvent("displaySource.onSessionErrorOccured", event_args);
246 }
247
248 DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession(
249 int sink_id) const {
250 auto iter = session_map_.find(sink_id);
251 if (iter != session_map_.end())
252 return iter->second.get();
253 return nullptr;
254 }
255
256 void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) {
257 DispatchSessionStarted(sink_id);
258 }
259
260 void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) {
261 DisplaySourceSession* session = GetDisplaySession(sink_id);
262 CHECK(session);
263 session_map_.erase(sink_id);
264
265 // Call a termination callback if needed.
266 auto iter = terminate_callback_map_.find(sink_id);
267 if (iter != terminate_callback_map_.end()) {
268 v8::Isolate* isolate = context()->isolate();
269 v8::Local<v8::Value> callback_args[1];
270 callback_args[0] = v8::Integer::New(isolate, sink_id);
271 context()->CallFunction(
272 v8::Local<v8::Function>::New(isolate, iter->second), 1,
273 callback_args);
274 terminate_callback_map_.erase(iter);
275 }
276
277 DispatchSessionTerminated(sink_id);
278 }
279
280 void DisplaySourceCustomBindings::OnSessionError(int sink_id,
281 DisplaySourceErrorType type,
282 const std::string& message) {
283 DisplaySourceSession* session = GetDisplaySession(sink_id);
284 CHECK(session);
285 if (session->state() == DisplaySourceSession::Establishing) {
286 // Error has occured before the session has actually started.
287 session_map_.erase(sink_id);
288 }
289
290 DispatchSessionError(sink_id, type, message);
291 }
292
293 } // extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698