| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 #include <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 using media::AudioManager; | 50 using media::AudioManager; |
| 51 | 51 |
| 52 namespace extensions { | 52 namespace extensions { |
| 53 | 53 |
| 54 using extension_function_test_utils::RunFunctionAndReturnError; | 54 using extension_function_test_utils::RunFunctionAndReturnError; |
| 55 using extension_function_test_utils::RunFunctionAndReturnSingleResult; | 55 using extension_function_test_utils::RunFunctionAndReturnSingleResult; |
| 56 | 56 |
| 57 class AudioWaitingExtensionTest : public ExtensionApiTest { | 57 class AudioWaitingExtensionTest : public ExtensionApiTest { |
| 58 protected: | 58 protected: |
| 59 void WaitUntilAudioIsPlaying(WebContents* tab) { | 59 void WaitUntilAudioIsPlaying(WebContents* tab) { |
| 60 // Wait for audio to start playing. We gate this on there being one | 60 // Wait for audio to start playing. |
| 61 // or more AudioOutputController objects for our tab. | |
| 62 bool audio_playing = false; | 61 bool audio_playing = false; |
| 63 for (size_t remaining_tries = 50; remaining_tries > 0; --remaining_tries) { | 62 for (size_t remaining_tries = 50; remaining_tries > 0; --remaining_tries) { |
| 64 tab->GetRenderProcessHost()->GetAudioOutputControllers( | 63 audio_playing = tab->WasRecentlyAudible(); |
| 65 base::Bind(OnAudioControllers, &audio_playing)); | |
| 66 base::RunLoop().RunUntilIdle(); | 64 base::RunLoop().RunUntilIdle(); |
| 67 if (audio_playing) | 65 if (audio_playing) |
| 68 break; | 66 break; |
| 69 | 67 |
| 70 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | 68 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); |
| 71 } | 69 } |
| 72 | 70 |
| 73 if (!audio_playing) | 71 if (!audio_playing) |
| 74 FAIL() << "Audio did not start playing within ~5 seconds."; | 72 FAIL() << "Audio did not start playing within ~5 seconds."; |
| 75 } | 73 } |
| 76 | |
| 77 // Used by the test above to wait until audio is playing. | |
| 78 static void OnAudioControllers( | |
| 79 bool* audio_playing, | |
| 80 const RenderProcessHost::AudioOutputControllerList& list) { | |
| 81 if (!list.empty()) | |
| 82 *audio_playing = true; | |
| 83 } | |
| 84 }; | 74 }; |
| 85 | 75 |
| 86 class WebrtcAudioPrivateTest : public AudioWaitingExtensionTest { | 76 class WebrtcAudioPrivateTest : public AudioWaitingExtensionTest { |
| 87 public: | 77 public: |
| 88 WebrtcAudioPrivateTest() | 78 WebrtcAudioPrivateTest() |
| 89 : enumeration_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 79 : enumeration_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 90 base::WaitableEvent::InitialState::NOT_SIGNALED) {} | 80 base::WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 91 | 81 |
| 92 void SetUpOnMainThread() override { | 82 void SetUpOnMainThread() override { |
| 93 AudioWaitingExtensionTest::SetUpOnMainThread(); | 83 AudioWaitingExtensionTest::SetUpOnMainThread(); |
| 94 // Needs to happen after chrome's schemes are added. | 84 // Needs to happen after chrome's schemes are added. |
| 95 source_url_ = GURL("chrome-extension://fakeid012345678/fakepage.html"); | 85 source_url_ = GURL("chrome-extension://fakeid012345678/fakepage.html"); |
| 96 } | 86 } |
| 97 | 87 |
| 98 protected: | 88 protected: |
| 99 void AppendTabIdToRequestInfo(base::ListValue* params, int tab_id) { | 89 void AppendTabIdToRequestInfo(base::ListValue* params, int tab_id) { |
| 100 std::unique_ptr<base::DictionaryValue> request_info( | 90 std::unique_ptr<base::DictionaryValue> request_info( |
| 101 new base::DictionaryValue()); | 91 new base::DictionaryValue()); |
| 102 request_info->SetInteger("tabId", tab_id); | 92 request_info->SetInteger("tabId", tab_id); |
| 103 params->Append(std::move(request_info)); | 93 params->Append(std::move(request_info)); |
| 104 } | 94 } |
| 105 | 95 |
| 106 std::string InvokeGetActiveSink(int tab_id) { | |
| 107 base::ListValue parameters; | |
| 108 AppendTabIdToRequestInfo(¶meters, tab_id); | |
| 109 std::string parameter_string; | |
| 110 JSONWriter::Write(parameters, ¶meter_string); | |
| 111 | |
| 112 scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function = | |
| 113 new WebrtcAudioPrivateGetActiveSinkFunction(); | |
| 114 function->set_source_url(source_url_); | |
| 115 std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult( | |
| 116 function.get(), parameter_string, browser())); | |
| 117 std::string device_id; | |
| 118 result->GetAsString(&device_id); | |
| 119 return device_id; | |
| 120 } | |
| 121 | |
| 122 std::unique_ptr<base::Value> InvokeGetSinks(base::ListValue** sink_list) { | 96 std::unique_ptr<base::Value> InvokeGetSinks(base::ListValue** sink_list) { |
| 123 scoped_refptr<WebrtcAudioPrivateGetSinksFunction> function = | 97 scoped_refptr<WebrtcAudioPrivateGetSinksFunction> function = |
| 124 new WebrtcAudioPrivateGetSinksFunction(); | 98 new WebrtcAudioPrivateGetSinksFunction(); |
| 125 function->set_source_url(source_url_); | 99 function->set_source_url(source_url_); |
| 126 | 100 |
| 127 std::unique_ptr<base::Value> result( | 101 std::unique_ptr<base::Value> result( |
| 128 RunFunctionAndReturnSingleResult(function.get(), "[]", browser())); | 102 RunFunctionAndReturnSingleResult(function.get(), "[]", browser())); |
| 129 result->GetAsList(sink_list); | 103 result->GetAsList(sink_list); |
| 130 return result; | 104 return result; |
| 131 } | 105 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 | 199 |
| 226 // TODO(joi): Verify the contents of these once we start actually | 200 // TODO(joi): Verify the contents of these once we start actually |
| 227 // filling them in. | 201 // filling them in. |
| 228 EXPECT_TRUE(dict->HasKey("isDefault")); | 202 EXPECT_TRUE(dict->HasKey("isDefault")); |
| 229 EXPECT_TRUE(dict->HasKey("isReady")); | 203 EXPECT_TRUE(dict->HasKey("isReady")); |
| 230 EXPECT_TRUE(dict->HasKey("sampleRate")); | 204 EXPECT_TRUE(dict->HasKey("sampleRate")); |
| 231 } | 205 } |
| 232 } | 206 } |
| 233 #endif // OS_MACOSX | 207 #endif // OS_MACOSX |
| 234 | 208 |
| 235 // This exercises the case where you have a tab with no active media | |
| 236 // stream and try to retrieve the currently active audio sink. | |
| 237 IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetActiveSinkNoMediaStream) { | |
| 238 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 239 int tab_id = ExtensionTabUtil::GetTabId(tab); | |
| 240 base::ListValue parameters; | |
| 241 AppendTabIdToRequestInfo(¶meters, tab_id); | |
| 242 std::string parameter_string; | |
| 243 JSONWriter::Write(parameters, ¶meter_string); | |
| 244 | |
| 245 scoped_refptr<WebrtcAudioPrivateGetActiveSinkFunction> function = | |
| 246 new WebrtcAudioPrivateGetActiveSinkFunction(); | |
| 247 function->set_source_url(source_url_); | |
| 248 std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult( | |
| 249 function.get(), parameter_string, browser())); | |
| 250 | |
| 251 std::string result_string; | |
| 252 JSONWriter::Write(*result, &result_string); | |
| 253 EXPECT_EQ("\"\"", result_string); | |
| 254 } | |
| 255 | |
| 256 // This exercises the case where you have a tab with no active media | |
| 257 // stream and try to set the audio sink. | |
| 258 IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, SetActiveSinkNoMediaStream) { | |
| 259 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 260 int tab_id = ExtensionTabUtil::GetTabId(tab); | |
| 261 base::ListValue parameters; | |
| 262 AppendTabIdToRequestInfo(¶meters, tab_id); | |
| 263 parameters.AppendString("no such id"); | |
| 264 std::string parameter_string; | |
| 265 JSONWriter::Write(parameters, ¶meter_string); | |
| 266 | |
| 267 scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function = | |
| 268 new WebrtcAudioPrivateSetActiveSinkFunction(); | |
| 269 function->set_source_url(source_url_); | |
| 270 std::string error(RunFunctionAndReturnError(function.get(), | |
| 271 parameter_string, | |
| 272 browser())); | |
| 273 EXPECT_EQ(base::StringPrintf("No active stream for tabId %d", tab_id), | |
| 274 error); | |
| 275 } | |
| 276 | |
| 277 IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAndSetWithMediaStream) { | |
| 278 // Disabled on Win 7. https://crbug.com/500432. | |
| 279 #if defined(OS_WIN) | |
| 280 if (base::win::GetVersion() == base::win::VERSION_WIN7) | |
| 281 return; | |
| 282 #endif | |
| 283 | |
| 284 // First retrieve the list of all sinks, so that we can run a test | |
| 285 // where we set the active sink to each of the different available | |
| 286 // sinks in turn. | |
| 287 base::ListValue* sink_list = NULL; | |
| 288 std::unique_ptr<base::Value> result = InvokeGetSinks(&sink_list); | |
| 289 | |
| 290 ASSERT_TRUE(StartEmbeddedTestServer()); | |
| 291 | |
| 292 // Open a normal page that uses an audio sink. | |
| 293 ui_test_utils::NavigateToURL( | |
| 294 browser(), | |
| 295 GURL(embedded_test_server()->GetURL("/extensions/loop_audio.html"))); | |
| 296 | |
| 297 WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); | |
| 298 int tab_id = ExtensionTabUtil::GetTabId(tab); | |
| 299 | |
| 300 WaitUntilAudioIsPlaying(tab); | |
| 301 | |
| 302 std::string current_device = InvokeGetActiveSink(tab_id); | |
| 303 VLOG(2) << "Before setting, current device: " << current_device; | |
| 304 EXPECT_NE("", current_device); | |
| 305 | |
| 306 // Set to each of the other devices in turn. | |
| 307 for (size_t ix = 0; ix < sink_list->GetSize(); ++ix) { | |
| 308 base::DictionaryValue* dict = NULL; | |
| 309 sink_list->GetDictionary(ix, &dict); | |
| 310 std::string target_device; | |
| 311 dict->GetString("sinkId", &target_device); | |
| 312 | |
| 313 base::ListValue parameters; | |
| 314 AppendTabIdToRequestInfo(¶meters, tab_id); | |
| 315 parameters.AppendString(target_device); | |
| 316 std::string parameter_string; | |
| 317 JSONWriter::Write(parameters, ¶meter_string); | |
| 318 | |
| 319 scoped_refptr<WebrtcAudioPrivateSetActiveSinkFunction> function = | |
| 320 new WebrtcAudioPrivateSetActiveSinkFunction(); | |
| 321 function->set_source_url(source_url_); | |
| 322 std::unique_ptr<base::Value> result(RunFunctionAndReturnSingleResult( | |
| 323 function.get(), parameter_string, browser())); | |
| 324 // The function was successful if the above invocation doesn't | |
| 325 // fail. Just for kicks, also check that it returns no result. | |
| 326 EXPECT_EQ(NULL, result.get()); | |
| 327 | |
| 328 current_device = InvokeGetActiveSink(tab_id); | |
| 329 VLOG(2) << "After setting to " << target_device | |
| 330 << ", current device is " << current_device; | |
| 331 EXPECT_EQ(target_device, current_device); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAssociatedSink) { | 209 IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAssociatedSink) { |
| 336 // Get the list of input devices. We can cheat in the unit test and | 210 // Get the list of input devices. We can cheat in the unit test and |
| 337 // run this on the main thread since nobody else will be running at | 211 // run this on the main thread since nobody else will be running at |
| 338 // the same time. | 212 // the same time. |
| 339 AudioDeviceDescriptions devices; | 213 AudioDeviceDescriptions devices; |
| 340 GetAudioDeviceDescriptions(&AudioManager::GetAudioInputDeviceDescriptions, | 214 GetAudioDeviceDescriptions(&AudioManager::GetAudioInputDeviceDescriptions, |
| 341 &devices); | 215 &devices); |
| 342 | 216 |
| 343 // Try to get an associated sink for each source. | 217 // Try to get an associated sink for each source. |
| 344 for (const auto& device : devices) { | 218 for (const auto& device : devices) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("failure")); | 303 title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("failure")); |
| 430 base::string16 result = title_watcher.WaitAndGetTitle(); | 304 base::string16 result = title_watcher.WaitAndGetTitle(); |
| 431 EXPECT_EQ(base::ASCIIToUTF16("success"), result); | 305 EXPECT_EQ(base::ASCIIToUTF16("success"), result); |
| 432 | 306 |
| 433 g_browser_process->webrtc_log_uploader()->OverrideUploadWithBufferForTesting( | 307 g_browser_process->webrtc_log_uploader()->OverrideUploadWithBufferForTesting( |
| 434 NULL); | 308 NULL); |
| 435 } | 309 } |
| 436 #endif // BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION) | 310 #endif // BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION) |
| 437 | 311 |
| 438 } // namespace extensions | 312 } // namespace extensions |
| OLD | NEW |