VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/audio/vkatCmdSelfTest.cpp@ 89643

Last change on this file since 89643 was 89643, checked in by vboxsync, 3 years ago

ValKit/Audio: Don't define g_aBackends in a header file. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Id: vkatCmdSelfTest.cpp 89643 2021-06-13 13:59:53Z vboxsync $ */
2/** @file
3 * Validation Kit Audio Test (VKAT) - Self test code.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31
32#include <iprt/ctype.h>
33#include <iprt/errcore.h>
34#include <iprt/getopt.h>
35#include <iprt/message.h>
36#include <iprt/test.h>
37
38#include "Audio/AudioHlp.h"
39#include "Audio/AudioTest.h"
40#include "Audio/AudioTestService.h"
41#include "Audio/AudioTestServiceClient.h"
42
43#include "vkatInternal.h"
44
45
46/**
47 * Thread callback for mocking the guest (VM) side of things.
48 *
49 * @returns VBox status code.
50 * @param hThread Thread handle.
51 * @param pvUser Pointer to user-supplied data.
52 */
53static DECLCALLBACK(int) audioTestSelftestGuestAtsThread(RTTHREAD hThread, void *pvUser)
54{
55 RT_NOREF(hThread);
56 PSELFTESTCTX pCtx = (PSELFTESTCTX)pvUser;
57
58 AUDIOTESTPARMS TstCust;
59 audioTestParmsInit(&TstCust);
60
61 PAUDIOTESTENV pTstEnv = &pCtx->Guest.TstEnv;
62
63 /* Flag the environment for self test mode. */
64 pTstEnv->fSelftest = true;
65
66 /* Generate tag for guest side. */
67 int rc = RTStrCopy(pTstEnv->szTag, sizeof(pTstEnv->szTag), pCtx->szTag);
68 AssertRCReturn(rc, rc);
69
70 rc = AudioTestPathCreateTemp(pTstEnv->szPathTemp, sizeof(pTstEnv->szPathTemp), "selftest-guest");
71 AssertRCReturn(rc, rc);
72
73 rc = AudioTestPathCreateTemp(pTstEnv->szPathOut, sizeof(pTstEnv->szPathOut), "selftest-out");
74 AssertRCReturn(rc, rc);
75
76 pTstEnv->enmMode = AUDIOTESTMODE_GUEST;
77
78 /** @todo Make this customizable. */
79 PDMAudioPropsInit(&TstCust.TestTone.Props,
80 2 /* 16-bit */, true /* fSigned */, 2 /* cChannels */, 44100 /* uHz */);
81
82 rc = audioTestEnvInit(pTstEnv, pTstEnv->DrvStack.pDrvReg, pCtx->fWithDrvAudio,
83 pCtx->Host.szValKitAtsAddr, pCtx->Host.uValKitAtsPort,
84 pCtx->Guest.szAtsAddr, pCtx->Guest.uAtsPort);
85 if (RT_SUCCESS(rc))
86 {
87 RTThreadUserSignal(hThread);
88
89 audioTestWorker(pTstEnv, &TstCust);
90 audioTestEnvDestroy(pTstEnv);
91 }
92
93 audioTestParmsDestroy(&TstCust);
94
95 return rc;
96}
97
98/**
99 * Main function for performing the self test.
100 *
101 * @returns RTEXITCODE
102 * @param pCtx Self test context to use.
103 */
104RTEXITCODE audioTestDoSelftest(PSELFTESTCTX pCtx)
105{
106 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Running self test ...\n");
107
108 /*
109 * The self-test does the following:
110 * - 1. a) Creates an ATS instance to emulate the guest mode ("--mode guest")
111 * at port 6042 (ATS_TCP_GUEST_DEFAULT_PORT).
112 * or
113 * b) Connect to an already existing guest ATS instance if "--guest-ats-address" is specified.
114 * This makes it more flexible in terms of testing / debugging.
115 * - 2. Uses the Validation Kit audio backend, which in turn creates an ATS instance
116 * at port 6052 (ATS_TCP_HOST_DEFAULT_PORT).
117 * - 3. Executes a complete test run locally (e.g. without any guest (VM) involved).
118 */
119
120 AUDIOTESTPARMS TstCust;
121 audioTestParmsInit(&TstCust);
122
123 /* Generate a common tag for guest and host side. */
124 int rc = AudioTestGenTag(pCtx->szTag, sizeof(pCtx->szTag));
125 AssertRCReturn(rc, RTEXITCODE_FAILURE);
126
127 PAUDIOTESTENV pTstEnv = &pCtx->Host.TstEnv;
128
129 /* Flag the environment for self test mode. */
130 pTstEnv->fSelftest = true;
131
132 /* Generate tag for host side. */
133 rc = RTStrCopy(pTstEnv->szTag, sizeof(pTstEnv->szTag), pCtx->szTag);
134 AssertRCReturn(rc, RTEXITCODE_FAILURE);
135
136 rc = AudioTestPathCreateTemp(pTstEnv->szPathTemp, sizeof(pTstEnv->szPathTemp), "selftest-tmp");
137 AssertRCReturn(rc, RTEXITCODE_FAILURE);
138
139 rc = AudioTestPathCreateTemp(pTstEnv->szPathOut, sizeof(pTstEnv->szPathOut), "selftest-out");
140 AssertRCReturn(rc, RTEXITCODE_FAILURE);
141
142 /*
143 * Step 1.
144 */
145 RTTHREAD hThreadGstAts = NIL_RTTHREAD;
146
147 bool const fStartGuestAts = RTStrNLen(pCtx->Host.szGuestAtsAddr, sizeof(pCtx->Host.szGuestAtsAddr)) == 0;
148 if (fStartGuestAts)
149 {
150 /* Step 1b. */
151 rc = RTThreadCreate(&hThreadGstAts, audioTestSelftestGuestAtsThread, pCtx, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
152 "VKATGstAts");
153 if (RT_SUCCESS(rc))
154 rc = RTThreadUserWait(hThreadGstAts, RT_MS_30SEC);
155 }
156 /* else Step 1a later. */
157
158 if (RT_SUCCESS(rc))
159 {
160 /*
161 * Steps 2 + 3.
162 */
163 pTstEnv->enmMode = AUDIOTESTMODE_HOST;
164
165 rc = audioTestEnvInit(pTstEnv, &g_DrvHostValidationKitAudio, true /* fWithDrvAudio */,
166 pCtx->Host.szValKitAtsAddr, pCtx->Host.uValKitAtsPort,
167 pCtx->Host.szGuestAtsAddr, pCtx->Host.uGuestAtsPort);
168 if (RT_SUCCESS(rc))
169 {
170 audioTestWorker(pTstEnv, &TstCust);
171 audioTestEnvDestroy(pTstEnv);
172 }
173 }
174
175 audioTestParmsDestroy(&TstCust);
176
177 /*
178 * Shutting down.
179 */
180 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Shutting down self test\n");
181
182 ASMAtomicWriteBool(&g_fTerminate, true);
183
184 if (fStartGuestAts)
185 {
186 int rcThread;
187 int rc2 = RTThreadWait(hThreadGstAts, RT_MS_30SEC, &rcThread);
188 if (RT_SUCCESS(rc2))
189 rc2 = rcThread;
190 if (RT_FAILURE(rc2))
191 RTTestFailed(g_hTest, "Shutting down guest ATS failed with %Rrc\n", rc2);
192 if (RT_SUCCESS(rc))
193 rc = rc2;
194 }
195
196 if (RT_FAILURE(rc))
197 RTTestFailed(g_hTest, "Self test failed with %Rrc\n", rc);
198
199 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
200}
201
202
203/*********************************************************************************************************************************
204* Command: selftest *
205*********************************************************************************************************************************/
206
207/**
208 * Long option values for the 'selftest' command.
209 */
210enum
211{
212 VKAT_SELFTEST_OPT_ATS_GUEST_ADDR = 900,
213 VKAT_SELFTEST_OPT_ATS_GUEST_PORT,
214 VKAT_SELFTEST_OPT_ATS_VALKIT_ADDR,
215 VKAT_SELFTEST_OPT_ATS_VALKIT_PORT
216};
217
218/**
219 * Command line parameters for self-test mode.
220 */
221static const RTGETOPTDEF s_aCmdSelftestOptions[] =
222{
223 { "--ats-guest-addr", VKAT_SELFTEST_OPT_ATS_GUEST_ADDR, RTGETOPT_REQ_STRING },
224 { "--ats-guest-port", VKAT_SELFTEST_OPT_ATS_GUEST_PORT, RTGETOPT_REQ_UINT32 },
225 { "--ats-valkit-addr", VKAT_SELFTEST_OPT_ATS_GUEST_ADDR, RTGETOPT_REQ_STRING },
226 { "--ats-valkit-port", VKAT_SELFTEST_OPT_ATS_GUEST_PORT, RTGETOPT_REQ_UINT32 },
227 { "--exclude-all", 'a', RTGETOPT_REQ_NOTHING },
228 { "--backend", 'b', RTGETOPT_REQ_STRING },
229 { "--with-drv-audio", 'd', RTGETOPT_REQ_NOTHING },
230 { "--exclude", 'e', RTGETOPT_REQ_UINT32 },
231 { "--include", 'i', RTGETOPT_REQ_UINT32 }
232};
233
234/** the 'selftest' command option help. */
235static DECLCALLBACK(const char *) audioTestCmdSelftestHelp(PCRTGETOPTDEF pOpt)
236{
237 switch (pOpt->iShort)
238 {
239 case 'b': return "The audio backend to use.";
240 case 'd': return "Go via DrvAudio instead of directly interfacing with the backend.";
241 default: return NULL;
242 }
243}
244
245/**
246 * The 'selftest' command handler.
247 *
248 * @returns Program exit code.
249 * @param pGetState RTGetOpt state.
250 */
251DECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState)
252{
253 SELFTESTCTX Ctx;
254 RT_ZERO(Ctx);
255
256 /* Go with the platform's default bakcend if nothing else is specified. */
257 Ctx.Guest.pDrvReg = AudioTestGetDefaultBackend();
258
259 /* Argument processing loop: */
260 int rc;
261 RTGETOPTUNION ValueUnion;
262 while ((rc = RTGetOpt(pGetState, &ValueUnion)) != 0)
263 {
264 switch (rc)
265 {
266 case VKAT_SELFTEST_OPT_ATS_GUEST_ADDR:
267 rc = RTStrCopy(Ctx.Host.szGuestAtsAddr, sizeof(Ctx.Host.szGuestAtsAddr), ValueUnion.psz);
268 break;
269
270 case VKAT_SELFTEST_OPT_ATS_GUEST_PORT:
271 Ctx.Host.uGuestAtsPort = ValueUnion.u32;
272 break;
273
274 case VKAT_SELFTEST_OPT_ATS_VALKIT_ADDR:
275 rc = RTStrCopy(Ctx.Host.szValKitAtsAddr, sizeof(Ctx.Host.szValKitAtsAddr), ValueUnion.psz);
276 break;
277
278 case VKAT_SELFTEST_OPT_ATS_VALKIT_PORT:
279 Ctx.Host.uValKitAtsPort = ValueUnion.u32;
280 break;
281
282 case 'a':
283 for (unsigned i = 0; i < g_cTests; i++)
284 g_aTests[i].fExcluded = true;
285 break;
286
287 case 'b':
288 Ctx.Guest.pDrvReg = AudioTestFindBackendOpt(ValueUnion.psz);
289 if (Ctx.Guest.pDrvReg == NULL)
290 return RTEXITCODE_SYNTAX;
291 break;
292
293 case 'd':
294 Ctx.fWithDrvAudio = true;
295 break;
296
297 case 'e':
298 if (ValueUnion.u32 >= g_cTests)
299 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --exclude", ValueUnion.u32);
300 g_aTests[ValueUnion.u32].fExcluded = true;
301 break;
302
303 case 'i':
304 if (ValueUnion.u32 >= g_cTests)
305 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --include", ValueUnion.u32);
306 g_aTests[ValueUnion.u32].fExcluded = false;
307 break;
308
309 AUDIO_TEST_COMMON_OPTION_CASES(ValueUnion);
310
311 default:
312 return RTGetOptPrintError(rc, &ValueUnion);
313 }
314 }
315
316 /*
317 * Start testing.
318 */
319 RTTestBanner(g_hTest);
320
321 int rc2 = audioTestDoSelftest(&Ctx);
322 if (RT_FAILURE(rc2))
323 RTTestFailed(g_hTest, "Self test failed with rc=%Rrc", rc2);
324
325 /*
326 * Print summary and exit.
327 */
328 return RTTestSummaryAndDestroy(g_hTest);
329}
330
331/**
332 * Command table entry for 'selftest'.
333 */
334const VKATCMD g_CmdSelfTest =
335{
336 "selftest",
337 audioTestCmdSelftestHandler,
338 "Performs self-tests.",
339 s_aCmdSelftestOptions,
340 RT_ELEMENTS(s_aCmdSelftestOptions),
341 audioTestCmdSelftestHelp,
342};
343
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