VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostAudioValidationKit.cpp@ 90176

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

Audio/ValKit: Added support for concurrent playback + recording tests to the ValKit audio driver. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.2 KB
Line 
1/* $Id: DrvHostAudioValidationKit.cpp 90056 2021-07-06 11:15:47Z vboxsync $ */
2/** @file
3 * Host audio driver - ValidationKit - For dumping and injecting audio data from/to the device emulation.
4 */
5
6/*
7 * Copyright (C) 2016-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
18
19/*********************************************************************************************************************************
20* Defined Constants And Macros *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
23#include <iprt/dir.h>
24#include <iprt/env.h>
25#include <iprt/mem.h>
26#include <iprt/path.h>
27#include <iprt/semaphore.h>
28#include <iprt/stream.h>
29#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
30
31#include <VBox/log.h>
32#include <VBox/vmm/pdmaudioifs.h>
33#include <VBox/vmm/pdmaudioinline.h>
34
35#include "VBoxDD.h"
36#include "AudioHlp.h"
37#include "AudioTest.h"
38#include "AudioTestService.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Structure for keeping a Validation Kit input/output stream.
46 */
47typedef struct VALKITAUDIOSTREAM
48{
49 /** Common part. */
50 PDMAUDIOBACKENDSTREAM Core;
51 /** The stream's acquired configuration. */
52 PDMAUDIOSTREAMCFG Cfg;
53} VALKITAUDIOSTREAM;
54/** Pointer to a Validation Kit stream. */
55typedef VALKITAUDIOSTREAM *PVALKITAUDIOSTREAM;
56
57/**
58 * Test tone-specific instance data.
59 */
60typedef struct VALKITTESTTONEDATA
61{
62 union
63 {
64 struct
65 {
66 /** How many bytes to write. */
67 uint64_t cbToWrite;
68 /** How many bytes already written. */
69 uint64_t cbWritten;
70 } Rec;
71 struct
72 {
73 /** How many bytes to read. */
74 uint64_t cbToRead;
75 /** How many bytes already read. */
76 uint64_t cbRead;
77 } Play;
78 } u;
79 /** The test tone instance to use. */
80 AUDIOTESTTONE Tone;
81 /** The test tone parameters to use. */
82 AUDIOTESTTONEPARMS Parms;
83} VALKITTESTTONEDATA;
84
85/**
86 * Structure keeping a single Validation Kit test.
87 */
88typedef struct VALKITTESTDATA
89{
90 /** The list node. */
91 RTLISTNODE Node;
92 /** Index in test sequence (0-based). */
93 uint32_t idxTest;
94 /** Current test set entry to process. */
95 PAUDIOTESTENTRY pEntry;
96 /** Current test object to process. */
97 AUDIOTESTOBJ Obj;
98 /** Stream configuration to use for this test. */
99 PDMAUDIOSTREAMCFG StreamCfg;
100 union
101 {
102 /** Test tone-specific data. */
103 VALKITTESTTONEDATA TestTone;
104 } t;
105 /** Time stamp (real, in ms) when test started. */
106 uint64_t msStartedTS;
107} VALKITTESTDATA;
108/** Pointer to Validation Kit test data. */
109typedef VALKITTESTDATA *PVALKITTESTDATA;
110
111/**
112 * Validation Kit audio driver instance data.
113 * @implements PDMIAUDIOCONNECTOR
114 */
115typedef struct DRVHOSTVALKITAUDIO
116{
117 /** Pointer to the driver instance structure. */
118 PPDMDRVINS pDrvIns;
119 /** Pointer to host audio interface. */
120 PDMIHOSTAUDIO IHostAudio;
121 /** Temporary path to use. */
122 char szPathTemp[RTPATH_MAX];
123 /** Output path to use. */
124 char szPathOut[RTPATH_MAX];
125 /** Current test set being handled. */
126 AUDIOTESTSET Set;
127 /** Number of total tests created. */
128 uint32_t cTestsTotal;
129 /** Number of tests in \a lstTestsRec. */
130 uint32_t cTestsRec;
131 /** List keeping the recording tests (FIFO). */
132 RTLISTANCHOR lstTestsRec;
133 /** Pointer to current recording test being processed.
134 * NULL if no current test active. */
135 PVALKITTESTDATA pTestCurRec;
136 /** Number of tests in \a lstTestsPlay. */
137 uint32_t cTestsPlay;
138 /** List keeping the recording tests (FIFO). */
139 RTLISTANCHOR lstTestsPlay;
140 /** Pointer to current playback test being processed.
141 * NULL if no current test active. */
142 PVALKITTESTDATA pTestCurPlay;
143 /** Critical section for serializing access across threads. */
144 RTCRITSECT CritSect;
145 bool fTestSetEnded;
146 RTSEMEVENT EventSemEnded;
147 /** The Audio Test Service (ATS) instance. */
148 ATSSERVER Srv;
149 /** Absolute path to the packed up test set archive.
150 * Keep it simple for now and only support one (open) archive at a time. */
151 char szTestSetArchive[RTPATH_MAX];
152 /** File handle to the (opened) test set archive for reading. */
153 RTFILE hTestSetArchive;
154
155} DRVHOSTVALKITAUDIO;
156/** Pointer to a Validation Kit host audio driver instance. */
157typedef DRVHOSTVALKITAUDIO *PDRVHOSTVALKITAUDIO;
158
159
160/*********************************************************************************************************************************
161* Internal test handling code *
162*********************************************************************************************************************************/
163
164/**
165 * Unregisters a ValKit test, common code.
166 *
167 * @param pTst Test to unregister.
168 * The pointer will be invalid afterwards.
169 */
170static void drvHostValKiUnregisterTest(PVALKITTESTDATA pTst)
171{
172 AssertPtrReturnVoid(pTst);
173
174 RTListNodeRemove(&pTst->Node);
175
176 AudioTestObjClose(pTst->Obj);
177 pTst->Obj = NULL;
178
179 if (pTst->pEntry) /* Set set entry assign? Mark as done. */
180 {
181 AssertPtrReturnVoid(pTst->pEntry);
182 pTst->pEntry = NULL;
183 }
184
185 RTMemFree(pTst);
186 pTst = NULL;
187}
188
189/**
190 * Unregisters a ValKit recording test.
191 *
192 * @param pThis ValKit audio driver instance.
193 * @param pTst Test to unregister.
194 * The pointer will be invalid afterwards.
195 */
196static void drvHostValKiUnregisterRecTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
197{
198 drvHostValKiUnregisterTest(pTst);
199
200 Assert(pThis->cTestsRec);
201 pThis->cTestsRec--;
202}
203
204/**
205 * Unregisters a ValKit playback test.
206 *
207 * @param pThis ValKit audio driver instance.
208 * @param pTst Test to unregister.
209 * The pointer will be invalid afterwards.
210 */
211static void drvHostValKiUnregisterPlayTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
212{
213 drvHostValKiUnregisterTest(pTst);
214
215 Assert(pThis->cTestsPlay);
216 pThis->cTestsPlay--;
217}
218
219/**
220 * Performs some internal cleanup / housekeeping of all registered tests.
221 *
222 * @param pThis ValKit audio driver instance.
223 */
224static void drvHostValKitCleanup(PDRVHOSTVALKITAUDIO pThis)
225{
226 LogRel(("ValKit: Cleaning up ...\n"));
227
228 if (pThis->cTestsRec)
229 LogRel(("ValKit: Warning: %RU32 guest recording tests still outstanding:\n", pThis->cTestsRec));
230
231 PVALKITTESTDATA pTst, pTstNext;
232 RTListForEachSafe(&pThis->lstTestsRec, pTst, pTstNext, VALKITTESTDATA, Node)
233 {
234 size_t const cbOutstanding = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
235 if (cbOutstanding)
236 LogRel(("ValKit: \tRecording test #%RU32 has %RU64 bytes (%RU32ms) outstanding\n",
237 pTst->idxTest, cbOutstanding, PDMAudioPropsBytesToMilli(&pTst->t.TestTone.Parms.Props, (uint32_t)cbOutstanding)));
238 drvHostValKiUnregisterRecTest(pThis, pTst);
239 }
240
241 if (pThis->cTestsPlay)
242 LogRel(("ValKit: Warning: %RU32 guest playback tests still outstanding:\n", pThis->cTestsPlay));
243
244 RTListForEachSafe(&pThis->lstTestsPlay, pTst, pTstNext, VALKITTESTDATA, Node)
245 {
246 size_t const cbOutstanding = pTst->t.TestTone.u.Play.cbToRead - pTst->t.TestTone.u.Play.cbRead;
247 if (cbOutstanding)
248 LogRel(("ValKit: \tPlayback test #%RU32 has %RU64 bytes (%RU32ms) outstanding\n",
249 pTst->idxTest, cbOutstanding, PDMAudioPropsBytesToMilli(&pTst->t.TestTone.Parms.Props, (uint32_t)cbOutstanding)));
250 drvHostValKiUnregisterPlayTest(pThis, pTst);
251 }
252
253 Assert(pThis->cTestsRec == 0);
254 Assert(pThis->cTestsPlay == 0);
255}
256
257
258/*********************************************************************************************************************************
259* ATS callback implementations *
260*********************************************************************************************************************************/
261
262/** @copydoc ATSCALLBACKS::pfnTestSetBegin */
263static DECLCALLBACK(int) drvHostValKitTestSetBegin(void const *pvUser, const char *pszTag)
264{
265 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
266
267 int rc = RTCritSectEnter(&pThis->CritSect);
268 if (RT_SUCCESS(rc))
269 {
270
271 LogRel(("ValKit: Beginning test set '%s'\n", pszTag));
272 rc = AudioTestSetCreate(&pThis->Set, pThis->szPathTemp, pszTag);
273
274 int rc2 = RTCritSectLeave(&pThis->CritSect);
275 if (RT_SUCCESS(rc))
276 rc = rc2;
277 }
278
279 if (RT_FAILURE(rc))
280 LogRel(("ValKit: Beginning test set failed with %Rrc\n", rc));
281
282 return rc;
283}
284
285/** @copydoc ATSCALLBACKS::pfnTestSetEnd */
286static DECLCALLBACK(int) drvHostValKitTestSetEnd(void const *pvUser, const char *pszTag)
287{
288 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
289
290 int rc = RTCritSectEnter(&pThis->CritSect);
291 if (RT_SUCCESS(rc))
292 {
293 const PAUDIOTESTSET pSet = &pThis->Set;
294
295 if (AudioTestSetIsRunning(pSet))
296 {
297 pThis->fTestSetEnded = true;
298
299 rc = RTCritSectLeave(&pThis->CritSect);
300 if (RT_SUCCESS(rc))
301 {
302 LogRel(("ValKit: Waiting for runnig test set '%s' to end ...\n", pszTag));
303 rc = RTSemEventWait(pThis->EventSemEnded, RT_MS_30SEC);
304
305 int rc2 = RTCritSectEnter(&pThis->CritSect);
306 if (RT_SUCCESS(rc))
307 rc = rc2;
308 }
309 }
310
311 if (RT_SUCCESS(rc))
312 {
313 LogRel(("ValKit: Ending test set '%s'\n", pszTag));
314
315 /* Close the test set first. */
316 rc = AudioTestSetClose(pSet);
317 if (RT_SUCCESS(rc))
318 {
319 /* Before destroying the test environment, pack up the test set so
320 * that it's ready for transmission. */
321 rc = AudioTestSetPack(pSet, pThis->szPathOut, pThis->szTestSetArchive, sizeof(pThis->szTestSetArchive));
322 if (RT_SUCCESS(rc))
323 LogRel(("ValKit: Packed up to '%s'\n", pThis->szTestSetArchive));
324
325 /* Do some internal housekeeping. */
326 drvHostValKitCleanup(pThis);
327
328#ifndef DEBUG_andy
329 int rc2 = AudioTestSetWipe(pSet);
330 if (RT_SUCCESS(rc))
331 rc = rc2;
332#endif
333 }
334
335 AudioTestSetDestroy(pSet);
336 }
337
338 int rc2 = RTCritSectLeave(&pThis->CritSect);
339 if (RT_SUCCESS(rc))
340 rc = rc2;
341 }
342
343 if (RT_FAILURE(rc))
344 LogRel(("ValKit: Ending test set failed with %Rrc\n", rc));
345
346 return rc;
347}
348
349/** @copydoc ATSCALLBACKS::pfnTonePlay
350 *
351 * Creates and registers a new test tone guest recording test.
352 * This backend will play (inject) input data to the guest.
353 */
354static DECLCALLBACK(int) drvHostValKitRegisterGuestRecTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
355{
356 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
357
358 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
359 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
360
361 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
362
363 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
364 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
365
366 AudioTestToneInit(&pTestData->t.TestTone.Tone, &pTestData->t.TestTone.Parms.Props, pTestData->t.TestTone.Parms.dbFreqHz);
367
368 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
369 pTestData->t.TestTone.Parms.msDuration);
370 int rc = RTCritSectEnter(&pThis->CritSect);
371 if (RT_SUCCESS(rc))
372 {
373 LogRel(("ValKit: Registered guest recording test #%RU32 (%RU32ms, %RU64 bytes)\n",
374 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
375
376 RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
377
378 pTestData->idxTest = pThis->cTestsTotal++;
379
380 pThis->cTestsRec++;
381
382 int rc2 = RTCritSectLeave(&pThis->CritSect);
383 AssertRC(rc2);
384 }
385
386 return VINF_SUCCESS;
387}
388
389/** @copydoc ATSCALLBACKS::pfnToneRecord
390 *
391 * Creates and registers a new test tone guest playback test.
392 * This backend will record the guest output data.
393 */
394static DECLCALLBACK(int) drvHostValKitRegisterGuestPlayTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
395{
396 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
397
398 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
399 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
400
401 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
402
403 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
404 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
405
406 pTestData->t.TestTone.u.Play.cbToRead = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
407 pTestData->t.TestTone.Parms.msDuration);
408 int rc = RTCritSectEnter(&pThis->CritSect);
409 if (RT_SUCCESS(rc))
410 {
411 LogRel(("ValKit: Registered guest playback test #%RU32 (%RU32ms, %RU64 bytes)\n",
412 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Play.cbToRead));
413
414 RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
415
416 pTestData->idxTest = pThis->cTestsTotal++;
417
418 pThis->cTestsPlay++;
419
420 int rc2 = RTCritSectLeave(&pThis->CritSect);
421 AssertRC(rc2);
422 }
423
424 return VINF_SUCCESS;
425}
426
427/** @copydoc ATSCALLBACKS::pfnTestSetSendBegin */
428static DECLCALLBACK(int) drvHostValKitTestSetSendBeginCallback(void const *pvUser, const char *pszTag)
429{
430 RT_NOREF(pszTag);
431
432 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
433
434 int rc = RTCritSectEnter(&pThis->CritSect);
435 if (RT_SUCCESS(rc))
436 {
437 if (RTFileExists(pThis->szTestSetArchive)) /* Has the archive successfully been created yet? */
438 {
439 rc = RTFileOpen(&pThis->hTestSetArchive, pThis->szTestSetArchive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
440 if (RT_SUCCESS(rc))
441 {
442 uint64_t uSize;
443 rc = RTFileQuerySize(pThis->hTestSetArchive, &uSize);
444 if (RT_SUCCESS(rc))
445 LogRel(("ValKit: Sending test set '%s' (%zu bytes)\n", pThis->szTestSetArchive, uSize));
446 }
447 }
448 else
449 rc = VERR_FILE_NOT_FOUND;
450
451 int rc2 = RTCritSectLeave(&pThis->CritSect);
452 if (RT_SUCCESS(rc))
453 rc = rc2;
454 }
455
456 if (RT_FAILURE(rc))
457 LogRel(("ValKit: Beginning to send test set failed with %Rrc\n", rc));
458
459 return rc;
460}
461
462/** @copydoc ATSCALLBACKS::pfnTestSetSendRead */
463static DECLCALLBACK(int) drvHostValKitTestSetSendReadCallback(void const *pvUser,
464 const char *pszTag, void *pvBuf, size_t cbBuf, size_t *pcbRead)
465{
466 RT_NOREF(pszTag);
467
468 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
469
470 int rc = RTCritSectEnter(&pThis->CritSect);
471 if (RT_SUCCESS(rc))
472 {
473 if (RTFileIsValid(pThis->hTestSetArchive))
474 {
475 rc = RTFileRead(pThis->hTestSetArchive, pvBuf, cbBuf, pcbRead);
476 }
477 else
478 rc = VERR_WRONG_ORDER;
479
480 int rc2 = RTCritSectLeave(&pThis->CritSect);
481 if (RT_SUCCESS(rc))
482 rc = rc2;
483 }
484
485 if (RT_FAILURE(rc))
486 LogRel(("ValKit: Reading from test set failed with %Rrc\n", rc));
487
488 return rc;
489}
490
491/** @copydoc ATSCALLBACKS::pfnTestSetSendEnd */
492static DECLCALLBACK(int) drvHostValKitTestSetSendEndCallback(void const *pvUser, const char *pszTag)
493{
494 RT_NOREF(pszTag);
495
496 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
497
498 int rc = RTCritSectEnter(&pThis->CritSect);
499 if (RT_SUCCESS(rc))
500 {
501 if (RTFileIsValid(pThis->hTestSetArchive))
502 {
503 rc = RTFileClose(pThis->hTestSetArchive);
504 if (RT_SUCCESS(rc))
505 pThis->hTestSetArchive = NIL_RTFILE;
506 }
507
508 int rc2 = RTCritSectLeave(&pThis->CritSect);
509 if (RT_SUCCESS(rc))
510 rc = rc2;
511 }
512
513 if (RT_FAILURE(rc))
514 LogRel(("ValKit: Ending to send test set failed with %Rrc\n", rc));
515
516 return rc;
517}
518
519
520/*********************************************************************************************************************************
521* PDMIHOSTAUDIO interface implementation *
522*********************************************************************************************************************************/
523
524/**
525 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
526 */
527static DECLCALLBACK(int) drvHostValKitAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
528{
529 RT_NOREF(pInterface);
530 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
531
532 /*
533 * Fill in the config structure.
534 */
535 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Validation Kit");
536 pBackendCfg->cbStream = sizeof(VALKITAUDIOSTREAM);
537 pBackendCfg->fFlags = 0;
538 pBackendCfg->cMaxStreamsOut = 1; /* Output (Playback). */
539 pBackendCfg->cMaxStreamsIn = 1; /* Input (Recording). */
540
541 return VINF_SUCCESS;
542}
543
544
545/**
546 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
547 */
548static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostValKitAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
549{
550 RT_NOREF(enmDir);
551 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
552
553 return PDMAUDIOBACKENDSTS_RUNNING;
554}
555
556
557/**
558 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
559 */
560static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
561 PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
562{
563 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
564 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
565 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
566 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
567 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
568 RT_NOREF(pThis);
569
570 int rc = VINF_SUCCESS;
571 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
572 return rc;
573}
574
575/**
576 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
577 */
578static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
579 bool fImmediate)
580{
581 RT_NOREF(pInterface, fImmediate);
582 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
583 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
584
585 return VINF_SUCCESS;
586}
587
588
589/**
590 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
591 */
592static DECLCALLBACK(int) drvHostValKitAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
593{
594 RT_NOREF(pInterface, pStream);
595 return VINF_SUCCESS;
596}
597
598
599/**
600 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
601 */
602static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
603{
604 RT_NOREF(pInterface, pStream);
605 return VINF_SUCCESS;
606}
607
608
609/**
610 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
611 */
612static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
613{
614 RT_NOREF(pInterface, pStream);
615 return VINF_SUCCESS;
616}
617
618
619/**
620 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
621 */
622static DECLCALLBACK(int) drvHostValKitAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
623{
624 RT_NOREF(pInterface, pStream);
625 return VINF_SUCCESS;
626}
627
628
629/**
630 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
631 */
632static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
633{
634 RT_NOREF(pStream);
635
636 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
637
638 int rc = RTCritSectEnter(&pThis->CritSect);
639 if (RT_SUCCESS(rc))
640 {
641 PVALKITTESTDATA pTst = pThis->pTestCurPlay;
642
643 if (pTst)
644 {
645 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
646 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
647
648 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
649 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
650 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
651
652 AudioTestSetTestDone(pTst->pEntry);
653
654 pThis->pTestCurPlay = NULL;
655 pTst = NULL;
656
657 if (pThis->fTestSetEnded)
658 rc = RTSemEventSignal(pThis->EventSemEnded);
659 }
660
661 int rc2 = RTCritSectLeave(&pThis->CritSect);
662 AssertRC(rc2);
663 }
664
665 return VINF_SUCCESS;
666}
667
668
669/**
670 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
671 */
672static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
673{
674 RT_NOREF(pStream);
675
676 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
677 PVALKITTESTDATA pTst = NULL;
678
679 int rc = RTCritSectEnter(&pThis->CritSect);
680 if (RT_SUCCESS(rc))
681 {
682 pTst = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
683
684 int rc2 = RTCritSectLeave(&pThis->CritSect);
685 AssertRC(rc2);
686 }
687
688 if (pTst == NULL) /* Empty list? */
689 return 0;
690
691 Assert(pTst->t.TestTone.u.Rec.cbToWrite >= pTst->t.TestTone.u.Rec.cbWritten);
692 return pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
693}
694
695
696/**
697 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
698 */
699static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
700{
701 RT_NOREF(pInterface, pStream);
702 return UINT32_MAX;
703}
704
705
706/**
707 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
708 */
709static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
710 PPDMAUDIOBACKENDSTREAM pStream)
711{
712 RT_NOREF(pInterface);
713 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
714 return PDMHOSTAUDIOSTREAMSTATE_OKAY;
715}
716
717
718/**
719 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
720 */
721static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
722 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
723{
724 if (cbBuf == 0)
725 {
726 /* Fend off draining calls. */
727 *pcbWritten = 0;
728 return VINF_SUCCESS;
729 }
730
731 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
732 PVALKITTESTDATA pTst = NULL;
733
734 bool const fIsSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBuf, cbBuf);
735
736 int rc = RTCritSectEnter(&pThis->CritSect);
737 if (RT_SUCCESS(rc))
738 {
739 if (pThis->pTestCurPlay == NULL)
740 {
741 pThis->pTestCurPlay = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
742 if (pThis->pTestCurPlay)
743 LogRel(("ValKit: Next guest playback test in queue is test #%RU32\n", pThis->pTestCurPlay->idxTest));
744 }
745
746 pTst = pThis->pTestCurPlay;
747
748 int rc2 = RTCritSectLeave(&pThis->CritSect);
749 AssertRC(rc2);
750 }
751
752 if (pTst == NULL) /* Empty list? */
753 {
754#ifdef DEBUG_andy
755 if (!fIsSilence)
756#endif
757 LogRel(("ValKit: Warning: Guest is playing back audio (%s, %RU32 bytes, %RU64ms) when no playback test is active\n",
758 fIsSilence ? "silence" : "audible", cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
759
760 *pcbWritten = cbBuf;
761 return VINF_SUCCESS;
762 }
763
764#ifndef DEBUG_andy
765 if (fIsSilence)
766 LogRel2(("ValKit: Guest is playing back %RU32 bytes (%RU64ms) silence\n",
767 cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
768#endif
769
770 const bool fHandleSilence = false; /** @todo Skip blocks of entire silence for now. */
771
772 if (pTst->pEntry == NULL) /* Test not started yet? */
773 {
774 AUDIOTESTPARMS Parms;
775 RT_ZERO(Parms);
776 Parms.enmDir = PDMAUDIODIR_IN;
777 Parms.enmType = AUDIOTESTTYPE_TESTTONE_RECORD;
778 Parms.TestTone = pTst->t.TestTone.Parms;
779
780 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
781 &Parms, &pTst->pEntry);
782 if (RT_SUCCESS(rc))
783 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-rec.pcm", &pTst->Obj);
784
785 if (RT_SUCCESS(rc))
786 {
787 pTst->msStartedTS = RTTimeMilliTS();
788 LogRel(("ValKit: Test #%RU32: Recording audio data (%RU16Hz, %RU32ms) started\n",
789 pTst->idxTest, (uint16_t)Parms.TestTone.dbFreqHz, Parms.TestTone.msDuration));
790 }
791 }
792
793 uint32_t cbWritten = 0;
794
795 if (RT_SUCCESS(rc))
796 {
797 if ( !fIsSilence
798 || (fIsSilence && fHandleSilence))
799 {
800 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbBuf);
801 pTst->t.TestTone.u.Play.cbRead += cbBuf;
802
803 const bool fComplete = pTst->t.TestTone.u.Play.cbRead >= pTst->t.TestTone.u.Play.cbToRead;
804 if (fComplete)
805 {
806 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
807 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
808
809 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
810 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
811 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
812
813 AudioTestSetTestDone(pTst->pEntry);
814
815 rc = RTCritSectEnter(&pThis->CritSect);
816 if (RT_SUCCESS(rc))
817 {
818 drvHostValKiUnregisterPlayTest(pThis, pTst);
819
820 pThis->pTestCurPlay = NULL;
821 pTst = NULL;
822
823 int rc2 = RTCritSectLeave(&pThis->CritSect);
824 if (RT_SUCCESS(rc))
825 rc = rc2;
826 }
827 }
828 }
829
830 /* Always report everything as being played. */
831 cbWritten = cbBuf;
832 }
833
834 if (RT_FAILURE(rc))
835 {
836 if ( pTst
837 && pTst->pEntry)
838 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
839 LogRel(("ValKit: Recording audio data failed with %Rrc\n", rc));
840 }
841
842 *pcbWritten = cbWritten;
843
844 return VINF_SUCCESS; /** @todo Return rc here? */
845}
846
847
848/**
849 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
850 */
851static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
852 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
853{
854 RT_NOREF(pStream);
855
856 if (cbBuf == 0)
857 {
858 /* Fend off draining calls. */
859 *pcbRead = 0;
860 return VINF_SUCCESS;
861 }
862
863 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
864 PVALKITTESTDATA pTst = NULL;
865
866 int rc = RTCritSectEnter(&pThis->CritSect);
867 if (RT_SUCCESS(rc))
868 {
869 if (pThis->pTestCurRec == NULL)
870 {
871 pThis->pTestCurRec = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
872 if (pThis->pTestCurRec)
873 LogRel(("ValKit: Next guest recording test in queue is test #%RU32\n", pThis->pTestCurRec->idxTest));
874 }
875
876 pTst = pThis->pTestCurRec;
877
878 int rc2 = RTCritSectLeave(&pThis->CritSect);
879 AssertRC(rc2);
880 }
881
882 if (pTst == NULL) /* Empty list? */
883 {
884 LogRelMax(64, ("ValKit: Warning: Guest is trying to record audio data when no recording test is active\n"));
885
886 *pcbRead = 0;
887 return VINF_SUCCESS;
888 }
889
890 if (pTst->pEntry == NULL) /* Test not started yet? */
891 {
892 AUDIOTESTPARMS Parms;
893 RT_ZERO(Parms);
894 Parms.enmDir = PDMAUDIODIR_OUT;
895 Parms.enmType = AUDIOTESTTYPE_TESTTONE_PLAY;
896 Parms.TestTone = pTst->t.TestTone.Parms;
897
898 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
899 &Parms, &pTst->pEntry);
900 if (RT_SUCCESS(rc))
901 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-play.pcm", &pTst->Obj);
902
903 if (RT_SUCCESS(rc))
904 {
905 pTst->msStartedTS = RTTimeMilliTS();
906 LogRel(("ValKit: Injecting audio input data (%RU16Hz, %RU32ms) started\n",
907 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
908 pTst->t.TestTone.Parms.msDuration));
909 }
910 }
911
912 uint32_t cbRead = 0;
913
914 if (RT_SUCCESS(rc))
915 {
916 uint32_t cbToWrite = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
917 if (cbToWrite)
918 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, RT_MIN(cbToWrite, cbBuf), &cbRead);
919 if ( RT_SUCCESS(rc)
920 && cbRead)
921 {
922 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbRead);
923 if (RT_SUCCESS(rc))
924 {
925 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
926 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
927
928 const bool fComplete = pTst->t.TestTone.u.Rec.cbToWrite >= pTst->t.TestTone.u.Rec.cbWritten;
929 if (fComplete)
930 {
931 LogRel(("ValKit: Injecting audio input data done (took %RU32ms)\n",
932 RTTimeMilliTS() - pTst->msStartedTS));
933
934 AudioTestSetTestDone(pTst->pEntry);
935
936 rc = RTCritSectEnter(&pThis->CritSect);
937 if (RT_SUCCESS(rc))
938 {
939 drvHostValKiUnregisterRecTest(pThis, pTst);
940
941 pThis->pTestCurRec = NULL;
942 pTst = NULL;
943
944 int rc2 = RTCritSectLeave(&pThis->CritSect);
945 AssertRC(rc2);
946 }
947 }
948 }
949 }
950 }
951
952 if (RT_FAILURE(rc))
953 {
954 if ( pTst
955 && pTst->pEntry)
956 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
957 LogRel(("ValKit: Injecting audio input data failed with %Rrc\n", rc));
958 }
959
960 *pcbRead = cbRead;
961
962 return VINF_SUCCESS; /** @todo Return rc here? */
963}
964
965
966/**
967 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
968 */
969static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
970{
971 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
972 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
973
974 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
975 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
976 return NULL;
977}
978
979
980/**
981 * Constructs a VaKit audio driver instance.
982 *
983 * @copydoc FNPDMDRVCONSTRUCT
984 */
985static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
986{
987 RT_NOREF(pCfg, fFlags);
988 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
989 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
990 LogRel(("Audio: Initializing VALKIT driver\n"));
991
992 /*
993 * Init the static parts.
994 */
995 pThis->pDrvIns = pDrvIns;
996 /* IBase */
997 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
998 /* IHostAudio */
999 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
1000 pThis->IHostAudio.pfnGetDevices = NULL;
1001 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
1002 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
1003 pThis->IHostAudio.pfnStreamConfigHint = NULL;
1004 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
1005 pThis->IHostAudio.pfnStreamInitAsync = NULL;
1006 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
1007 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
1008 pThis->IHostAudio.pfnStreamEnable = drvHostValKitAudioHA_StreamEnable;
1009 pThis->IHostAudio.pfnStreamDisable = drvHostValKitAudioHA_StreamDisable;
1010 pThis->IHostAudio.pfnStreamPause = drvHostValKitAudioHA_StreamPause;
1011 pThis->IHostAudio.pfnStreamResume = drvHostValKitAudioHA_StreamResume;
1012 pThis->IHostAudio.pfnStreamDrain = drvHostValKitAudioHA_StreamDrain;
1013 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
1014 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
1015 pThis->IHostAudio.pfnStreamGetPending = NULL;
1016 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
1017 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
1018 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
1019
1020 int rc = RTCritSectInit(&pThis->CritSect);
1021 AssertRCReturn(rc, rc);
1022 rc = RTSemEventCreate(&pThis->EventSemEnded);
1023 AssertRCReturn(rc, rc);
1024
1025 pThis->fTestSetEnded = false;
1026
1027 RTListInit(&pThis->lstTestsRec);
1028 pThis->cTestsRec = 0;
1029 RTListInit(&pThis->lstTestsPlay);
1030 pThis->cTestsPlay = 0;
1031
1032 ATSCALLBACKS Callbacks;
1033 RT_ZERO(Callbacks);
1034 Callbacks.pfnTestSetBegin = drvHostValKitTestSetBegin;
1035 Callbacks.pfnTestSetEnd = drvHostValKitTestSetEnd;
1036 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
1037 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
1038 Callbacks.pfnTestSetSendBegin = drvHostValKitTestSetSendBeginCallback;
1039 Callbacks.pfnTestSetSendRead = drvHostValKitTestSetSendReadCallback;
1040 Callbacks.pfnTestSetSendEnd = drvHostValKitTestSetSendEndCallback;
1041 Callbacks.pvUser = pThis;
1042
1043 /** @todo Make this configurable via CFGM. */
1044 const char *pszTcpAddr = "127.0.0.1"; /* Only reachable for localhost for now. */
1045 uint32_t uTcpPort = ATS_TCP_DEF_BIND_PORT_VALKIT;
1046
1047 LogRel(("ValKit: Starting Audio Test Service (ATS) at %s:%RU32...\n",
1048 pszTcpAddr, uTcpPort));
1049
1050 rc = AudioTestSvcCreate(&pThis->Srv);
1051 if (RT_SUCCESS(rc))
1052 {
1053 RTGETOPTUNION Val;
1054 RT_ZERO(Val);
1055
1056 Val.psz = "server"; /** @ŧodo No client connection mode needed here (yet). Make this configurable via CFGM. */
1057 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_MODE, &Val);
1058 AssertRC(rc);
1059
1060 Val.psz = pszTcpAddr;
1061 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_ADDRESS, &Val);
1062 AssertRC(rc);
1063
1064 Val.u16 = uTcpPort;
1065 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_PORT, &Val);
1066 AssertRC(rc);
1067
1068 rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
1069 if (RT_SUCCESS(rc))
1070 rc = AudioTestSvcStart(&pThis->Srv);
1071 }
1072
1073 if (RT_SUCCESS(rc))
1074 {
1075 LogRel(("ValKit: Audio Test Service (ATS) running\n"));
1076
1077 /** @todo Let the following be customizable by CFGM later. */
1078 rc = AudioTestPathCreateTemp(pThis->szPathTemp, sizeof(pThis->szPathTemp), "ValKitAudio");
1079 if (RT_SUCCESS(rc))
1080 {
1081 LogRel(("ValKit: Using temp dir '%s'\n", pThis->szPathTemp));
1082 rc = AudioTestPathGetTemp(pThis->szPathOut, sizeof(pThis->szPathOut));
1083 if (RT_SUCCESS(rc))
1084 LogRel(("ValKit: Using output dir '%s'\n", pThis->szPathOut));
1085 }
1086 }
1087
1088 if (RT_FAILURE(rc))
1089 LogRel(("ValKit: Initialization failed, rc=%Rrc\n", rc));
1090
1091 return rc;
1092}
1093
1094static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
1095{
1096 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1097 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1098
1099 LogRel(("ValKit: Shutting down Audio Test Service (ATS) ...\n"));
1100
1101 int rc = AudioTestSvcShutdown(&pThis->Srv);
1102 if (RT_SUCCESS(rc))
1103 rc = AudioTestSvcDestroy(&pThis->Srv);
1104
1105 if (RT_SUCCESS(rc))
1106 {
1107 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) complete\n"));
1108 drvHostValKitCleanup(pThis);
1109 }
1110 else
1111 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) failed, rc=%Rrc\n", rc));
1112
1113 /* Try cleaning up a bit. */
1114 RTDirRemove(pThis->szPathTemp);
1115 RTDirRemove(pThis->szPathOut);
1116
1117 RTSemEventDestroy(pThis->EventSemEnded);
1118
1119 if (RTCritSectIsInitialized(&pThis->CritSect))
1120 {
1121 int rc2 = RTCritSectDelete(&pThis->CritSect);
1122 if (RT_SUCCESS(rc))
1123 rc = rc2;
1124 }
1125
1126 if (RT_FAILURE(rc))
1127 LogRel(("ValKit: Destruction failed, rc=%Rrc\n", rc));
1128}
1129
1130/**
1131 * Char driver registration record.
1132 */
1133const PDMDRVREG g_DrvHostValidationKitAudio =
1134{
1135 /* u32Version */
1136 PDM_DRVREG_VERSION,
1137 /* szName */
1138 "ValidationKitAudio",
1139 /* szRCMod */
1140 "",
1141 /* szR0Mod */
1142 "",
1143 /* pszDescription */
1144 "ValidationKitAudio audio host driver",
1145 /* fFlags */
1146 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1147 /* fClass. */
1148 PDM_DRVREG_CLASS_AUDIO,
1149 /* cMaxInstances */
1150 ~0U,
1151 /* cbInstance */
1152 sizeof(DRVHOSTVALKITAUDIO),
1153 /* pfnConstruct */
1154 drvHostValKitAudioConstruct,
1155 /* pfnDestruct */
1156 drvHostValKitAudioDestruct,
1157 /* pfnRelocate */
1158 NULL,
1159 /* pfnIOCtl */
1160 NULL,
1161 /* pfnPowerOn */
1162 NULL,
1163 /* pfnReset */
1164 NULL,
1165 /* pfnSuspend */
1166 NULL,
1167 /* pfnResume */
1168 NULL,
1169 /* pfnAttach */
1170 NULL,
1171 /* pfnDetach */
1172 NULL,
1173 /* pfnPowerOff */
1174 NULL,
1175 /* pfnSoftReset */
1176 NULL,
1177 /* u32EndVersion */
1178 PDM_DRVREG_VERSION
1179};
1180
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