OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "chrome/browser/media/webrtc_browsertest_base.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include "base/lazy_instance.h" | |
10 #include "base/macros.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/strings/stringprintf.h" | |
13 #include "build/build_config.h" | |
14 #include "chrome/browser/media/webrtc_browsertest_common.h" | |
15 #include "chrome/browser/permissions/permission_request_manager.h" | |
16 #include "chrome/browser/ui/browser.h" | |
17 #include "chrome/browser/ui/browser_tabstrip.h" | |
18 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
19 #include "chrome/test/base/ui_test_utils.h" | |
20 #include "content/public/test/browser_test_utils.h" | |
21 #include "net/test/embedded_test_server/embedded_test_server.h" | |
22 | |
23 #if defined(OS_WIN) | |
24 // For fine-grained suppression. | |
25 #include "base/win/windows_version.h" | |
26 #endif | |
27 | |
28 const char WebRtcTestBase::kAudioVideoCallConstraints[] = | |
29 "{audio: true, video: true}"; | |
30 const char WebRtcTestBase::kVideoCallConstraintsQVGA[] = | |
31 "{video: {mandatory: {minWidth: 320, maxWidth: 320, " | |
32 " minHeight: 240, maxHeight: 240}}}"; | |
33 const char WebRtcTestBase::kVideoCallConstraints360p[] = | |
34 "{video: {mandatory: {minWidth: 640, maxWidth: 640, " | |
35 " minHeight: 360, maxHeight: 360}}}"; | |
36 const char WebRtcTestBase::kVideoCallConstraintsVGA[] = | |
37 "{video: {mandatory: {minWidth: 640, maxWidth: 640, " | |
38 " minHeight: 480, maxHeight: 480}}}"; | |
39 const char WebRtcTestBase::kVideoCallConstraints720p[] = | |
40 "{video: {mandatory: {minWidth: 1280, maxWidth: 1280, " | |
41 " minHeight: 720, maxHeight: 720}}}"; | |
42 const char WebRtcTestBase::kVideoCallConstraints1080p[] = | |
43 "{video: {mandatory: {minWidth: 1920, maxWidth: 1920, " | |
44 " minHeight: 1080, maxHeight: 1080}}}"; | |
45 const char WebRtcTestBase::kAudioOnlyCallConstraints[] = "{audio: true}"; | |
46 const char WebRtcTestBase::kVideoOnlyCallConstraints[] = "{video: true}"; | |
47 const char WebRtcTestBase::kOkGotStream[] = "ok-got-stream"; | |
48 const char WebRtcTestBase::kFailedWithPermissionDeniedError[] = | |
49 "failed-with-error-PermissionDeniedError"; | |
50 const char WebRtcTestBase::kFailedWithPermissionDismissedError[] = | |
51 "failed-with-error-PermissionDismissedError"; | |
52 const char WebRtcTestBase::kAudioVideoCallConstraints360p[] = | |
53 "{audio: true, video: {mandatory: {minWidth: 640, maxWidth: 640, " | |
54 " minHeight: 360, maxHeight: 360}}}"; | |
55 const char WebRtcTestBase::kAudioVideoCallConstraints720p[] = | |
56 "{audio: true, video: {mandatory: {minWidth: 1280, maxWidth: 1280, " | |
57 " minHeight: 720, maxHeight: 720}}}"; | |
58 const char WebRtcTestBase::kUseDefaultCertKeygen[] = "null"; | |
59 const char WebRtcTestBase::kUseDefaultVideoCodec[] = ""; | |
60 | |
61 namespace { | |
62 | |
63 base::LazyInstance<bool> hit_javascript_errors_ = | |
64 LAZY_INSTANCE_INITIALIZER; | |
65 | |
66 // Intercepts all log messages. We always attach this handler but only look at | |
67 // the results if the test requests so. Note that this will only work if the | |
68 // WebrtcTestBase-inheriting test cases do not run in parallel (if they did they | |
69 // would race to look at the log, which is global to all tests). | |
70 bool JavascriptErrorDetectingLogHandler(int severity, | |
71 const char* file, | |
72 int line, | |
73 size_t message_start, | |
74 const std::string& str) { | |
75 if (file == NULL || std::string("CONSOLE") != file) | |
76 return false; | |
77 | |
78 bool contains_uncaught = str.find("\"Uncaught ") != std::string::npos; | |
79 if (severity == logging::LOG_ERROR || | |
80 (severity == logging::LOG_INFO && contains_uncaught)) { | |
81 hit_javascript_errors_.Get() = true; | |
82 } | |
83 | |
84 return false; | |
85 } | |
86 | |
87 // PermissionRequestObserver --------------------------------------------------- | |
88 | |
89 // Used to observe the creation of permission prompt without responding. | |
90 class PermissionRequestObserver : public PermissionRequestManager::Observer { | |
91 public: | |
92 explicit PermissionRequestObserver(content::WebContents* web_contents) | |
93 : request_manager_( | |
94 PermissionRequestManager::FromWebContents(web_contents)), | |
95 request_shown_(false), | |
96 message_loop_runner_(new content::MessageLoopRunner) { | |
97 request_manager_->AddObserver(this); | |
98 } | |
99 ~PermissionRequestObserver() override { | |
100 // Safe to remove twice if it happens. | |
101 request_manager_->RemoveObserver(this); | |
102 } | |
103 | |
104 void Wait() { message_loop_runner_->Run(); } | |
105 | |
106 bool request_shown() const { return request_shown_; } | |
107 | |
108 private: | |
109 // PermissionRequestManager::Observer | |
110 void OnBubbleAdded() override { | |
111 request_shown_ = true; | |
112 request_manager_->RemoveObserver(this); | |
113 message_loop_runner_->Quit(); | |
114 } | |
115 | |
116 PermissionRequestManager* request_manager_; | |
117 bool request_shown_; | |
118 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
119 | |
120 DISALLOW_COPY_AND_ASSIGN(PermissionRequestObserver); | |
121 }; | |
122 | |
123 } // namespace | |
124 | |
125 WebRtcTestBase::WebRtcTestBase(): detect_errors_in_javascript_(false) { | |
126 // The handler gets set for each test method, but that's fine since this | |
127 // set operation is idempotent. | |
128 logging::SetLogMessageHandler(&JavascriptErrorDetectingLogHandler); | |
129 hit_javascript_errors_.Get() = false; | |
130 | |
131 EnablePixelOutput(); | |
132 } | |
133 | |
134 WebRtcTestBase::~WebRtcTestBase() { | |
135 if (detect_errors_in_javascript_) { | |
136 EXPECT_FALSE(hit_javascript_errors_.Get()) | |
137 << "Encountered javascript errors during test execution (Search " | |
138 << "for Uncaught or ERROR:CONSOLE in the test output)."; | |
139 } | |
140 } | |
141 | |
142 bool WebRtcTestBase::GetUserMediaAndAccept( | |
143 content::WebContents* tab_contents) const { | |
144 return GetUserMediaWithSpecificConstraintsAndAccept( | |
145 tab_contents, kAudioVideoCallConstraints); | |
146 } | |
147 | |
148 bool WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAccept( | |
149 content::WebContents* tab_contents, | |
150 const std::string& constraints) const { | |
151 std::string result; | |
152 PermissionRequestManager::FromWebContents(tab_contents) | |
153 ->set_auto_response_for_test(PermissionRequestManager::ACCEPT_ALL); | |
154 PermissionRequestObserver permissionRequestObserver(tab_contents); | |
155 GetUserMedia(tab_contents, constraints); | |
156 EXPECT_TRUE(permissionRequestObserver.request_shown()); | |
157 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
158 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
159 return kOkGotStream == result; | |
160 } | |
161 | |
162 bool WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndAcceptIfPrompted( | |
163 content::WebContents* tab_contents, | |
164 const std::string& constraints) const { | |
165 std::string result; | |
166 PermissionRequestManager::FromWebContents(tab_contents) | |
167 ->set_auto_response_for_test(PermissionRequestManager::ACCEPT_ALL); | |
168 GetUserMedia(tab_contents, constraints); | |
169 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
170 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
171 return kOkGotStream == result; | |
172 } | |
173 | |
174 void WebRtcTestBase::GetUserMediaAndDeny(content::WebContents* tab_contents) { | |
175 return GetUserMediaWithSpecificConstraintsAndDeny(tab_contents, | |
176 kAudioVideoCallConstraints); | |
177 } | |
178 | |
179 void WebRtcTestBase::GetUserMediaWithSpecificConstraintsAndDeny( | |
180 content::WebContents* tab_contents, | |
181 const std::string& constraints) const { | |
182 std::string result; | |
183 PermissionRequestManager::FromWebContents(tab_contents) | |
184 ->set_auto_response_for_test(PermissionRequestManager::DENY_ALL); | |
185 PermissionRequestObserver permissionRequestObserver(tab_contents); | |
186 GetUserMedia(tab_contents, constraints); | |
187 EXPECT_TRUE(permissionRequestObserver.request_shown()); | |
188 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
189 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
190 EXPECT_EQ(kFailedWithPermissionDeniedError, result); | |
191 } | |
192 | |
193 void WebRtcTestBase::GetUserMediaAndDismiss( | |
194 content::WebContents* tab_contents) const { | |
195 std::string result; | |
196 PermissionRequestManager::FromWebContents(tab_contents) | |
197 ->set_auto_response_for_test(PermissionRequestManager::DISMISS); | |
198 PermissionRequestObserver permissionRequestObserver(tab_contents); | |
199 GetUserMedia(tab_contents, kAudioVideoCallConstraints); | |
200 EXPECT_TRUE(permissionRequestObserver.request_shown()); | |
201 // A dismiss should be treated like a deny. | |
202 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
203 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
204 EXPECT_EQ(kFailedWithPermissionDismissedError, result); | |
205 } | |
206 | |
207 void WebRtcTestBase::GetUserMediaAndExpectAutoAcceptWithoutPrompt( | |
208 content::WebContents* tab_contents) const { | |
209 std::string result; | |
210 // We issue a GetUserMedia() request. We expect that the origin already has a | |
211 // sticky "accept" permission (e.g. because the caller previously called | |
212 // GetUserMediaAndAccept()), and therefore the GetUserMedia() request | |
213 // automatically succeeds without a prompt. | |
214 // If the caller made a mistake, a prompt may show up instead. For this case, | |
215 // we set an auto-response to avoid leaving the prompt hanging. The choice of | |
216 // DENY_ALL makes sure that the response to the prompt doesn't accidentally | |
217 // result in a newly granted media stream permission. | |
218 PermissionRequestManager::FromWebContents(tab_contents) | |
219 ->set_auto_response_for_test(PermissionRequestManager::DENY_ALL); | |
220 PermissionRequestObserver permissionRequestObserver(tab_contents); | |
221 GetUserMedia(tab_contents, kAudioVideoCallConstraints); | |
222 EXPECT_FALSE(permissionRequestObserver.request_shown()); | |
223 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
224 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
225 EXPECT_EQ(kOkGotStream, result); | |
226 } | |
227 | |
228 void WebRtcTestBase::GetUserMediaAndExpectAutoDenyWithoutPrompt( | |
229 content::WebContents* tab_contents) const { | |
230 std::string result; | |
231 // We issue a GetUserMedia() request. We expect that the origin already has a | |
232 // sticky "deny" permission (e.g. because the caller previously called | |
233 // GetUserMediaAndDeny()), and therefore the GetUserMedia() request | |
234 // automatically succeeds without a prompt. | |
235 // If the caller made a mistake, a prompt may show up instead. For this case, | |
236 // we set an auto-response to avoid leaving the prompt hanging. The choice of | |
237 // ACCEPT_ALL makes sure that the response to the prompt doesn't accidentally | |
238 // result in a newly granted media stream permission. | |
239 PermissionRequestManager::FromWebContents(tab_contents) | |
240 ->set_auto_response_for_test(PermissionRequestManager::ACCEPT_ALL); | |
241 PermissionRequestObserver permissionRequestObserver(tab_contents); | |
242 GetUserMedia(tab_contents, kAudioVideoCallConstraints); | |
243 EXPECT_FALSE(permissionRequestObserver.request_shown()); | |
244 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
245 tab_contents->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
246 EXPECT_EQ(kFailedWithPermissionDeniedError, result); | |
247 } | |
248 | |
249 void WebRtcTestBase::GetUserMedia(content::WebContents* tab_contents, | |
250 const std::string& constraints) const { | |
251 // Request user media: this will launch the media stream info bar or bubble. | |
252 std::string result; | |
253 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
254 tab_contents, "doGetUserMedia(" + constraints + ");", &result)); | |
255 EXPECT_TRUE(result == "request-callback-denied" || | |
256 result == "request-callback-granted"); | |
257 } | |
258 | |
259 content::WebContents* WebRtcTestBase::OpenPageAndGetUserMediaInNewTab( | |
260 const GURL& url) const { | |
261 return OpenPageAndGetUserMediaInNewTabWithConstraints( | |
262 url, kAudioVideoCallConstraints); | |
263 } | |
264 | |
265 content::WebContents* | |
266 WebRtcTestBase::OpenPageAndGetUserMediaInNewTabWithConstraints( | |
267 const GURL& url, | |
268 const std::string& constraints) const { | |
269 chrome::AddTabAt(browser(), GURL(), -1, true); | |
270 ui_test_utils::NavigateToURL(browser(), url); | |
271 content::WebContents* new_tab = | |
272 browser()->tab_strip_model()->GetActiveWebContents(); | |
273 // Accept if necessary, but don't expect a prompt (because auto-accept is also | |
274 // okay). | |
275 PermissionRequestManager::FromWebContents(new_tab) | |
276 ->set_auto_response_for_test(PermissionRequestManager::ACCEPT_ALL); | |
277 GetUserMedia(new_tab, constraints); | |
278 std::string result; | |
279 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
280 new_tab->GetMainFrame(), "obtainGetUserMediaResult();", &result)); | |
281 EXPECT_EQ(kOkGotStream, result); | |
282 return new_tab; | |
283 } | |
284 | |
285 content::WebContents* WebRtcTestBase::OpenTestPageAndGetUserMediaInNewTab( | |
286 const std::string& test_page) const { | |
287 return OpenPageAndGetUserMediaInNewTab( | |
288 embedded_test_server()->GetURL(test_page)); | |
289 } | |
290 | |
291 void WebRtcTestBase::CloseLastLocalStream( | |
292 content::WebContents* tab_contents) const { | |
293 EXPECT_EQ("ok-stopped", | |
294 ExecuteJavascript("stopLocalStream();", tab_contents)); | |
295 } | |
296 | |
297 // Convenience method which executes the provided javascript in the context | |
298 // of the provided web contents and returns what it evaluated to. | |
299 std::string WebRtcTestBase::ExecuteJavascript( | |
300 const std::string& javascript, | |
301 content::WebContents* tab_contents) const { | |
302 std::string result; | |
303 EXPECT_TRUE(content::ExecuteScriptAndExtractString( | |
304 tab_contents, javascript, &result)); | |
305 return result; | |
306 } | |
307 | |
308 void WebRtcTestBase::SetupPeerconnectionWithLocalStream( | |
309 content::WebContents* tab, | |
310 const std::string& certificate_keygen_algorithm) const { | |
311 SetupPeerconnectionWithoutLocalStream(tab, certificate_keygen_algorithm); | |
312 EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab)); | |
313 } | |
314 | |
315 void WebRtcTestBase::SetupPeerconnectionWithoutLocalStream( | |
316 content::WebContents* tab, | |
317 const std::string& certificate_keygen_algorithm) const { | |
318 std::string javascript = base::StringPrintf( | |
319 "preparePeerConnection(%s)", certificate_keygen_algorithm.c_str()); | |
320 EXPECT_EQ("ok-peerconnection-created", ExecuteJavascript(javascript, tab)); | |
321 } | |
322 | |
323 void WebRtcTestBase::SetupPeerconnectionWithCertificateAndLocalStream( | |
324 content::WebContents* tab, | |
325 const std::string& certificate) const { | |
326 SetupPeerconnectionWithCertificateWithoutLocalStream(tab, certificate); | |
327 EXPECT_EQ("ok-added", ExecuteJavascript("addLocalStream()", tab)); | |
328 } | |
329 | |
330 void WebRtcTestBase::SetupPeerconnectionWithCertificateWithoutLocalStream( | |
331 content::WebContents* tab, | |
332 const std::string& certificate) const { | |
333 std::string javascript = base::StringPrintf( | |
334 "preparePeerConnectionWithCertificate(%s)", certificate.c_str()); | |
335 EXPECT_EQ("ok-peerconnection-created", ExecuteJavascript(javascript, tab)); | |
336 } | |
337 | |
338 std::string WebRtcTestBase::CreateLocalOffer( | |
339 content::WebContents* from_tab) const { | |
340 std::string response = ExecuteJavascript("createLocalOffer({})", from_tab); | |
341 EXPECT_EQ("ok-", response.substr(0, 3)) << "Failed to create local offer: " | |
342 << response; | |
343 | |
344 std::string local_offer = response.substr(3); | |
345 return local_offer; | |
346 } | |
347 | |
348 std::string WebRtcTestBase::CreateAnswer(std::string local_offer, | |
349 content::WebContents* to_tab) const { | |
350 std::string javascript = | |
351 base::StringPrintf("receiveOfferFromPeer('%s', {})", local_offer.c_str()); | |
352 std::string response = ExecuteJavascript(javascript, to_tab); | |
353 EXPECT_EQ("ok-", response.substr(0, 3)) | |
354 << "Receiving peer failed to receive offer and create answer: " | |
355 << response; | |
356 | |
357 std::string answer = response.substr(3); | |
358 response = ExecuteJavascript( | |
359 base::StringPrintf("verifyDefaultVideoCodec('%s')", answer.c_str()), | |
360 to_tab); | |
361 EXPECT_EQ("ok-", response.substr(0, 3)) | |
362 << "Receiving peer failed to verify default codec: " << response; | |
363 return answer; | |
364 } | |
365 | |
366 void WebRtcTestBase::ReceiveAnswer(const std::string& answer, | |
367 content::WebContents* from_tab) const { | |
368 ASSERT_EQ( | |
369 "ok-accepted-answer", | |
370 ExecuteJavascript( | |
371 base::StringPrintf("receiveAnswerFromPeer('%s')", answer.c_str()), | |
372 from_tab)); | |
373 } | |
374 | |
375 void WebRtcTestBase::GatherAndSendIceCandidates( | |
376 content::WebContents* from_tab, | |
377 content::WebContents* to_tab) const { | |
378 std::string ice_candidates = | |
379 ExecuteJavascript("getAllIceCandidates()", from_tab); | |
380 | |
381 EXPECT_EQ("ok-received-candidates", ExecuteJavascript( | |
382 base::StringPrintf("receiveIceCandidates('%s')", ice_candidates.c_str()), | |
383 to_tab)); | |
384 } | |
385 | |
386 void WebRtcTestBase::NegotiateCall(content::WebContents* from_tab, | |
387 content::WebContents* to_tab) const { | |
388 std::string local_offer = CreateLocalOffer(from_tab); | |
389 std::string answer = CreateAnswer(local_offer, to_tab); | |
390 ReceiveAnswer(answer, from_tab); | |
391 | |
392 // Send all ICE candidates (wait for gathering to finish if necessary). | |
393 GatherAndSendIceCandidates(to_tab, from_tab); | |
394 GatherAndSendIceCandidates(from_tab, to_tab); | |
395 } | |
396 | |
397 void WebRtcTestBase::HangUp(content::WebContents* from_tab) const { | |
398 EXPECT_EQ("ok-call-hung-up", ExecuteJavascript("hangUp()", from_tab)); | |
399 } | |
400 | |
401 void WebRtcTestBase::DetectErrorsInJavaScript() { | |
402 detect_errors_in_javascript_ = true; | |
403 } | |
404 | |
405 void WebRtcTestBase::StartDetectingVideo( | |
406 content::WebContents* tab_contents, | |
407 const std::string& video_element) const { | |
408 std::string javascript = base::StringPrintf( | |
409 "startDetection('%s', 320, 240)", video_element.c_str()); | |
410 EXPECT_EQ("ok-started", ExecuteJavascript(javascript, tab_contents)); | |
411 } | |
412 | |
413 bool WebRtcTestBase::WaitForVideoToPlay( | |
414 content::WebContents* tab_contents) const { | |
415 bool is_video_playing = test::PollingWaitUntil( | |
416 "isVideoPlaying()", "video-playing", tab_contents); | |
417 EXPECT_TRUE(is_video_playing); | |
418 return is_video_playing; | |
419 } | |
420 | |
421 std::string WebRtcTestBase::GetStreamSize( | |
422 content::WebContents* tab_contents, | |
423 const std::string& video_element) const { | |
424 std::string javascript = | |
425 base::StringPrintf("getStreamSize('%s')", video_element.c_str()); | |
426 std::string result = ExecuteJavascript(javascript, tab_contents); | |
427 EXPECT_TRUE(base::StartsWith(result, "ok-", base::CompareCase::SENSITIVE)); | |
428 return result.substr(3); | |
429 } | |
430 | |
431 bool WebRtcTestBase::HasWebcamAvailableOnSystem( | |
432 content::WebContents* tab_contents) const { | |
433 std::string result = | |
434 ExecuteJavascript("hasVideoInputDeviceOnSystem();", tab_contents); | |
435 return result == "has-video-input-device"; | |
436 } | |
437 | |
438 bool WebRtcTestBase::OnWin8() const { | |
439 #if defined(OS_WIN) | |
440 return base::win::GetVersion() > base::win::VERSION_WIN7; | |
441 #else | |
442 return false; | |
443 #endif | |
444 } | |
445 | |
446 void WebRtcTestBase::OpenDatabase(content::WebContents* tab) const { | |
447 EXPECT_EQ("ok-database-opened", ExecuteJavascript("openDatabase()", tab)); | |
448 } | |
449 | |
450 void WebRtcTestBase::CloseDatabase(content::WebContents* tab) const { | |
451 EXPECT_EQ("ok-database-closed", ExecuteJavascript("closeDatabase()", tab)); | |
452 } | |
453 | |
454 void WebRtcTestBase::DeleteDatabase(content::WebContents* tab) const { | |
455 EXPECT_EQ("ok-database-deleted", ExecuteJavascript("deleteDatabase()", tab)); | |
456 } | |
457 | |
458 void WebRtcTestBase::GenerateAndCloneCertificate( | |
459 content::WebContents* tab, const std::string& keygen_algorithm) const { | |
460 std::string javascript = base::StringPrintf( | |
461 "generateAndCloneCertificate(%s)", keygen_algorithm.c_str()); | |
462 EXPECT_EQ("ok-generated-and-cloned", ExecuteJavascript(javascript, tab)); | |
463 } | |
464 | |
465 void WebRtcTestBase::VerifyStatsGenerated(content::WebContents* tab) const { | |
466 EXPECT_EQ("ok-got-stats", ExecuteJavascript("verifyStatsGenerated()", tab)); | |
467 } | |
468 | |
469 void WebRtcTestBase::SetDefaultVideoCodec( | |
470 content::WebContents* tab, | |
471 const std::string& video_codec) const { | |
472 EXPECT_EQ("ok-forced", | |
473 ExecuteJavascript("forceVideoCodec('" + video_codec + "')", tab)); | |
474 } | |
475 | |
476 void WebRtcTestBase::EnableOpusDtx(content::WebContents* tab) const { | |
477 EXPECT_EQ("ok-forced", ExecuteJavascript("forceOpusDtx()", tab)); | |
478 } | |
OLD | NEW |