Bug 1763403 - Create multiple virtual sources using pulse on Linux, when --use-test-media-devices is passed. r=chunmin,ahal

Gecko is being taught to open multiple microphone at once in bug 1238038, this
allows testing complex scenarios locally and in automation.

Differential Revision: https://phabricator.services.mozilla.com/D143055
This commit is contained in:
Paul Adenot 2022-04-13 16:04:28 +00:00
parent b3f08bf9bd
commit 853f5390b7

View File

@ -2250,7 +2250,7 @@ toolbar#nav-bar {
return os.pathsep.join(gmp_paths)
def cleanup(self, options, final=False):
"""remove temporary files and profile"""
"""remove temporary files, profile and virtual audio input device"""
if hasattr(self, "manifest") and self.manifest is not None:
if os.path.exists(self.manifest):
os.remove(self.manifest)
@ -2272,6 +2272,24 @@ toolbar#nav-bar {
)
options.manifestFile = None
if hasattr(self, "virtualInputDeviceIdList"):
pactl = spawn.find_executable("pactl")
if not pactl:
self.log.error("Could not find pactl on system")
return None
for id in self.virtualInputDeviceIdList:
try:
subprocess.check_call([pactl, "unload-module", str(id)])
except subprocess.CalledProcessError:
self.log.error(
"Could not remove pulse module with id {}".format(id)
)
return None
self.virtualInputDeviceIdList = []
def dumpScreen(self, utilityPath):
if self.haveDumpedScreen:
self.log.info(
@ -2705,6 +2723,65 @@ toolbar#nav-bar {
options.manifestFile = None
options.profilePath = None
def initializeVirtualInputDevices(self):
"""
Configure the system to have a number of virtual audio input devices, that
each produce a tone at a particular frequency.
This method is only currently implemented for Linux.
"""
if not mozinfo.isLinux:
return
pactl = spawn.find_executable("pactl")
if not pactl:
self.log.error("Could not find pactl on system")
return
DEVICES_COUNT = 4
DEVICES_BASE_FREQUENCY = 110 # Hz
self.virtualInputDeviceIdList = []
# If the device are already present, find their id and return early
o = subprocess.check_output([pactl, "list", "modules", "short"])
found_devices = 0
for input in o.splitlines():
device = input.decode().split("\t")
if device[1] == "module-sine-source":
self.virtualInputDeviceIdList.append(int(device[0]))
found_devices += 1
if found_devices == DEVICES_COUNT:
return
elif found_devices != 0:
# Remove all devices and reinitialize them properly
for id in self.virtualInputDeviceIdList:
try:
subprocess.check_call([pactl, "unload-module", str(id)])
except subprocess.CalledProcessError:
log.error("Could not remove pulse module with id {}".format(id))
return None
# We want quite a number of input devices, each with a different tone
# frequency and device name so that we can recognize them easily during
# testing.
command = [pactl, "load-module", "module-sine-source", "rate=44100"]
for i in range(1, DEVICES_COUNT + 1):
freq = i * DEVICES_BASE_FREQUENCY
complete_command = command + [
"source_name=sine-{}".format(freq),
"frequency={}".format(freq),
]
try:
o = subprocess.check_output(complete_command)
self.virtualInputDeviceIdList.append(o)
except subprocess.CalledProcessError:
self.log.error(
"Could not create device with module-sine-source"
" (freq={})".format(freq)
)
def normalize_paths(self, paths):
# Normalize test paths so they are relative to test root
norm_paths = []
@ -3129,6 +3206,7 @@ toolbar#nav-bar {
self.log.error("Could not find test media devices to use")
return 1
self.mediaDevices = devices
self.initializeVirtualInputDevices()
# See if we were asked to run on Valgrind
valgrindPath = None