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