OLD | NEW |
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 <algorithm> |
10 #include <set> | 10 #include <set> |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 const char kEnableAutoThrottlingKey[] = "enableAutoThrottling"; | 68 const char kEnableAutoThrottlingKey[] = "enableAutoThrottling"; |
69 | 69 |
70 bool OptionsSpecifyAudioOrVideo(const TabCapture::CaptureOptions& options) { | 70 bool OptionsSpecifyAudioOrVideo(const TabCapture::CaptureOptions& options) { |
71 return (options.audio && *options.audio) || (options.video && *options.video); | 71 return (options.audio && *options.audio) || (options.video && *options.video); |
72 } | 72 } |
73 | 73 |
74 bool IsAcceptableOffscreenTabUrl(const GURL& url) { | 74 bool IsAcceptableOffscreenTabUrl(const GURL& url) { |
75 return url.is_valid() && (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs("data")); | 75 return url.is_valid() && (url.SchemeIsHTTPOrHTTPS() || url.SchemeIs("data")); |
76 } | 76 } |
77 | 77 |
| 78 // Removes all mandatory and optional constraint entries that start with the |
| 79 // "goog" prefix. These are never needed and may cause the renderer-side |
| 80 // getUserMedia() call to fail. http://crbug.com/579729 |
| 81 // |
| 82 // TODO(miu): Remove once tabCapture API is migrated to new constraints spec. |
| 83 // http://crbug.com/579729 |
| 84 void FilterDeprecatedGoogConstraints(TabCapture::CaptureOptions* options) { |
| 85 const auto FilterGoogKeysFromDictionary = [](base::DictionaryValue* dict) { |
| 86 std::vector<std::string> bad_keys; |
| 87 base::DictionaryValue::Iterator it(*dict); |
| 88 for (; !it.IsAtEnd(); it.Advance()) { |
| 89 if (it.key().find("goog") == 0) |
| 90 bad_keys.push_back(it.key()); |
| 91 } |
| 92 for (const std::string& k : bad_keys) { |
| 93 scoped_ptr<base::Value> ignored; |
| 94 dict->RemoveWithoutPathExpansion(k, &ignored); |
| 95 } |
| 96 }; |
| 97 |
| 98 if (options->audio_constraints) { |
| 99 FilterGoogKeysFromDictionary( |
| 100 &options->audio_constraints->mandatory.additional_properties); |
| 101 if (options->audio_constraints->optional) { |
| 102 FilterGoogKeysFromDictionary( |
| 103 &options->audio_constraints->optional->additional_properties); |
| 104 } |
| 105 } |
| 106 |
| 107 if (options->video_constraints) { |
| 108 FilterGoogKeysFromDictionary( |
| 109 &options->video_constraints->mandatory.additional_properties); |
| 110 if (options->video_constraints->optional) { |
| 111 FilterGoogKeysFromDictionary( |
| 112 &options->video_constraints->optional->additional_properties); |
| 113 } |
| 114 } |
| 115 } |
| 116 |
78 // Add Chrome-specific source identifiers to the MediaStreamConstraints objects | 117 // Add Chrome-specific source identifiers to the MediaStreamConstraints objects |
79 // in |options| to provide references to the |target_contents| to be captured. | 118 // in |options| to provide references to the |target_contents| to be captured. |
80 void AddMediaStreamSourceConstraints(content::WebContents* target_contents, | 119 void AddMediaStreamSourceConstraints(content::WebContents* target_contents, |
81 TabCapture::CaptureOptions* options) { | 120 TabCapture::CaptureOptions* options) { |
82 DCHECK(options); | 121 DCHECK(options); |
83 DCHECK(target_contents); | 122 DCHECK(target_contents); |
84 | 123 |
85 MediaStreamConstraint* constraints_to_modify[2] = { nullptr, nullptr }; | 124 MediaStreamConstraint* constraints_to_modify[2] = { nullptr, nullptr }; |
86 | 125 |
87 if (options->audio && *options->audio) { | 126 if (options->audio && *options->audio) { |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 return false; | 240 return false; |
202 } | 241 } |
203 | 242 |
204 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); | 243 TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); |
205 if (!registry->AddRequest(target_contents, extension_id, false)) { | 244 if (!registry->AddRequest(target_contents, extension_id, false)) { |
206 // TODO(miu): Allow multiple consumers of single tab capture. | 245 // TODO(miu): Allow multiple consumers of single tab capture. |
207 // http://crbug.com/535336 | 246 // http://crbug.com/535336 |
208 error_ = kCapturingSameTab; | 247 error_ = kCapturingSameTab; |
209 return false; | 248 return false; |
210 } | 249 } |
| 250 FilterDeprecatedGoogConstraints(¶ms->options); |
211 AddMediaStreamSourceConstraints(target_contents, ¶ms->options); | 251 AddMediaStreamSourceConstraints(target_contents, ¶ms->options); |
212 | 252 |
213 // At this point, everything is set up in the browser process. It's now up to | 253 // At this point, everything is set up in the browser process. It's now up to |
214 // the custom JS bindings in the extension's render process to request a | 254 // the custom JS bindings in the extension's render process to request a |
215 // MediaStream using navigator.webkitGetUserMedia(). The result dictionary, | 255 // MediaStream using navigator.webkitGetUserMedia(). The result dictionary, |
216 // passed to SetResult() here, contains the extra "hidden options" that will | 256 // passed to SetResult() here, contains the extra "hidden options" that will |
217 // allow the Chrome platform implementation for getUserMedia() to start the | 257 // allow the Chrome platform implementation for getUserMedia() to start the |
218 // virtual audio/video capture devices and set up all the data flows. The | 258 // virtual audio/video capture devices and set up all the data flows. The |
219 // custom JS bindings can be found here: | 259 // custom JS bindings can be found here: |
220 // chrome/renderer/resources/extensions/tab_capture_custom_bindings.js | 260 // chrome/renderer/resources/extensions/tab_capture_custom_bindings.js |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 return false; | 319 return false; |
280 } | 320 } |
281 | 321 |
282 if (!TabCaptureRegistry::Get(browser_context())->AddRequest( | 322 if (!TabCaptureRegistry::Get(browser_context())->AddRequest( |
283 offscreen_tab->web_contents(), extension()->id(), true)) { | 323 offscreen_tab->web_contents(), extension()->id(), true)) { |
284 // TODO(miu): Allow multiple consumers of single tab capture. | 324 // TODO(miu): Allow multiple consumers of single tab capture. |
285 // http://crbug.com/535336 | 325 // http://crbug.com/535336 |
286 SetError(kCapturingSameOffscreenTab); | 326 SetError(kCapturingSameOffscreenTab); |
287 return false; | 327 return false; |
288 } | 328 } |
| 329 FilterDeprecatedGoogConstraints(¶ms->options); |
289 AddMediaStreamSourceConstraints(offscreen_tab->web_contents(), | 330 AddMediaStreamSourceConstraints(offscreen_tab->web_contents(), |
290 ¶ms->options); | 331 ¶ms->options); |
291 | 332 |
292 // At this point, everything is set up in the browser process. It's now up to | 333 // At this point, everything is set up in the browser process. It's now up to |
293 // the custom JS bindings in the extension's render process to complete the | 334 // the custom JS bindings in the extension's render process to complete the |
294 // request. See the comment at end of TabCaptureCaptureFunction::RunSync() | 335 // request. See the comment at end of TabCaptureCaptureFunction::RunSync() |
295 // for more details. | 336 // for more details. |
296 base::DictionaryValue* const result = new base::DictionaryValue(); | 337 base::DictionaryValue* const result = new base::DictionaryValue(); |
297 result->MergeDictionary(params->options.ToValue().get()); | 338 result->MergeDictionary(params->options.ToValue().get()); |
298 SetResult(result); | 339 SetResult(result); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 } | 383 } |
343 } | 384 } |
344 | 385 |
345 // No maximum size was provided, so just return the default size bounded by | 386 // No maximum size was provided, so just return the default size bounded by |
346 // the minimum size. | 387 // the minimum size. |
347 return gfx::Size(std::max(kDefaultWidth, min_size.width()), | 388 return gfx::Size(std::max(kDefaultWidth, min_size.width()), |
348 std::max(kDefaultHeight, min_size.height())); | 389 std::max(kDefaultHeight, min_size.height())); |
349 } | 390 } |
350 | 391 |
351 } // namespace extensions | 392 } // namespace extensions |
OLD | NEW |