Add support for launching webcam software for use in recipes
* Copy ensure_webcam_is_running.py from recipes repo
* Turn it into a wrapper that can launch another script
(fix_python_path is copied from test_env.py as _ForcePythonInterpreter)
* Support it in mb.py
* Add it to video_capture_unittests
No-Try: True
Bug: chromium:755660
Change-Id: I376724a77e443620724add7818592e9368d02079
Reviewed-on: https://webrtc-review.googlesource.com/77320
Commit-Queue: Oleh Prypin <oprypin@webrtc.org>
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23275}
diff --git a/tools_webrtc/ensure_webcam_is_running.py b/tools_webrtc/ensure_webcam_is_running.py
new file mode 100755
index 0000000..952ebd6
--- /dev/null
+++ b/tools_webrtc/ensure_webcam_is_running.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+"""Checks if a virtual webcam is running and starts it if not.
+
+Returns a non-zero return code if the webcam could not be started.
+
+Prerequisites:
+* The Python interpreter must have the psutil package installed.
+* Windows: a scheduled task named 'ManyCam' must exist and be configured to
+ launch ManyCam preconfigured to auto-play the test clip.
+* Mac: ManyCam must be installed in the default location and be preconfigured
+ to auto-play the test clip.
+* Linux: The v4l2loopback kernel module must be compiled and loaded to the
+ kernel already and the v4l2_file_player application must be compiled and put
+ in the location specified below.
+
+NOTICE: When running this script as a buildbot step, make sure to set
+usePTY=False for the build step when adding it, or the subprocess will die as
+soon the step has executed.
+
+If any command line arguments are passed to the script, it is executed as a
+command in a subprocess.
+"""
+
+import os
+# psutil is not installed on non-Linux machines by default.
+import psutil # pylint: disable=F0401
+import subprocess
+import sys
+import time
+
+
+WEBCAM_WIN = ('schtasks', '/run', '/tn', 'ManyCam')
+WEBCAM_MAC = ('open', '/Applications/ManyCam/ManyCam.app')
+E = os.path.expandvars
+WEBCAM_LINUX = (
+ E('$HOME/fake-webcam-driver/linux/v4l2_file_player/v4l2_file_player'),
+ E('$HOME/webrtc_video_quality/reference_video.yuv'),
+ '640', '480', '/dev/video0',
+)
+
+
+def IsWebCamRunning():
+ if sys.platform == 'win32':
+ process_name = 'ManyCam.exe'
+ elif sys.platform.startswith('darwin'):
+ process_name = 'ManyCam'
+ elif sys.platform.startswith('linux'):
+ process_name = 'v4l2_file_player'
+ else:
+ raise Exception('Unsupported platform: %s' % sys.platform)
+ for p in psutil.process_iter():
+ try:
+ if process_name == p.name:
+ print 'Found a running virtual webcam (%s with PID %s)' % (p.name,
+ p.pid)
+ return True
+ except psutil.AccessDenied:
+ pass # This is normal if we query sys processes, etc.
+ return False
+
+
+def StartWebCam():
+ try:
+ if sys.platform == 'win32':
+ subprocess.check_call(WEBCAM_WIN)
+ print 'Successfully launched virtual webcam.'
+ elif sys.platform.startswith('darwin'):
+ subprocess.check_call(WEBCAM_MAC)
+ print 'Successfully launched virtual webcam.'
+ elif sys.platform.startswith('linux'):
+
+ # Must redirect stdout/stderr/stdin to avoid having the subprocess
+ # being killed when the parent shell dies (happens on the bots).
+ process = subprocess.Popen(WEBCAM_LINUX, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ # If the v4l2loopback module is not loaded or incorrectly configured,
+ # the process will still launch but will die immediately.
+ # Wait for a second and then check for aliveness to catch such errors.
+ time.sleep(1)
+ if process.poll() is None:
+ print 'Successfully launched virtual webcam with PID %s' % process.pid
+ else:
+ print 'Failed to launch virtual webcam.'
+ return False
+
+ except Exception as e:
+ print 'Failed to launch virtual webcam: %s' % e
+ return False
+
+ return True
+
+
+def _ForcePythonInterpreter(cmd):
+ """Returns the fixed command line to call the right python executable."""
+ out = cmd[:]
+ if out[0] == 'python':
+ out[0] = sys.executable
+ elif out[0].endswith('.py'):
+ out.insert(0, sys.executable)
+ return out
+
+
+def Main(argv):
+ if IsWebCamRunning():
+ return 0
+ if not StartWebCam():
+ return 1
+
+ if argv:
+ return subprocess.call(_ForcePythonInterpreter(argv))
+
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv[1:]))
diff --git a/tools_webrtc/mb/gn_isolate_map.pyl b/tools_webrtc/mb/gn_isolate_map.pyl
index ef18910..848a9b3 100644
--- a/tools_webrtc/mb/gn_isolate_map.pyl
+++ b/tools_webrtc/mb/gn_isolate_map.pyl
@@ -121,6 +121,7 @@
"video_capture_tests": {
"label": "//modules/video_capture:video_capture_tests",
"type": "console_test_launcher",
+ "use_webcam": True,
},
"video_engine_tests": {
"label": "//:video_engine_tests",
diff --git a/tools_webrtc/mb/mb.py b/tools_webrtc/mb/mb.py
index 0291066..e888367 100755
--- a/tools_webrtc/mb/mb.py
+++ b/tools_webrtc/mb/mb.py
@@ -844,18 +844,20 @@
else:
extra_files = ['../../testing/test_env.py']
+ if isolate_map[target].get('use_webcam', False):
+ cmdline.append('../../tools_webrtc/ensure_webcam_is_running.py')
+ extra_files.append('../../tools_webrtc/ensure_webcam_is_running.py')
+
# This needs to mirror the settings in //build/config/ui.gni:
# use_x11 = is_linux && !use_ozone.
use_x11 = is_linux and not 'use_ozone=true' in vals['gn_args']
xvfb = use_x11 and test_type == 'windowed_test_launcher'
if xvfb:
- extra_files += [
- '../../testing/xvfb.py',
- ]
-
- cmdline = (['../../testing/xvfb.py'] if xvfb else
- ['../../testing/test_env.py'])
+ cmdline.append('../../testing/xvfb.py')
+ extra_files.append('../../testing/xvfb.py')
+ else:
+ cmdline.append('../../testing/test_env.py')
# Memcheck is only supported for linux. Ignore in other platforms.
if is_linux and 'rtc_use_memcheck=true' in vals['gn_args']:
diff --git a/tools_webrtc/mb/mb_unittest.py b/tools_webrtc/mb/mb_unittest.py
index 6dea9b8..379a56d 100755
--- a/tools_webrtc/mb/mb_unittest.py
+++ b/tools_webrtc/mb/mb_unittest.py
@@ -711,6 +711,57 @@
'--tsan=0',
])
+ def test_isolate_test_launcher_with_webcam(self):
+ test_files = {
+ '/tmp/swarming_targets': 'base_unittests\n',
+ '/fake_src/testing/buildbot/gn_isolate_map.pyl': (
+ "{'base_unittests': {"
+ " 'label': '//base:base_unittests',"
+ " 'type': 'console_test_launcher',"
+ " 'use_webcam': True,"
+ "}}\n"
+ ),
+ '/fake_src/out/Default/base_unittests.runtime_deps': (
+ "base_unittests\n"
+ "some_resource_file\n"
+ ),
+ }
+ mbw = self.check(['gen', '-c', 'debug_goma', '//out/Default',
+ '--swarming-targets-file', '/tmp/swarming_targets',
+ '--isolate-map-file',
+ '/fake_src/testing/buildbot/gn_isolate_map.pyl'],
+ files=test_files, ret=0)
+
+ isolate_file = mbw.files['/fake_src/out/Default/base_unittests.isolate']
+ isolate_file_contents = ast.literal_eval(isolate_file)
+ files = isolate_file_contents['variables']['files']
+ command = isolate_file_contents['variables']['command']
+
+ self.assertEqual(files, [
+ '../../testing/test_env.py',
+ '../../third_party/gtest-parallel/gtest-parallel',
+ '../../third_party/gtest-parallel/gtest_parallel.py',
+ '../../tools_webrtc/ensure_webcam_is_running.py',
+ '../../tools_webrtc/gtest-parallel-wrapper.py',
+ 'base_unittests',
+ 'some_resource_file',
+ ])
+ self.assertEqual(command, [
+ '../../tools_webrtc/ensure_webcam_is_running.py',
+ '../../testing/test_env.py',
+ '../../tools_webrtc/gtest-parallel-wrapper.py',
+ '--output_dir=${ISOLATED_OUTDIR}/test_logs',
+ '--gtest_color=no',
+ '--timeout=900',
+ '--retry_failed=3',
+ './base_unittests',
+ '--',
+ '--asan=0',
+ '--lsan=0',
+ '--msan=0',
+ '--tsan=0',
+ ])
+
def test_isolate(self):
files = {
'/fake_src/out/Default/toolchain.ninja': "",