1 // Copyright 2014 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 "base/command_line.h" 6 #include "base/json/json_reader.h" 7 #include "base/strings/string_util.h" 8 #include "chrome/browser/media/webrtc_browsertest_base.h" 9 #include "chrome/browser/media/webrtc_browsertest_common.h" 10 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser_tabstrip.h" 12 #include "chrome/browser/ui/tabs/tab_strip_model.h" 13 #include "chrome/common/chrome_switches.h" 14 #include "chrome/test/base/in_process_browser_test.h" 15 #include "chrome/test/base/ui_test_utils.h" 16 #include "content/public/test/browser_test_utils.h" 17 #include "media/audio/audio_manager.h" 18 #include "media/base/media_switches.h" 19 #include "net/test/embedded_test_server/embedded_test_server.h" 20 21 namespace { 22 23 const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html"; 24 25 const char kDeviceKindAudioInput[] = "audioinput"; 26 const char kDeviceKindVideoInput[] = "videoinput"; 27 const char kDeviceKindAudioOutput[] = "audiooutput"; 28 29 const char kSourceKindAudioInput[] = "audio"; 30 const char kSourceKindVideoInput[] = "video"; 31 32 } // namespace 33 34 // Integration test for WebRTC getMediaDevices. It always uses fake devices. 35 // It needs to be a browser test (and not content browser test) to be able to 36 // test that labels are cleared or not depending on if access to devices has 37 // been granted. 38 class WebRtcGetMediaDevicesBrowserTest 39 : public WebRtcTestBase, 40 public testing::WithParamInterface<bool> { 41 public: 42 WebRtcGetMediaDevicesBrowserTest() 43 : has_audio_output_devices_initialized_(false), 44 has_audio_output_devices_(false) {} 45 46 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 47 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. 48 } 49 50 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 51 // Ensure the infobar is enabled, since we expect that in this test. 52 EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream)); 53 54 // Always use fake devices. 55 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream); 56 } 57 58 protected: 59 // This is used for media devices and sources. 60 struct MediaDeviceInfo { 61 std::string device_id; // Domain specific device ID. 62 std::string kind; 63 std::string label; 64 std::string group_id; 65 }; 66 67 bool HasOutputDevices() { 68 // There's no fake audio output devices supported yet. We can't test audio 69 // output devices on bots with no output devices, so skip testing for that 70 // on such bots. We cache the result since querying for devices can take 71 // considerable time. 72 if (!has_audio_output_devices_initialized_) { 73 has_audio_output_devices_ = 74 media::AudioManager::Get()->HasAudioOutputDevices(); 75 has_audio_output_devices_initialized_ = true; 76 } 77 return has_audio_output_devices_; 78 } 79 80 // If |get_sources| is true, use getSources API and leave groupId empty, 81 // otherwise use getMediaDevices API. 82 void GetMediaDevicesOrSources(content::WebContents* tab, 83 std::vector<MediaDeviceInfo>* devices, 84 bool get_sources) { 85 std::string devices_as_json = 86 ExecuteJavascript(get_sources ? "getSources()" : "getMediaDevices()", 87 tab); 88 EXPECT_FALSE(devices_as_json.empty()); 89 90 int error_code; 91 std::string error_message; 92 scoped_ptr<base::Value> value( 93 base::JSONReader::ReadAndReturnError(devices_as_json, 94 base::JSON_ALLOW_TRAILING_COMMAS, 95 &error_code, 96 &error_message)); 97 98 ASSERT_TRUE(value.get() != NULL) << error_message; 99 EXPECT_EQ(value->GetType(), base::Value::TYPE_LIST); 100 101 base::ListValue* values; 102 ASSERT_TRUE(value->GetAsList(&values)); 103 ASSERT_FALSE(values->empty()); 104 bool found_audio_input = false; 105 bool found_video_input = false; 106 bool found_audio_output = false; 107 108 for (base::ListValue::iterator it = values->begin(); 109 it != values->end(); ++it) { 110 const base::DictionaryValue* dict; 111 MediaDeviceInfo device; 112 ASSERT_TRUE((*it)->GetAsDictionary(&dict)); 113 ASSERT_TRUE(dict->GetString(get_sources ? "id" : "deviceId", 114 &device.device_id)); 115 ASSERT_TRUE(dict->GetString("kind", &device.kind)); 116 ASSERT_TRUE(dict->GetString("label", &device.label)); 117 if (!get_sources) 118 ASSERT_TRUE(dict->GetString("groupId", &device.group_id)); 119 120 // Should be HMAC SHA256. 121 EXPECT_EQ(64ul, device.device_id.length()); 122 EXPECT_TRUE(base::ContainsOnlyChars(device.device_id, 123 "0123456789abcdef")); 124 125 const char* kAudioInputKind = 126 get_sources ? kSourceKindAudioInput : kDeviceKindAudioInput; 127 const char* kVideoInputKind = 128 get_sources ? kSourceKindVideoInput : kDeviceKindVideoInput; 129 if (get_sources) { 130 EXPECT_TRUE(device.kind == kAudioInputKind || 131 device.kind == kVideoInputKind); 132 } else { 133 EXPECT_TRUE(device.kind == kAudioInputKind || 134 device.kind == kVideoInputKind || 135 device.kind == kDeviceKindAudioOutput); 136 } 137 if (device.kind == kAudioInputKind) { 138 found_audio_input = true; 139 } else if (device.kind == kVideoInputKind) { 140 found_video_input = true; 141 } else { 142 found_audio_output = true; 143 } 144 145 // getSources doesn't have group ID support. getMediaDevices doesn't have 146 // group ID support for video input devices. 147 if (get_sources || device.kind == kDeviceKindVideoInput) { 148 EXPECT_TRUE(device.group_id.empty()); 149 } else { 150 EXPECT_FALSE(device.group_id.empty()); 151 } 152 153 devices->push_back(device); 154 } 155 156 EXPECT_TRUE(found_audio_input); 157 EXPECT_TRUE(found_video_input); 158 if (get_sources) { 159 EXPECT_FALSE(found_audio_output); 160 } else { 161 EXPECT_EQ(HasOutputDevices(), found_audio_output); 162 } 163 } 164 165 void GetMediaDevices(content::WebContents* tab, 166 std::vector<MediaDeviceInfo>* devices) { 167 GetMediaDevicesOrSources(tab, devices, false); 168 } 169 170 void GetSources(content::WebContents* tab, 171 std::vector<MediaDeviceInfo>* sources) { 172 GetMediaDevicesOrSources(tab, sources, true); 173 } 174 175 bool has_audio_output_devices_initialized_; 176 bool has_audio_output_devices_; 177 }; 178 179 static const bool kParamsToRunTestsWith[] = { false, true }; 180 INSTANTIATE_TEST_CASE_P(WebRtcGetMediaDevicesBrowserTests, 181 WebRtcGetMediaDevicesBrowserTest, 182 testing::ValuesIn(kParamsToRunTestsWith)); 183 184 // getMediaDevices has been removed and will be replaced 185 // MediaDevices.enumerateDevices. http://crbug.com/388648. 186 IN_PROC_BROWSER_TEST_P(WebRtcGetMediaDevicesBrowserTest, 187 DISABLED_GetMediaDevicesWithoutAccess) { 188 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 189 GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage)); 190 ui_test_utils::NavigateToURL(browser(), url); 191 content::WebContents* tab = 192 browser()->tab_strip_model()->GetActiveWebContents(); 193 194 std::vector<MediaDeviceInfo> devices; 195 GetMediaDevices(tab, &devices); 196 197 // Labels should be empty if access has not been allowed. 198 for (std::vector<MediaDeviceInfo>::iterator it = devices.begin(); 199 it != devices.end(); ++it) { 200 EXPECT_TRUE(it->label.empty()); 201 } 202 } 203 204 // getMediaDevices has been removed and will be replaced 205 // MediaDevices.enumerateDevices. http://crbug.com/388648. 206 // Disabled, fails due to http://crbug.com/382391. 207 IN_PROC_BROWSER_TEST_P(WebRtcGetMediaDevicesBrowserTest, 208 DISABLED_GetMediaDevicesWithAccess) { 209 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 210 GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage)); 211 ui_test_utils::NavigateToURL(browser(), url); 212 content::WebContents* tab = 213 browser()->tab_strip_model()->GetActiveWebContents(); 214 215 GetUserMediaAndAccept(tab); 216 217 std::vector<MediaDeviceInfo> devices; 218 GetMediaDevices(tab, &devices); 219 220 // Labels should be non-empty if access has been allowed. 221 for (std::vector<MediaDeviceInfo>::iterator it = devices.begin(); 222 it != devices.end(); ++it) { 223 EXPECT_TRUE(!it->label.empty()); 224 } 225 } 226 227 // getMediaDevices has been removed and will be replaced 228 // MediaDevices.enumerateDevices. http://crbug.com/388648. 229 IN_PROC_BROWSER_TEST_P(WebRtcGetMediaDevicesBrowserTest, 230 DISABLED_GetMediaDevicesEqualsGetSourcesWithoutAccess) { 231 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 232 GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage)); 233 ui_test_utils::NavigateToURL(browser(), url); 234 content::WebContents* tab = 235 browser()->tab_strip_model()->GetActiveWebContents(); 236 237 std::vector<MediaDeviceInfo> devices; 238 GetMediaDevices(tab, &devices); 239 240 std::vector<MediaDeviceInfo> sources; 241 GetSources(tab, &sources); 242 243 std::vector<MediaDeviceInfo>::iterator sources_it = sources.begin(); 244 for (std::vector<MediaDeviceInfo>::iterator devices_it = devices.begin(); 245 devices_it != devices.end(); ++devices_it) { 246 if (devices_it->kind == kDeviceKindAudioOutput) 247 continue; 248 EXPECT_STREQ(devices_it->device_id.c_str(), sources_it->device_id.c_str()); 249 if (devices_it->kind == kDeviceKindAudioInput) { 250 EXPECT_STREQ(kSourceKindAudioInput, sources_it->kind.c_str()); 251 } else { 252 EXPECT_STREQ(kSourceKindVideoInput, sources_it->kind.c_str()); 253 } 254 EXPECT_TRUE(devices_it->label.empty()); 255 EXPECT_TRUE(sources_it->label.empty()); 256 ++sources_it; 257 } 258 EXPECT_EQ(sources.end(), sources_it); 259 } 260 261 // getMediaDevices has been removed and will be replaced 262 // MediaDevices.enumerateDevices. http://crbug.com/388648. 263 // Disabled, fails due to http://crbug.com/382391. 264 IN_PROC_BROWSER_TEST_P(WebRtcGetMediaDevicesBrowserTest, 265 DISABLED_GetMediaDevicesEqualsGetSourcesWithAccess) { 266 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 267 GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage)); 268 ui_test_utils::NavigateToURL(browser(), url); 269 content::WebContents* tab = 270 browser()->tab_strip_model()->GetActiveWebContents(); 271 272 GetUserMediaAndAccept(tab); 273 274 std::vector<MediaDeviceInfo> devices; 275 GetMediaDevices(tab, &devices); 276 277 std::vector<MediaDeviceInfo> sources; 278 GetSources(tab, &sources); 279 280 std::vector<MediaDeviceInfo>::iterator sources_it = sources.begin(); 281 for (std::vector<MediaDeviceInfo>::iterator devices_it = devices.begin(); 282 devices_it != devices.end(); ++devices_it) { 283 if (devices_it->kind == kDeviceKindAudioOutput) 284 continue; 285 EXPECT_STREQ(devices_it->device_id.c_str(), sources_it->device_id.c_str()); 286 if (devices_it->kind == kDeviceKindAudioInput) { 287 EXPECT_STREQ(kSourceKindAudioInput, sources_it->kind.c_str()); 288 } else { 289 EXPECT_STREQ(kSourceKindVideoInput, sources_it->kind.c_str()); 290 } 291 EXPECT_TRUE(!devices_it->label.empty()); 292 EXPECT_STREQ(devices_it->label.c_str(), sources_it->label.c_str()); 293 ++sources_it; 294 } 295 EXPECT_EQ(sources.end(), sources_it); 296 } 297