VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/audio/tdGuestHostTimings.py@ 106089

Last change on this file since 106089 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: tdGuestHostTimings.py 106061 2024-09-16 14:03:52Z vboxsync $
3
4"""
5????????
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2024 Oracle and/or its affiliates.
11
12This file is part of VirtualBox base platform packages, as
13available from https://www.virtualbox.org.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation, in version 3 of the
18License.
19
20This program is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, see <https://www.gnu.org/licenses>.
27
28The contents of this file may alternatively be used under the terms
29of the Common Development and Distribution License Version 1.0
30(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31in the VirtualBox distribution, in which case the provisions of the
32CDDL are applicable instead of those of the GPL.
33
34You may elect to license modified versions of this file under the
35terms and conditions of either the GPL or the CDDL or both.
36
37SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38"""
39__version__ = "$Revision: 106061 $"
40
41
42import os
43import sys
44import time
45import subprocess
46import re
47import time
48
49# Only the main script needs to modify the path.
50try: __file__ # pylint: disable=used-before-assignment
51except: __file__ = sys.argv[0];
52g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
53sys.path.append(g_ksValidationKitDir);
54
55# Validation Kit imports.
56from testdriver import reporter
57from testdriver import base
58from testdriver import vbox
59from testdriver import vboxcon
60from testdriver import vboxtestvms
61
62class tdGuestHostTimings(vbox.TestDriver): # pylint: disable=too-many-instance-attributes
63
64 def __init__(self):
65 vbox.TestDriver.__init__(self);
66 self.sSessionTypeDef = 'gui';
67
68 self.oTestVmSet = self.oTestVmManager.getStandardVmSet('nat') ## ???
69
70 # Use the command line "--test-vms mw7x64 execute" to run the only "mw7x64" VM
71 oTestVm = vboxtestvms.TestVm('mw7x64', oSet = self.oTestVmSet, sHd = 'mw7x64.vdi',
72 sKind = 'Windows7', acCpusSup = range(1, 2), fIoApic = True, sFirmwareType = 'bios',
73 asParavirtModesSup = ['hyperv'], asVirtModesSup = ['hwvirt-np'],
74 sHddControllerType = 'SATA Controller');
75
76 self.oTestVmSet.aoTestVms.append(oTestVm);
77
78 self.sVMname = None
79
80 def showUsage(self):
81 rc = vbox.TestDriver.showUsage(self);
82 reporter.log('');
83 reporter.log('tdGuestHostTimings Options:');
84 reporter.log(' --runningvmname <vmname>');
85 return rc;
86
87 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
88 if asArgs[iArg] == '--runningvmname':
89 iArg += 1
90 if iArg >= len(asArgs):
91 raise base.InvalidOption('The "----runningvmname" needs VM name')
92
93 self.sVMname = asArgs[iArg]
94 else:
95 return vbox.TestDriver.parseOption(self, asArgs, iArg)
96 return iArg + 1
97
98 def actionConfig(self):
99 return True
100
101 def actionExecute(self):
102 #self.sTempPathHost = os.environ.get("IPRT_TMPDIR")
103 self.sTempPathHost = os.path.normpath(os.environ.get("TEMP") + "/VBoxAudioValKit")
104
105 if self.sVMname is None:
106 return self.oTestVmSet.actionExecute(self, self.testOneVmConfig)
107 else:
108 return self.actionExecuteOnRunnigVM()
109
110 def doTest(self, oSession):
111 oConsole = oSession.console
112 oGuest = oConsole.guest
113
114 sOSTypeId = oGuest.OSTypeId.lower()
115 if sOSTypeId.find("win") == -1 :
116 reporter.log("Only Windows guests are currently supported")
117 reporter.testDone()
118 return True
119
120 oGuestSession = oGuest.createSession("Administrator", "password", "", "Audio Validation Kit")
121 guestSessionWaitResult = oGuestSession.waitFor(self.oVBoxMgr.constants.GuestSessionWaitResult_Start, 2000)
122 reporter.log("guestSessionWaitResult = %d" % guestSessionWaitResult)
123
124 for duration in range(3, 6):
125 reporter.testStart("Checking for duration of " + str(duration) + " seconds")
126 sPathToPlayer = "D:\\win\\" + ("amd64" if (sOSTypeId.find('_64') >= 0) else "x86") + "\\ntPlayToneWaveX.exe"
127 oProcess = oGuestSession.processCreate(sPathToPlayer, ["xxx0", "--total-duration-in-secs", str(duration)], [], [], 0)
128 processWaitResult = oProcess.waitFor(self.oVBoxMgr.constants.ProcessWaitForFlag_Start, 1000)
129 reporter.log("Started: pid %d, waitResult %d" % (oProcess.PID, processWaitResult))
130
131 processWaitResult = oProcess.waitFor(self.oVBoxMgr.constants.ProcessWaitForFlag_Terminate, 2 * duration * 1000)
132 reporter.log("Terminated: pid %d, waitResult %d" % (oProcess.PID, processWaitResult))
133 time.sleep(1) # Give audio backend sometime to save a stream to .wav file
134
135 absFileName = self.seekLatestAudioFileName(oGuestSession, duration)
136
137 if absFileName is None:
138 reporter.testFailure("Unable to find audio file")
139 continue
140
141 reporter.log("Checking audio file '" + absFileName + "'")
142
143 diff = self.checkGuestHostTimings(absFileName + ".timing")
144 if diff is not None:
145 if diff > 0.0: # Guest sends data quicker than a host can play
146 if diff > 0.01: # 1% is probably good threshold here
147 reporter.testFailure("Guest sends audio buffers too quickly")
148 else:
149 diff = -diff; # Much worse case: guest sends data very slow, host feels starvation
150 if diff > 0.005: # 0.5% is probably good threshold here
151 reporter.testFailure("Guest sends audio buffers too slowly")
152
153 reporter.testDone()
154 else:
155 reporter.testFailure("Unable to parse a file with timings")
156
157 oGuestSession.close()
158
159 del oGuest
160 del oConsole
161
162 return True
163
164 def testOneVmConfig(self, oVM, oTestVm):
165 #self.logVmInfo(oVM)
166 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName,
167 fCdWait = True,
168 cMsTimeout = 60 * 1000)
169 if oSession is not None and oTxsSession is not None:
170 # Wait until guest reported success
171 reporter.log('Guest started. Connection to TXS service established.')
172 self.doTest(oSessionWrapper.o)
173
174 return True
175
176 def actionExecuteOnRunnigVM(self):
177 if not self.importVBoxApi():
178 return False;
179
180 oVirtualBox = self.oVBoxMgr.getVirtualBox()
181 oMachine = oVirtualBox.findMachine(self.sVMname)
182
183 if oMachine == None:
184 reporter.log("Machine '%s' is unknown" % (oMachine.name))
185 return False
186
187 if oMachine.state != self.oVBoxMgr.constants.MachineState_Running:
188 reporter.log("Machine '%s' is not Running" % (oMachine.name))
189 return False
190
191 oSession = self.oVBoxMgr.mgr.getSessionObject(oVirtualBox)
192 oMachine.lockMachine(oSession, self.oVBoxMgr.constants.LockType_Shared)
193
194 self.doTest(oSession);
195
196 oSession.unlockMachine()
197
198 del oSession
199 del oMachine
200 del oVirtualBox
201 return True
202
203 def seekLatestAudioFileName(self, guestSession, duration):
204
205 listOfFiles = os.listdir(self.sTempPathHost)
206 # Assuming that .wav files are named like 2016-11-15T12_08_27.669573100Z.wav by VBOX audio backend
207 # So that sorting by name = sorting by creation date
208 listOfFiles.sort(reverse = True)
209
210 for fileName in listOfFiles:
211 if not fileName.endswith(".wav"):
212 continue
213
214 absFileName = os.path.join(self.sTempPathHost, fileName)
215
216 # Ignore too small wav files (usually uncompleted audio streams)
217 statInfo = os.stat(absFileName)
218 if statInfo.st_size > 100:
219 return absFileName
220
221 return
222
223 def checkGuestHostTimings(self, absFileName):
224 with open(absFileName) as f:
225 for line_terminated in f:
226 line = line_terminated.rstrip('\n')
227
228 reporter.log("Last line is: " + line)
229 matchObj = re.match( r'(\d+) (\d+)', line, re.I)
230 if matchObj:
231 hostTime = int(matchObj.group(1))
232 guestTime = int(matchObj.group(2))
233
234 diff = float(guestTime - hostTime) / hostTime
235 return diff
236
237 return
238
239if __name__ == '__main__':
240 sys.exit(tdGuestHostTimings().main(sys.argv));
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette