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

Side by Side Diff: chrome/browser/extensions/api/tab_capture/tab_capture_api.cc

Issue 1221483002: New tabCapture.captureOffscreenTab API, initially for Presentation API 1UA mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Register off-screen tabs as presentations via separate private API. Created 5 years, 2 months 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Implements the Chrome Extensions Tab Capture API. 5 // Implements the Chrome Extensions Tab Capture API.
6 6
7 #include "chrome/browser/extensions/api/tab_capture/tab_capture_api.h" 7 #include "chrome/browser/extensions/api/tab_capture/tab_capture_api.h"
8 8
9 #include <algorithm>
9 #include <set> 10 #include <set>
10 #include <string> 11 #include <string>
11 #include <vector> 12 #include <vector>
12 13
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
15 #include "base/values.h" 16 #include "base/values.h"
17 #include "chrome/browser/extensions/api/tab_capture/offscreen_presentation.h"
16 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" 18 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
17 #include "chrome/browser/extensions/extension_renderer_state.h" 19 #include "chrome/browser/extensions/extension_renderer_state.h"
18 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/sessions/session_tab_helper.h" 21 #include "chrome/browser/sessions/session_tab_helper.h"
20 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_finder.h" 23 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/chrome_switches.h"
23 #include "content/public/browser/render_frame_host.h" 26 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/render_process_host.h" 27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/web_contents.h"
25 #include "extensions/common/features/feature.h" 29 #include "extensions/common/features/feature.h"
26 #include "extensions/common/features/feature_provider.h" 30 #include "extensions/common/features/feature_provider.h"
27 #include "extensions/common/features/simple_feature.h" 31 #include "extensions/common/features/simple_feature.h"
28 #include "extensions/common/permissions/permissions_data.h" 32 #include "extensions/common/permissions/permissions_data.h"
29 #include "extensions/common/switches.h" 33 #include "extensions/common/switches.h"
30 34
31 using extensions::api::tab_capture::MediaStreamConstraint; 35 using extensions::api::tab_capture::MediaStreamConstraint;
32 36
33 namespace TabCapture = extensions::api::tab_capture; 37 namespace TabCapture = extensions::api::tab_capture;
34 namespace GetCapturedTabs = TabCapture::GetCapturedTabs; 38 namespace GetCapturedTabs = TabCapture::GetCapturedTabs;
35 39
36 namespace extensions { 40 namespace extensions {
37 namespace { 41 namespace {
38 42
39 const char kCapturingSameTab[] = "Cannot capture a tab with an active stream."; 43 const char kCapturingSameTab[] = "Cannot capture a tab with an active stream.";
40 const char kFindingTabError[] = "Error finding tab to capture."; 44 const char kFindingTabError[] = "Error finding tab to capture.";
41 const char kNoAudioOrVideo[] = "Capture failed. No audio or video requested."; 45 const char kNoAudioOrVideo[] = "Capture failed. No audio or video requested.";
42 const char kGrantError[] = 46 const char kGrantError[] =
43 "Extension has not been invoked for the current page (see activeTab " 47 "Extension has not been invoked for the current page (see activeTab "
44 "permission). Chrome pages cannot be captured."; 48 "permission). Chrome pages cannot be captured.";
45 49
46 // Keys/values for media stream constraints. 50 const char kNotWhitelistedForOffscreenTabApi[] =
51 "Extension is not whitelisted for use of the unstable, in-development "
52 "chrome.tabCapture.captureOffscreenTab API.";
53 const char kInvalidStartUrl[] =
54 "Invalid/Missing/Malformatted starting URL for off-screen tab.";
55 const char kMissingExtensionPage[] =
56 "tabCapture API was not invoked from an extension background page.";
57 const char kTooManyOffscreenTabs[] =
58 "Extension has already started too many off-screen tabs.";
59 const char kCapturingSameOffscreenTab[] =
60 "Cannot capture the same off-screen tab more than once.";
61
62 const char kOffscreenTabNotFound[] =
63 "ID does not reference any currently-alive off-screen tab.";
64
65 // Keys/values passed to renderer-side JS bindings.
47 const char kMediaStreamSource[] = "chromeMediaSource"; 66 const char kMediaStreamSource[] = "chromeMediaSource";
48 const char kMediaStreamSourceId[] = "chromeMediaSourceId"; 67 const char kMediaStreamSourceId[] = "chromeMediaSourceId";
49 const char kMediaStreamSourceTab[] = "tab"; 68 const char kMediaStreamSourceTab[] = "tab";
69 const char kOffscreenTabIdKey[] = "offscreenTabId";
50 70
51 // Tab Capture-specific video constraint to enable automatic resolution/rate 71 // Tab Capture-specific video constraint to enable automatic resolution/rate
52 // throttling mode in the capture pipeline. 72 // throttling mode in the capture pipeline.
53 const char kEnableAutoThrottlingKey[] = "enableAutoThrottling"; 73 const char kEnableAutoThrottlingKey[] = "enableAutoThrottling";
54 74
75 bool OptionsSpecifyAudioOrVideo(const TabCapture::CaptureOptions& options) {
76 return (options.audio && *options.audio) || (options.video && *options.video);
77 }
78
79 bool IsAcceptableOffscreenTabUrl(const GURL& url) {
80 return url.is_valid() && (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs("data"));
81 }
82
83 // Add Chrome-specific source identifiers to the MediaStreamConstraints objects
84 // in |options| to provide references to the |target_contents| to be captured.
85 void AddMediaStreamSourceConstraints(content::WebContents* target_contents,
86 TabCapture::CaptureOptions* options) {
87 DCHECK(options);
88 DCHECK(target_contents);
89
90 MediaStreamConstraint* constraints_to_modify[2] = { nullptr, nullptr };
91
92 if (options->audio && *options->audio) {
93 if (!options->audio_constraints)
94 options->audio_constraints.reset(new MediaStreamConstraint);
95 constraints_to_modify[0] = options->audio_constraints.get();
96 }
97
98 bool enable_auto_throttling = false;
99 if (options->video && *options->video) {
100 if (options->video_constraints) {
101 // Check for the Tab Capture-specific video constraint for enabling
102 // automatic resolution/rate throttling mode in the capture pipeline. See
103 // implementation comments for content::WebContentsVideoCaptureDevice.
104 base::DictionaryValue& props =
105 options->video_constraints->mandatory.additional_properties;
106 if (!props.GetBooleanWithoutPathExpansion(
107 kEnableAutoThrottlingKey, &enable_auto_throttling)) {
108 enable_auto_throttling = false;
109 }
110 // Remove the key from the properties to avoid an "unrecognized
111 // constraint" error in the renderer.
112 props.RemoveWithoutPathExpansion(kEnableAutoThrottlingKey, nullptr);
113 } else {
114 options->video_constraints.reset(new MediaStreamConstraint);
115 }
116 constraints_to_modify[1] = options->video_constraints.get();
117 }
118
119 // Format the device ID that references the target tab.
120 content::RenderFrameHost* const main_frame = target_contents->GetMainFrame();
121 // TODO(miu): We should instead use a "randomly generated device ID" scheme,
122 // like that employed by the desktop capture API. http://crbug.com/163100
123 const std::string device_id = base::StringPrintf(
124 "web-contents-media-stream://%i:%i%s",
125 main_frame->GetProcess()->GetID(),
126 main_frame->GetRoutingID(),
127 enable_auto_throttling ? "?throttling=auto" : "");
128
129 // Append chrome specific tab constraints.
130 for (MediaStreamConstraint* msc : constraints_to_modify) {
131 if (!msc)
132 continue;
133 base::DictionaryValue* constraint = &msc->mandatory.additional_properties;
134 constraint->SetString(kMediaStreamSource, kMediaStreamSourceTab);
135 constraint->SetString(kMediaStreamSourceId, device_id);
136 }
137 }
138
55 } // namespace 139 } // namespace
56 140
57 // Whitelisted extensions that do not check for a browser action grant because 141 // Whitelisted extensions that do not check for a browser action grant because
58 // they provide API's. If there are additional extension ids that need 142 // they provide API's. If there are additional extension ids that need
59 // whitelisting and are *not* the Chromecast extension, add them to a new 143 // whitelisting and are *not* the Chromecast extension, add them to a new
60 // kWhitelist array. 144 // kWhitelist array.
61 // 145 //
62 // This list is also used by CastConfigDelegateChromeos to find official Cast 146 // This list is also used by CastConfigDelegateChromeos to find official Cast
63 // extensions. 147 // extensions.
64 const char* const kChromecastExtensionIds[] = { 148 const char* const kChromecastExtensionIds[] = {
65 "enhhojjnijigcajfphajepfemndkmdlo", // Dev 149 "enhhojjnijigcajfphajepfemndkmdlo", // Dev
66 "fmfcbgogabcbclcofgocippekhfcmgfj", // Staging 150 "fmfcbgogabcbclcofgocippekhfcmgfj", // Staging
67 "hfaagokkkhdbgiakmmlclaapfelnkoah", // Canary 151 "hfaagokkkhdbgiakmmlclaapfelnkoah", // Canary
68 "dliochdbjfkdbacpmhlcpmleaejidimm", // Google Cast Beta 152 "dliochdbjfkdbacpmhlcpmleaejidimm", // Google Cast Beta
69 "boadgeojelhgndaghljhdicfkmllpafd", // Google Cast Stable 153 "boadgeojelhgndaghljhdicfkmllpafd", // Google Cast Stable
70 "hlgmmjhlnlapooncikdpiiokdjcdpjme", // Test cast extension 154 "hlgmmjhlnlapooncikdpiiokdjcdpjme", // Test cast extension
71 }; 155 };
72 156
73 const char* const kMediaRouterExtensionIds[] = { 157 const char* const kMediaRouterExtensionIds[] = {
74 "fjhoaacokmgbjemoflkofnenfaiekifl", // Stable 158 "fjhoaacokmgbjemoflkofnenfaiekifl", // Stable
75 "ekpaaapppgpmolpcldedioblbkmijaca", // Beta 159 "ekpaaapppgpmolpcldedioblbkmijaca", // Beta
76 }; 160 };
77 161
78 bool TabCaptureCaptureFunction::RunSync() { 162 bool TabCaptureCaptureFunction::RunSync() {
79 scoped_ptr<api::tab_capture::Capture::Params> params = 163 scoped_ptr<api::tab_capture::Capture::Params> params =
80 TabCapture::Capture::Params::Create(*args_); 164 TabCapture::Capture::Params::Create(*args_);
81 EXTENSION_FUNCTION_VALIDATE(params.get()); 165 EXTENSION_FUNCTION_VALIDATE(params);
82 166
83 // Figure out the active WebContents and retrieve the needed ids. 167 // Figure out the active WebContents and retrieve the needed ids.
84 Browser* target_browser = chrome::FindAnyBrowser( 168 Browser* target_browser = chrome::FindAnyBrowser(
85 GetProfile(), include_incognito(), chrome::GetActiveDesktop()); 169 GetProfile(), include_incognito(), chrome::GetActiveDesktop());
86 if (!target_browser) { 170 if (!target_browser) {
87 error_ = kFindingTabError; 171 error_ = kFindingTabError;
88 return false; 172 return false;
89 } 173 }
90 174
91 content::WebContents* target_contents = 175 content::WebContents* target_contents =
(...skipping 13 matching lines...) Expand all
105 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 189 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
106 switches::kWhitelistedExtensionID) != extension_id && 190 switches::kWhitelistedExtensionID) != extension_id &&
107 !SimpleFeature::IsIdInArray(extension_id, kChromecastExtensionIds, 191 !SimpleFeature::IsIdInArray(extension_id, kChromecastExtensionIds,
108 arraysize(kChromecastExtensionIds)) && 192 arraysize(kChromecastExtensionIds)) &&
109 !SimpleFeature::IsIdInArray(extension_id, kMediaRouterExtensionIds, 193 !SimpleFeature::IsIdInArray(extension_id, kMediaRouterExtensionIds,
110 arraysize(kMediaRouterExtensionIds))) { 194 arraysize(kMediaRouterExtensionIds))) {
111 error_ = kGrantError; 195 error_ = kGrantError;
112 return false; 196 return false;
113 } 197 }
114 198
115 // Create a constraints vector. We will modify all the constraints in this 199 if (!OptionsSpecifyAudioOrVideo(params->options)) {
116 // vector to append our chrome specific constraints.
117 std::vector<MediaStreamConstraint*> constraints;
118 bool has_audio = params->options.audio.get() && *params->options.audio.get();
119 bool has_video = params->options.video.get() && *params->options.video.get();
120
121 if (!has_audio && !has_video) {
122 error_ = kNoAudioOrVideo; 200 error_ = kNoAudioOrVideo;
123 return false; 201 return false;
124 } 202 }
125 203
126 if (has_audio) {
127 if (!params->options.audio_constraints.get())
128 params->options.audio_constraints.reset(new MediaStreamConstraint);
129
130 constraints.push_back(params->options.audio_constraints.get());
131 }
132
133 bool enable_auto_throttling = false;
134 if (has_video) {
135 if (params->options.video_constraints.get()) {
136 // Check for the Tab Capture-specific video constraint for enabling
137 // automatic resolution/rate throttling mode in the capture pipeline. See
138 // implementation comments for content::WebContentsVideoCaptureDevice.
139 base::DictionaryValue& props =
140 params->options.video_constraints->mandatory.additional_properties;
141 if (!props.GetBooleanWithoutPathExpansion(
142 kEnableAutoThrottlingKey, &enable_auto_throttling)) {
143 enable_auto_throttling = false;
144 }
145 // Remove the key from the properties to avoid an "unrecognized
146 // constraint" error in the renderer.
147 props.RemoveWithoutPathExpansion(kEnableAutoThrottlingKey, nullptr);
148 } else {
149 params->options.video_constraints.reset(new MediaStreamConstraint);
150 }
151
152 constraints.push_back(params->options.video_constraints.get());
153 }
154
155 // Device id we use for Tab Capture.
156 content::RenderFrameHost* const main_frame = target_contents->GetMainFrame();
157 // TODO(miu): We should instead use a "randomly generated device ID" scheme,
158 // like that employed by the desktop capture API. http://crbug.com/163100
159 const std::string device_id = base::StringPrintf(
160 "web-contents-media-stream://%i:%i%s",
161 main_frame->GetProcess()->GetID(),
162 main_frame->GetRoutingID(),
163 enable_auto_throttling ? "?throttling=auto" : "");
164
165 // Append chrome specific tab constraints.
166 for (std::vector<MediaStreamConstraint*>::iterator it = constraints.begin();
167 it != constraints.end(); ++it) {
168 base::DictionaryValue* constraint = &(*it)->mandatory.additional_properties;
169 constraint->SetString(kMediaStreamSource, kMediaStreamSourceTab);
170 constraint->SetString(kMediaStreamSourceId, device_id);
171 }
172
173 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); 204 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile());
174 if (!registry->AddRequest(target_contents, extension_id)) { 205 if (!registry->AddRequest(target_contents, extension_id, false)) {
206 // TODO(miu): Allow multiple consumers of single tab capture.
207 // http://crbug.com/535336
175 error_ = kCapturingSameTab; 208 error_ = kCapturingSameTab;
176 return false; 209 return false;
177 } 210 }
211 AddMediaStreamSourceConstraints(target_contents, &params->options);
178 212
179 // Copy the result from our modified input parameters. This will be 213 // At this point, everything is set up in the browser process. It's now up to
180 // intercepted by custom bindings which will build and send the special 214 // the custom JS bindings in the extension's render process to request a
181 // WebRTC user media request. 215 // MediaStream using navigator.webkitGetUserMedia(). The result dictionary,
216 // passed to SetResult() here, contains the extra "hidden options" that will
217 // allow the Chrome platform implementation for getUserMedia() to start the
218 // virtual audio/video capture devices and set up all the data flows. The
219 // custom JS bindings can be found here:
220 // chrome/renderer/resources/extensions/tab_capture_custom_bindings.js
182 base::DictionaryValue* result = new base::DictionaryValue(); 221 base::DictionaryValue* result = new base::DictionaryValue();
183 result->MergeDictionary(params->options.ToValue().get()); 222 result->MergeDictionary(params->options.ToValue().get());
184
185 SetResult(result); 223 SetResult(result);
186 return true; 224 return true;
187 } 225 }
188 226
189 bool TabCaptureGetCapturedTabsFunction::RunSync() { 227 bool TabCaptureGetCapturedTabsFunction::RunSync() {
190 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); 228 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile());
191 base::ListValue* const list = new base::ListValue(); 229 base::ListValue* const list = new base::ListValue();
192 if (registry) 230 if (registry)
193 registry->GetCapturedTabs(extension()->id(), list); 231 registry->GetCapturedTabs(extension()->id(), list);
194 SetResult(list); 232 SetResult(list);
195 return true; 233 return true;
196 } 234 }
197 235
236 bool TabCaptureCaptureOffscreenTabFunction::RunSync() {
237 scoped_ptr<TabCapture::CaptureOffscreenTab::Params> params =
238 TabCapture::CaptureOffscreenTab::Params::Create(*args_);
239 EXTENSION_FUNCTION_VALIDATE(params);
240
241 // Make sure the extension is whitelisted for using this API, or this is a
242 // Canary/Dev-channel build of Chrome.
243 //
244 // TODO(miu): Use _api_features.json and extensions::Feature library instead.
245 // http://crbug.com/537732
246 const bool is_whitelisted_extension =
247 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
248 switches::kWhitelistedExtensionID) == extension()->id() ||
249 SimpleFeature::IsIdInArray(extension()->id(), kChromecastExtensionIds,
250 arraysize(kChromecastExtensionIds)) ||
251 SimpleFeature::IsIdInArray(extension()->id(), kMediaRouterExtensionIds,
252 arraysize(kMediaRouterExtensionIds));
253 if (!is_whitelisted_extension) {
254 error_ = kNotWhitelistedForOffscreenTabApi;
255 return false;
256 }
257
258 const GURL start_url(params->start_url);
259 if (!IsAcceptableOffscreenTabUrl(start_url)) {
260 SetError(kInvalidStartUrl);
261 return false;
262 }
263
264 if (!OptionsSpecifyAudioOrVideo(params->options)) {
265 SetError(kNoAudioOrVideo);
266 return false;
267 }
268
269 content::WebContents* const extension_web_contents = GetSenderWebContents();
270 if (!extension_web_contents) {
271 SetError(kMissingExtensionPage);
272 return false;
273 }
274
275 OffscreenPresentation* const offscreen_tab =
276 OffscreenPresentationsOwner::Get(extension_web_contents)
277 ->StartPresentation(start_url,
278 DetermineInitialSize(params->options));
279 if (!offscreen_tab) {
280 SetError(kTooManyOffscreenTabs);
281 return false;
282 }
283
284 if (!TabCaptureRegistry::Get(browser_context())->AddRequest(
285 offscreen_tab->web_contents(), extension()->id(), true)) {
286 // TODO(miu): Allow multiple consumers of single tab capture.
287 // http://crbug.com/535336
288 SetError(kCapturingSameOffscreenTab);
289 return false;
290 }
291 AddMediaStreamSourceConstraints(offscreen_tab->web_contents(),
292 &params->options);
293
294 // At this point, everything is set up in the browser process. It's now up to
295 // the custom JS bindings in the extension's render process to complete the
296 // request. See the comment at end of TabCaptureCaptureFunction::RunSync()
297 // for more details.
298 base::DictionaryValue* const result = new base::DictionaryValue();
299 result->MergeDictionary(params->options.ToValue().get());
300 result->SetStringWithoutPathExpansion(kOffscreenTabIdKey,
301 offscreen_tab->id());
302 SetResult(result);
303 return true;
304 }
305
306 // static
307 gfx::Size TabCaptureCaptureOffscreenTabFunction::DetermineInitialSize(
308 const TabCapture::CaptureOptions& options) {
309 static const int kDefaultWidth = 1280;
310 static const int kDefaultHeight = 720;
311
312 if (!options.video_constraints)
313 return gfx::Size(kDefaultWidth, kDefaultHeight);
314
315 gfx::Size min_size;
316 int width = -1;
317 int height = -1;
318 const base::DictionaryValue& mandatory_properties =
319 options.video_constraints->mandatory.additional_properties;
320 if (mandatory_properties.GetInteger("maxWidth", &width) && width >= 0 &&
321 mandatory_properties.GetInteger("maxHeight", &height) && height >= 0) {
322 return gfx::Size(width, height);
323 }
324 if (mandatory_properties.GetInteger("minWidth", &width) && width >= 0 &&
325 mandatory_properties.GetInteger("minHeight", &height) && height >= 0) {
326 min_size.SetSize(width, height);
327 }
328
329 // Use optional size constraints if no mandatory ones were provided.
330 if (options.video_constraints->optional) {
331 const base::DictionaryValue& optional_properties =
332 options.video_constraints->optional->additional_properties;
333 if (optional_properties.GetInteger("maxWidth", &width) && width >= 0 &&
334 optional_properties.GetInteger("maxHeight", &height) && height >= 0) {
335 if (min_size.IsEmpty()) {
336 return gfx::Size(width, height);
337 } else {
338 return gfx::Size(std::max(width, min_size.width()),
339 std::max(height, min_size.height()));
340 }
341 }
342 if (min_size.IsEmpty() &&
343 optional_properties.GetInteger("minWidth", &width) && width >= 0 &&
344 optional_properties.GetInteger("minHeight", &height) && height >= 0) {
345 min_size.SetSize(width, height);
346 }
347 }
348
349 // No maximum size was provided, so just return the default size bounded by
350 // the minimum size.
351 return gfx::Size(std::max(kDefaultWidth, min_size.width()),
352 std::max(kDefaultHeight, min_size.height()));
353 }
354
355 bool TabCapturePrivateRegisterOffscreenTabAsPresentationFunction::RunSync() {
356 namespace TabCapturePrivate = extensions::api::tab_capture_private;
not at google - send to devlin 2015/10/02 01:17:26 already in extensions namespace, no extensions::
miu 2015/10/02 18:58:21 N/A, since reverting mostly back to PS6.
357 using Params = TabCapturePrivate::RegisterOffscreenTabAsPresentation::Params;
358 scoped_ptr<Params> params = Params::Create(*args_);
359 EXTENSION_FUNCTION_VALIDATE(params);
360
361 // Make sure the extension is whitelisted for using this API.
362 //
363 // TODO(miu): Use _api_features.json and extensions::Feature library instead.
364 // http://crbug.com/537732
365 const bool is_whitelisted_extension =
366 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
367 switches::kWhitelistedExtensionID) == extension()->id() ||
368 SimpleFeature::IsIdInArray(extension()->id(), kChromecastExtensionIds,
369 arraysize(kChromecastExtensionIds)) ||
370 SimpleFeature::IsIdInArray(extension()->id(), kMediaRouterExtensionIds,
371 arraysize(kMediaRouterExtensionIds));
372 if (!is_whitelisted_extension) {
373 error_ = kNotWhitelistedForOffscreenTabApi;
374 return false;
375 }
376
377 content::WebContents* const extension_web_contents = GetSenderWebContents();
not at google - send to devlin 2015/10/02 01:17:26 This API can only be called from extension pages,
miu 2015/10/02 18:58:21 Done in TabCaptureCaptureOffscreenTabFunction::Run
378 if (!extension_web_contents) {
379 SetError(kMissingExtensionPage);
380 return false;
381 }
382
383 OffscreenPresentation* const offscreen_tab =
384 OffscreenPresentationsOwner::Get(extension_web_contents)
385 ->FindByOffscreenTabId(params->offscreen_tab_id);
386 if (!offscreen_tab) {
387 SetError(kOffscreenTabNotFound);
388 return false;
389 }
390
391 // TODO(imcheng): Register offscreen_tab->web_contents() with the
392 // PresentationRouter. http://crbug.com/513859
393 LOG(ERROR) << "NOT IMPLEMENTED: Register with PresentationRouter, id="
not at google - send to devlin 2015/10/02 01:17:26 NOT_IMPLEMENTED()?
miu 2015/10/02 18:58:21 Done. (I had it as LOG(ERROR) to confirm the plum
394 << params->presentation_id;
395
396 return true;
397 }
398
198 } // namespace extensions 399 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698