VirtualBox

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

最後變更 在這個檔案從90012是 89994,由 vboxsync 提交於 4 年 前

Audio/ValKit: Cleaned up test object API + handling. bugref:10008

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

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