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