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 kInvalidStreamArgs[] = "Invalid stream arguments"; | |
22 const char kSessionAlreadyStarted[] = "The session has been already started"; | |
23 const char kSessionAlreadyTerminating[] = "The session is already terminating"; | |
24 const char kSessionNotFound[] = "Session not found"; | |
25 } // namespace | |
26 | |
27 DisplaySourceCustomBindings::DisplaySourceCustomBindings(ScriptContext* context) | |
28 : ObjectBackedNativeHandler(context), | |
29 weak_factory_(this) { | |
30 RouteFunction("StartSession", | |
31 base::Bind(&DisplaySourceCustomBindings::StartSession, | |
32 weak_factory_.GetWeakPtr())); | |
33 RouteFunction("TerminateSession", | |
34 base::Bind(&DisplaySourceCustomBindings::TerminateSession, | |
35 weak_factory_.GetWeakPtr())); | |
36 } | |
37 | |
38 DisplaySourceCustomBindings::~DisplaySourceCustomBindings() { | |
39 } | |
40 | |
41 void DisplaySourceCustomBindings::Invalidate() { | |
42 session_map_.clear(); | |
43 weak_factory_.InvalidateWeakPtrs(); | |
44 ObjectBackedNativeHandler::Invalidate(); | |
45 } | |
46 | |
47 namespace { | |
48 | |
49 v8::Local<v8::Value> GetChildValue(v8::Local<v8::Object> value, | |
50 const std::string& key_name, | |
51 v8::Isolate* isolate) { | |
52 v8::Local<v8::Array> property_names(value->GetOwnPropertyNames()); | |
53 for (uint32 i = 0; i < property_names->Length(); ++i) { | |
54 v8::Local<v8::Value> key(property_names->Get(i)); | |
55 if (key_name == *v8::String::Utf8Value(key)) { | |
56 v8::TryCatch try_catch(isolate); | |
57 v8::Local<v8::Value> child_v8 = value->Get(key); | |
58 if (try_catch.HasCaught()) { | |
59 return v8::Null(isolate); | |
60 } | |
61 return child_v8; | |
62 } | |
63 } | |
64 | |
65 return v8::Null(isolate); | |
66 } | |
67 | |
68 } // namespace | |
69 | |
70 void DisplaySourceCustomBindings::StartSession( | |
71 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
72 CHECK_EQ(1, args.Length()); | |
73 CHECK(args[0]->IsObject()); | |
74 v8::Isolate* isolate = context()->isolate(); | |
75 v8::Local<v8::Object> start_info = args[0].As<v8::Object>(); | |
76 | |
77 v8::Local<v8::Value> sink_id_val = | |
78 GetChildValue(start_info, "sinkId", isolate); | |
79 CHECK(sink_id_val->IsInt32()); | |
80 const int sink_id = sink_id_val->ToInt32(isolate)->Value(); | |
81 if (GetDisplaySession(sink_id)) { | |
82 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | |
83 isolate, kSessionAlreadyStarted))); | |
84 return; | |
85 } | |
86 | |
87 v8::Local<v8::Value> video_stream_val = | |
88 GetChildValue(start_info, "videoTrack", isolate); | |
89 v8::Local<v8::Value> audio_stream_val = | |
90 GetChildValue(start_info, "audioTrack", isolate); | |
91 | |
92 if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) && | |
93 (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) { | |
94 isolate->ThrowException(v8::Exception::Error( | |
95 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | |
96 return; | |
97 } | |
98 | |
99 blink::WebMediaStreamTrack audio_track, video_track; | |
100 | |
101 if (!video_stream_val->IsNull() && !video_stream_val->IsUndefined()) { | |
102 CHECK(video_stream_val->IsObject()); | |
103 video_track = | |
104 blink::WebDOMMediaStreamTrack::fromV8Value( | |
105 video_stream_val).component(); | |
106 if (video_track.isNull()) { | |
107 isolate->ThrowException(v8::Exception::Error( | |
108 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | |
109 return; | |
110 } | |
111 } | |
112 if (!audio_stream_val->IsNull() && !audio_stream_val->IsUndefined()) { | |
113 CHECK(audio_stream_val->IsObject()); | |
114 audio_track = | |
115 blink::WebDOMMediaStreamTrack::fromV8Value( | |
116 audio_stream_val).component(); | |
117 if (audio_track.isNull()) { | |
118 isolate->ThrowException(v8::Exception::Error( | |
119 v8::String::NewFromUtf8(isolate, kInvalidStreamArgs))); | |
120 return; | |
121 } | |
122 } | |
123 | |
124 scoped_ptr<DisplaySourceAuthInfo> auth_info; | |
125 v8::Local<v8::Value> auth_info_v8_val = | |
126 GetChildValue(start_info, "authenticationInfo", isolate); | |
127 if (!auth_info_v8_val->IsNull()) { | |
128 CHECK(auth_info_v8_val->IsObject()); | |
129 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | |
130 scoped_ptr<base::Value> auth_info_val( | |
131 converter->FromV8Value(auth_info_v8_val, context()->v8_context())); | |
132 CHECK(auth_info_val); | |
133 auth_info = DisplaySourceAuthInfo::FromValue(*auth_info_val); | |
134 } | |
135 | |
136 scoped_ptr<DisplaySourceSession> session = | |
137 DisplaySourceSessionFactory::CreateSession( | |
138 sink_id, video_track, audio_track, std::move(auth_info)); | |
139 if (!session) { | |
140 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | |
141 isolate, kErrorNotSupported))); | |
142 return; | |
143 } | |
144 | |
145 auto on_started_callback = base::Bind( | |
146 &DisplaySourceCustomBindings::OnSessionStarted, | |
147 weak_factory_.GetWeakPtr()); | |
148 auto on_terminated_callback = base::Bind( | |
149 &DisplaySourceCustomBindings::OnSessionTerminated, | |
150 weak_factory_.GetWeakPtr()); | |
151 auto on_error_callback = base::Bind( | |
152 &DisplaySourceCustomBindings::OnSessionError, | |
153 weak_factory_.GetWeakPtr()); | |
154 session->SetCallbacks(on_started_callback, | |
155 on_terminated_callback, | |
156 on_error_callback); | |
157 session_map_.insert(std::make_pair(sink_id, std::move(session))); | |
158 session->Start(); | |
159 } | |
160 | |
161 void DisplaySourceCustomBindings::TerminateSession( | |
162 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
163 CHECK_EQ(1, args.Length()); | |
164 CHECK(args[0]->IsInt32()); | |
165 | |
166 v8::Isolate* isolate = context()->isolate(); | |
167 int sink_id = args[0]->ToInt32(args.GetIsolate())->Value(); | |
168 DisplaySourceSession* session = GetDisplaySession(sink_id); | |
169 if (!session) { | |
170 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | |
171 isolate, kSessionNotFound))); | |
172 return; | |
173 } | |
174 | |
175 if (session->state() == DisplaySourceSession::Terminating) { | |
176 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8( | |
177 isolate, kSessionAlreadyTerminating))); | |
178 return; | |
179 } | |
180 | |
181 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.
| |
182 } | |
183 | |
184 void DisplaySourceCustomBindings::DispatchSessionStarted(int sink_id) const { | |
185 v8::Isolate* isolate = context()->isolate(); | |
186 v8::HandleScope handle_scope(isolate); | |
187 v8::Context::Scope context_scope(context()->v8_context()); | |
188 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1); | |
189 event_args->Set(0, v8::Integer::New(isolate, sink_id)); | |
190 context()->DispatchEvent("displaySource.onSessionStarted", event_args); | |
191 } | |
192 | |
193 void DisplaySourceCustomBindings::DispatchSessionTerminated(int sink_id) const { | |
194 v8::Isolate* isolate = context()->isolate(); | |
195 v8::HandleScope handle_scope(isolate); | |
196 v8::Context::Scope context_scope(context()->v8_context()); | |
197 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 1); | |
198 event_args->Set(0, v8::Integer::New(isolate, sink_id)); | |
199 context()->DispatchEvent("displaySource.onSessionTerminated", event_args); | |
200 } | |
201 | |
202 void DisplaySourceCustomBindings::DispatchSessionError( | |
203 int sink_id, | |
204 DisplaySourceErrorType type, | |
205 const std::string& message) const { | |
206 v8::Isolate* isolate = context()->isolate(); | |
207 v8::HandleScope handle_scope(isolate); | |
208 v8::Context::Scope context_scope(context()->v8_context()); | |
209 | |
210 api::display_source::ErrorInfo error_info; | |
211 error_info.type = type; | |
212 if (!message.empty()) | |
213 error_info.description.reset(new std::string(message)); | |
214 | |
215 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); | |
216 v8::Local<v8::Value> info_arg = | |
217 converter->ToV8Value(error_info.ToValue().get(), | |
218 context()->v8_context()); | |
219 | |
220 v8::Local<v8::Array> event_args = v8::Array::New(isolate, 2); | |
221 event_args->Set(0, v8::Integer::New(isolate, sink_id)); | |
222 event_args->Set(1, info_arg); | |
223 context()->DispatchEvent("displaySource.onSessionErrorOccured", event_args); | |
224 } | |
225 | |
226 DisplaySourceSession* DisplaySourceCustomBindings::GetDisplaySession( | |
227 int sink_id) const { | |
228 auto iter = session_map_.find(sink_id); | |
229 if (iter != session_map_.end()) | |
230 return iter->second.get(); | |
231 return nullptr; | |
232 } | |
233 | |
234 void DisplaySourceCustomBindings::OnSessionStarted(int sink_id) { | |
235 DispatchSessionStarted(sink_id); | |
236 } | |
237 | |
238 void DisplaySourceCustomBindings::OnSessionTerminated(int sink_id) { | |
239 DisplaySourceSession* session = GetDisplaySession(sink_id); | |
240 CHECK(session); | |
241 session_map_.erase(sink_id); | |
242 DispatchSessionTerminated(sink_id); | |
243 } | |
244 | |
245 void DisplaySourceCustomBindings::OnSessionError(int sink_id, | |
246 DisplaySourceErrorType type, | |
247 const std::string& message) { | |
248 DisplaySourceSession* session = GetDisplaySession(sink_id); | |
249 CHECK(session); | |
250 if (session->state() == DisplaySourceSession::Establishing) { | |
251 // Error has occured before the session has actually started. | |
252 session_map_.erase(sink_id); | |
253 } | |
254 | |
255 DispatchSessionError(sink_id, type, message); | |
256 } | |
257 | |
258 } // extensions | |
OLD | NEW |