1# Lint as: python2, python3 2# Copyright 2017 The Chromium OS 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 6import logging 7 8from six.moves.urllib.parse import urlparse 9 10from autotest_lib.client.bin import utils 11from autotest_lib.client.common_lib import error 12 13 14DEFAULT_TIMEOUT = 30 15TELEMETRY_API = 'hrTelemetryApi' 16 17 18class CfmMeetingsAPI(object): 19 """Utility class for interacting with CfMs.""" 20 21 def __init__(self, webview_context): 22 self._webview_context = webview_context 23 24 def _execute_telemetry_command(self, command): 25 self._webview_context.ExecuteJavaScript( 26 'window.%s.%s' % (TELEMETRY_API, command)) 27 28 def _evaluate_telemetry_command(self, command): 29 return self._webview_context.EvaluateJavaScript( 30 'window.%s.%s' % (TELEMETRY_API, command)) 31 32 # UI commands/functions 33 def wait_for_meetings_landing_page(self): 34 """Waits for the landing page screen.""" 35 self._webview_context.WaitForJavaScriptCondition( 36 'window.hasOwnProperty("%s") ' 37 '&& !window.%s.isInMeeting()' % (TELEMETRY_API, TELEMETRY_API), 38 timeout=DEFAULT_TIMEOUT) 39 logging.info('Reached meetings landing page.') 40 41 def wait_for_meetings_in_call_page(self): 42 """Waits for the in-call page to launch.""" 43 self._webview_context.WaitForJavaScriptCondition( 44 'window.hasOwnProperty("%s") ' 45 '&& window.%s.isInMeeting()' % (TELEMETRY_API, TELEMETRY_API), 46 timeout=DEFAULT_TIMEOUT) 47 logging.info('Reached meetings in-call page.') 48 49 def wait_for_oobe_start_page(self): 50 """Wait for oobe start screen to launch.""" 51 self._webview_context.WaitForJavaScriptCondition( 52 'window.hasOwnProperty("%s") ' 53 '&& typeof window.%s.skipOobe === "function"' % ( 54 TELEMETRY_API, TELEMETRY_API), 55 timeout=DEFAULT_TIMEOUT) 56 logging.info('Reached oobe page.') 57 58 def skip_oobe_screen(self): 59 """Skip Chromebox for Meetings oobe screen.""" 60 self._execute_telemetry_command('skipOobe()') 61 utils.poll_for_condition( 62 lambda: not self.is_oobe_start_page(), 63 exception=error.TestFail('Not able to skip oobe screen.'), 64 timeout=DEFAULT_TIMEOUT, 65 sleep_interval=1) 66 logging.info('Skipped oobe screen.') 67 68 def is_oobe_start_page(self): 69 """Check if device is on CFM oobe start screen.""" 70 if self._webview_context.EvaluateJavaScript( 71 'window.hasOwnProperty("%s") ' 72 '&& typeof window.%s.skipOobe === "function"' % ( 73 TELEMETRY_API, TELEMETRY_API)): 74 logging.info('Is on oobe start page.') 75 return True 76 logging.info('Is not on oobe start page.') 77 return False 78 79 # Hangouts commands/functions 80 def start_meeting_session(self): 81 """Start a meeting. 82 83 @return code for the started meeting 84 """ 85 if self.is_in_meeting_session(): 86 self.end_meeting_session() 87 88 self._execute_telemetry_command('startMeeting()') 89 self.wait_for_meetings_in_call_page() 90 meeting_code = self._get_meeting_code() 91 logging.info('Started meeting session %s', meeting_code) 92 return meeting_code 93 94 def _get_meeting_code(self): 95 path = urlparse(self._webview_context.GetUrl()).path 96 # The meeting code is the last part of the path. 97 return path.split('/')[-1] 98 99 def join_meeting_session(self, meeting_name): 100 """Joins a meeting. 101 102 @param meeting_name: Name of the meeting session. 103 """ 104 if self.is_in_meeting_session(): 105 self.end_meeting_session() 106 107 self._execute_telemetry_command('joinMeeting("%s")' % meeting_name) 108 self.wait_for_meetings_in_call_page() 109 logging.info('Started meeting session: %s', meeting_name) 110 111 def end_meeting_session(self): 112 """End current meeting session.""" 113 self._execute_telemetry_command('endCall()') 114 self.wait_for_meetings_landing_page() 115 logging.info('Ended meeting session.') 116 117 def is_in_meeting_session(self): 118 """Check if device is in meeting session.""" 119 if self._evaluate_telemetry_command('isInMeeting()'): 120 logging.info('Is in meeting session.') 121 return True 122 logging.info('Is not in meeting session.') 123 return False 124 125 def start_new_hangout_session(self, hangout_name): 126 """Start a new hangout session. 127 128 @param hangout_name: Name of the hangout session. 129 """ 130 raise NotImplementedError 131 132 def end_hangout_session(self): 133 """End current hangout session.""" 134 raise NotImplementedError 135 136 def is_in_hangout_session(self): 137 """Check if device is in hangout session.""" 138 raise NotImplementedError 139 140 def is_ready_to_start_hangout_session(self): 141 """Check if device is ready to start a new hangout session.""" 142 raise NotImplementedError 143 144 def get_participant_count(self): 145 """Returns the total number of participants in a meeting.""" 146 return self._evaluate_telemetry_command('getParticipantCount()') 147 148 # Diagnostics commands/functions 149 def is_diagnostic_run_in_progress(self): 150 """Check if hotrod diagnostics is running.""" 151 raise NotImplementedError 152 153 def wait_for_diagnostic_run_to_complete(self): 154 """Wait for hotrod diagnostics to complete.""" 155 raise NotImplementedError 156 157 def run_diagnostics(self): 158 """Run hotrod diagnostics.""" 159 raise NotImplementedError 160 161 def get_last_diagnostics_results(self): 162 """Get latest hotrod diagnostics results.""" 163 raise NotImplementedError 164 165 # Mic audio commands/functions 166 def is_mic_muted(self): 167 """Check if mic is muted.""" 168 if self._evaluate_telemetry_command('isMicMuted()'): 169 logging.info('Mic is muted.') 170 return True 171 logging.info('Mic is not muted.') 172 return False 173 174 def mute_mic(self): 175 """Local mic mute from toolbar.""" 176 self._execute_telemetry_command('setMicMuted(true)') 177 logging.info('Locally muted mic.') 178 179 def unmute_mic(self): 180 """Local mic unmute from toolbar.""" 181 self._execute_telemetry_command('setMicMuted(false)') 182 logging.info('Locally unmuted mic.') 183 184 def get_mic_devices(self): 185 """Get all mic devices detected by hotrod.""" 186 return self._evaluate_telemetry_command('getAudioInDevices()') 187 188 def get_preferred_mic(self): 189 """Get preferred microphone for hotrod.""" 190 return self._evaluate_telemetry_command('getPreferredAudioInDevice()') 191 192 def set_preferred_mic(self, mic_name): 193 """Set preferred mic for hotrod. 194 195 @param mic_name: String with mic name. 196 """ 197 self._execute_telemetry_command('setPreferredAudioInDevice(%s)' 198 % mic_name) 199 logging.info('Setting preferred mic to %s.', mic_name) 200 201 def remote_mute_mic(self): 202 """Remote mic mute request from cPanel.""" 203 raise NotImplementedError 204 205 def remote_unmute_mic(self): 206 """Remote mic unmute request from cPanel.""" 207 raise NotImplementedError 208 209 # Speaker commands/functions 210 def get_speaker_devices(self): 211 """Get all speaker devices detected by hotrod.""" 212 return self._evaluate_telemetry_command('getAudioOutDevices()') 213 214 def get_preferred_speaker(self): 215 """Get speaker preferred for hotrod.""" 216 return self._evaluate_telemetry_command('getPreferredAudioOutDevice()') 217 218 def set_preferred_speaker(self, speaker_name): 219 """Set preferred speaker for hotrod. 220 221 @param speaker_name: String with speaker name. 222 """ 223 self._execute_telemetry_command('setPreferredAudioOutDevice(%s)' 224 % speaker_name) 225 logging.info('Set preferred speaker to %s.', speaker_name) 226 227 def set_speaker_volume(self, volume_level): 228 """Set speaker volume. 229 230 @param volume_level: Number value ranging from 0-100 to set volume to. 231 """ 232 self._execute_telemetry_command('setAudioOutVolume(%d)' % volume_level) 233 logging.info('Set speaker volume to %d', volume_level) 234 235 def get_speaker_volume(self): 236 """Get current speaker volume.""" 237 return self._evaluate_telemetry_command('getAudioOutVolume()') 238 239 def play_test_sound(self): 240 """Play test sound.""" 241 raise NotImplementedError 242 243 # Camera commands/functions 244 def get_camera_devices(self): 245 """Get all camera devices detected by hotrod. 246 247 @return List of camera devices. 248 """ 249 return self._evaluate_telemetry_command('getVideoInDevices()') 250 251 def get_preferred_camera(self): 252 """Get camera preferred for hotrod.""" 253 return self._evaluate_telemetry_command('getPreferredVideoInDevice()') 254 255 def set_preferred_camera(self, camera_name): 256 """Set preferred camera for hotrod. 257 258 @param camera_name: String with camera name. 259 """ 260 self._execute_telemetry_command('setPreferredVideoInDevice(%s)' 261 % camera_name) 262 logging.info('Set preferred camera to %s.', camera_name) 263 264 def is_camera_muted(self): 265 """Check if camera is muted (turned off).""" 266 if self._evaluate_telemetry_command('isCameraMuted()'): 267 logging.info('Camera is muted.') 268 return True 269 logging.info('Camera is not muted.') 270 return False 271 272 def mute_camera(self): 273 """Mute (turn off) camera.""" 274 self._execute_telemetry_command('setCameraMuted(true)') 275 logging.info('Camera muted.') 276 277 def unmute_camera(self): 278 """Unmute (turn on) camera.""" 279 self._execute_telemetry_command('setCameraMuted(false)') 280 logging.info('Camera unmuted.') 281 282 def move_camera(self, camera_motion): 283 """Move camera(PTZ functions). 284 285 @param camera_motion: String of the desired camera motion. 286 """ 287 ptz_motions = ['panLeft','panRight','panStop', 288 'tiltUp','tiltDown','tiltStop', 289 'zoomIn','zoomOut','resetPosition'] 290 291 if camera_motion in ptz_motions: 292 self._execute_telemetry_command('ptz.%s()' % camera_motion) 293 else: 294 raise ValueError('Unsupported PTZ camera action: "%s"' 295 % camera_motion) 296