1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import os 7 import platform 8 import re 9 import subprocess 10 11 import pyauto 12 13 14 class MissingRequiredBinaryException(Exception): 15 pass 16 17 18 class WebrtcTestBase(pyauto.PyUITest): 19 """This base class provides helpers for WebRTC calls.""" 20 21 DEFAULT_TEST_PAGE = 'webrtc_jsep01_test.html' 22 23 def ExtraChromeFlags(self): 24 """Adds flags to the Chrome command line.""" 25 extra_flags = ['--enable-data-channels', '--enable-dcheck'] 26 return pyauto.PyUITest.ExtraChromeFlags(self) + extra_flags 27 28 def LoadTestPageInTwoTabs(self, test_page=DEFAULT_TEST_PAGE): 29 url = self.GetFileURLForDataPath('webrtc', test_page) 30 self.NavigateToURL(url) 31 self.AppendTab(pyauto.GURL(url)) 32 33 def LoadTestPageInOneTab(self, test_page=DEFAULT_TEST_PAGE): 34 url = self.GetFileURLForDataPath('webrtc', test_page) 35 self.NavigateToURL(url) 36 37 def GetUserMedia(self, tab_index, action='accept', 38 request_video=True, request_audio=True): 39 """Acquires webcam or mic for one tab and returns the result. 40 41 Args: 42 tab_index: The tab to request user media on. 43 action: The action to take on the info bar. Can be 'accept', 'cancel' or 44 'dismiss'. 45 request_video: Whether to request video. 46 request_audio: Whether to request audio. 47 48 Returns: 49 A string as specified by the getUserMedia javascript function. 50 """ 51 constraints = '{ video: %s, audio: %s }' % (str(request_video).lower(), 52 str(request_audio).lower()) 53 self.assertEquals('ok-requested', self.ExecuteJavascript( 54 'getUserMedia("%s")' % constraints, tab_index=tab_index)) 55 56 self.WaitForInfobarCount(1, tab_index=tab_index) 57 self.PerformActionOnInfobar(action, infobar_index=0, tab_index=tab_index) 58 self.WaitForGetUserMediaResult(tab_index=0) 59 60 result = self.GetUserMediaResult(tab_index=0) 61 self.AssertNoFailures(tab_index) 62 return result 63 64 def WaitForGetUserMediaResult(self, tab_index): 65 """Waits until WebRTC has responded to a getUserMedia query. 66 67 Fails an assert if WebRTC doesn't respond within the default timeout. 68 69 Args: 70 tab_index: the tab to query. 71 """ 72 def HasResult(): 73 return self.GetUserMediaResult(tab_index) != 'not-called-yet' 74 self.assertTrue(self.WaitUntil(HasResult), 75 msg='Timed out while waiting for getUserMedia callback.') 76 77 def GetUserMediaResult(self, tab_index): 78 """Retrieves WebRTC's answer to a user media query. 79 80 Args: 81 tab_index: the tab to query. 82 83 Returns: 84 Specified in obtainGetUserMediaResult() in getusermedia.js. 85 """ 86 return self.ExecuteJavascript( 87 'obtainGetUserMediaResult()', tab_index=tab_index) 88 89 def AssertNoFailures(self, tab_index): 90 """Ensures the javascript hasn't registered any asynchronous errors. 91 92 Args: 93 tab_index: The tab to check. 94 """ 95 self.assertEquals('ok-no-errors', self.ExecuteJavascript( 96 'getAnyTestFailures()', tab_index=tab_index)) 97 98 def Connect(self, user_name, tab_index): 99 self.assertEquals('ok-connected', self.ExecuteJavascript( 100 'connect("http://localhost:8888", "%s")' % user_name, 101 tab_index=tab_index)) 102 self.AssertNoFailures(tab_index) 103 104 def CreatePeerConnection(self, tab_index): 105 self.assertEquals('ok-peerconnection-created', self.ExecuteJavascript( 106 'preparePeerConnection()', tab_index=tab_index)) 107 108 def AddUserMediaLocalStream(self, tab_index): 109 self.assertEquals('ok-added', self.ExecuteJavascript( 110 'addLocalStream()', tab_index=tab_index)) 111 112 def AddWebAudioFile(self, tab_index, input_relative_path): 113 """The path must be relative to where the javascript is. 114 115 This call just loads and adds a file to a peer connection, but it doesn't 116 start to play it until you call PlayWebAudioFile. 117 """ 118 self.assertEquals('ok-added', self.ExecuteJavascript( 119 'addAudioFile("%s")' % re.escape(input_relative_path), 120 tab_index=tab_index)) 121 122 def PlayWebAudioFile(self, tab_index): 123 """Plays a web audio file which was added earlier.""" 124 self.assertEquals('ok-playing', self.ExecuteJavascript( 125 'playAudioFile()', tab_index=tab_index)) 126 127 def EstablishCall(self, from_tab_with_index, to_tab_with_index): 128 self.WaitUntilPeerConnects(tab_index=from_tab_with_index) 129 130 self.assertEquals('ok-negotiating', self.ExecuteJavascript( 131 'negotiateCall()', tab_index=from_tab_with_index)) 132 self.AssertNoFailures(from_tab_with_index) 133 134 self.WaitUntilReadyState(ready_state='active', 135 tab_index=from_tab_with_index) 136 137 # Double-check the call reached the other side. 138 self.WaitUntilReadyState(ready_state='active', 139 tab_index=to_tab_with_index) 140 141 def HangUp(self, from_tab_with_index): 142 self.assertEquals('ok-call-hung-up', self.ExecuteJavascript( 143 'hangUp()', tab_index=from_tab_with_index)) 144 self.WaitUntilHangUpVerified(tab_index=from_tab_with_index) 145 self.AssertNoFailures(tab_index=from_tab_with_index) 146 147 def WaitUntilPeerConnects(self, tab_index): 148 peer_connected = self.WaitUntil( 149 function=lambda: self.ExecuteJavascript('remotePeerIsConnected()', 150 tab_index=tab_index), 151 expect_retval='peer-connected') 152 self.assertTrue(peer_connected, 153 msg='Timed out while waiting for peer to connect.') 154 155 def WaitUntilReadyState(self, ready_state, tab_index): 156 got_ready_state = self.WaitUntil( 157 function=lambda: self.ExecuteJavascript('getPeerConnectionReadyState()', 158 tab_index=tab_index), 159 expect_retval=ready_state) 160 self.assertTrue(got_ready_state, 161 msg=('Timed out while waiting for peer connection ready ' 162 'state to change to %s for tab %d.' % (ready_state, 163 tab_index))) 164 165 def WaitUntilHangUpVerified(self, tab_index): 166 self.WaitUntilReadyState('no-peer-connection', tab_index=tab_index) 167 168 def Disconnect(self, tab_index): 169 self.assertEquals('ok-disconnected', self.ExecuteJavascript( 170 'disconnect()', tab_index=tab_index)) 171 172 def BinPathForPlatform(self, path): 173 """Form a platform specific path to a binary. 174 175 Args: 176 path(string): The path to the binary without an extension. 177 Return: 178 (string): The platform-specific bin path. 179 """ 180 if self.IsWin(): 181 path += '.exe' 182 return path 183 184 def PlatformIsWinXP(self): 185 """Check if the executing platform is Windows XP. 186 187 Return: 188 True if the platform is Windows XP. 189 """ 190 return platform.system() == 'Windows' and platform.release() == 'XP' 191 192 def StartPeerConnectionServer(self): 193 """Starts peerconnection_server. 194 195 Peerconnection_server is a custom binary allowing two WebRTC clients to find 196 each other. For more details, see the source code which is available at the 197 site http://code.google.com/p/libjingle/source/browse/ (make sure to browse 198 to trunk/talk/examples/peerconnection/server). 199 """ 200 # Start the peerconnection_server. It should be next to chrome. 201 binary_path = os.path.join(self.BrowserPath(), 'peerconnection_server') 202 binary_path = self.BinPathForPlatform(binary_path) 203 204 if not os.path.exists(binary_path): 205 raise MissingRequiredBinaryException( 206 'Could not locate peerconnection_server. Have you built the ' 207 'peerconnection_server target? We expect to have a ' 208 'peerconnection_server binary next to the chrome binary.') 209 210 self._server_process = subprocess.Popen(binary_path) 211 212 def StopPeerConnectionServer(self): 213 """Stops the peerconnection_server.""" 214 assert self._server_process 215 self._server_process.kill() 216