VirtualBox

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

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

Audio: Split up PDMIHOSTAUDIO::pfnStreamControl into individual methods for each command. bugref:9890

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.0 KB
 
1/* $Id: DrvHostAudioValidationKit.cpp 89510 2021-06-04 13:20: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/env.h>
24#include <iprt/mem.h>
25#include <iprt/path.h>
26#include <iprt/stream.h>
27#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
28
29#include <VBox/log.h>
30#include <VBox/vmm/pdmaudioifs.h>
31#include <VBox/vmm/pdmaudioinline.h>
32
33#include "VBoxDD.h"
34#include "AudioHlp.h"
35#include "AudioTest.h"
36#include "AudioTestService.h"
37
38
39/*********************************************************************************************************************************
40* Structures and Typedefs *
41*********************************************************************************************************************************/
42/**
43 * Structure for keeping a Validation Kit input/output stream.
44 */
45typedef struct VALKITAUDIOSTREAM
46{
47 /** Common part. */
48 PDMAUDIOBACKENDSTREAM Core;
49 /** The stream's acquired configuration. */
50 PDMAUDIOSTREAMCFG Cfg;
51} VALKITAUDIOSTREAM;
52/** Pointer to a Validation Kit stream. */
53typedef VALKITAUDIOSTREAM *PVALKITAUDIOSTREAM;
54
55/**
56 * Test tone-specific instance data.
57 */
58typedef struct VALKITTESTTONEDATA
59{
60 union
61 {
62 struct
63 {
64 /** How many bytes to write. */
65 uint64_t cbToWrite;
66 /** How many bytes already written. */
67 uint64_t cbWritten;
68 } Rec;
69 struct
70 {
71 /** How many bytes to read. */
72 uint64_t cbToRead;
73 /** How many bytes already read. */
74 uint64_t cbRead;
75 } Play;
76 } u;
77 /** The test tone instance to use. */
78 AUDIOTESTTONE Tone;
79 /** The test tone parameters to use. */
80 AUDIOTESTTONEPARMS Parms;
81} VALKITTESTTONEDATA;
82
83/**
84 * Structure keeping a single Validation Kit test.
85 */
86typedef struct VALKITTESTDATA
87{
88 /** The list node. */
89 RTLISTNODE Node;
90 /** Current test set entry to process. */
91 PAUDIOTESTENTRY pEntry;
92 /** Current test object to process. */
93 PAUDIOTESTOBJ pObj;
94 /** Stream configuration to use for this test. */
95 PDMAUDIOSTREAMCFG StreamCfg;
96 union
97 {
98 /** Test tone-specific data. */
99 VALKITTESTTONEDATA TestTone;
100 } t;
101 /** Time stamp (real, in ms) when test started. */
102 uint64_t msStartedTS;
103} VALKITTESTDATA;
104/** Pointer to Validation Kit test data. */
105typedef VALKITTESTDATA *PVALKITTESTDATA;
106
107/**
108 * Validation Kit audio driver instance data.
109 * @implements PDMIAUDIOCONNECTOR
110 */
111typedef struct DRVHOSTVALKITAUDIO
112{
113 /** Pointer to the driver instance structure. */
114 PPDMDRVINS pDrvIns;
115 /** Pointer to host audio interface. */
116 PDMIHOSTAUDIO IHostAudio;
117 /** Temporary path to use. */
118 char szPathTemp[RTPATH_MAX];
119 /** Output path to use. */
120 char szPathOut[RTPATH_MAX];
121 /** Current test set being handled. */
122 AUDIOTESTSET Set;
123 /** Number of tests in \a lstTestsRec. */
124 uint32_t cTestsRec;
125 /** List keeping the recording tests (FIFO). */
126 RTLISTANCHOR lstTestsRec;
127 /** Number of tests in \a lstTestsPlay. */
128 uint32_t cTestsPlay;
129 /** List keeping the recording tests (FIFO). */
130 RTLISTANCHOR lstTestsPlay;
131 /** Pointer to current test being processed. */
132 PVALKITTESTDATA pTestCur;
133 /** Critical section for serializing access across threads. */
134 RTCRITSECT CritSect;
135 /** The Audio Test Service (ATS) instance. */
136 ATSSERVER Srv;
137} DRVHOSTVALKITAUDIO;
138/** Pointer to a Validation Kit host audio driver instance. */
139typedef DRVHOSTVALKITAUDIO *PDRVHOSTVALKITAUDIO;
140
141
142/**
143 * Unregisters a ValKit test, common code.
144 *
145 * @param pTst Test to unregister.
146 * The pointer will be invalid afterwards.
147 */
148static void drvHostValKiUnregisterTest(PVALKITTESTDATA pTst)
149{
150 AssertPtrReturnVoid(pTst);
151
152 RTListNodeRemove(&pTst->Node);
153
154 AudioTestSetObjClose(pTst->pObj);
155 pTst->pObj = NULL;
156
157 AssertPtrReturnVoid(pTst->pEntry);
158 AudioTestSetTestDone(pTst->pEntry);
159 pTst->pEntry = NULL;
160
161 RTMemFree(pTst);
162 pTst = NULL;
163}
164
165/**
166 * Unregisters a ValKit recording test.
167 *
168 * @param pThis ValKit audio driver instance.
169 * @param pTst Test to unregister.
170 * The pointer will be invalid afterwards.
171 */
172static void drvHostValKiUnregisterRecTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
173{
174 drvHostValKiUnregisterTest(pTst);
175
176 Assert(pThis->cTestsRec);
177 pThis->cTestsRec--;
178}
179
180/**
181 * Unregisters a ValKit playback test.
182 *
183 * @param pThis ValKit audio driver instance.
184 * @param pTst Test to unregister.
185 * The pointer will be invalid afterwards.
186 */
187static void drvHostValKiUnregisterPlayTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
188{
189 drvHostValKiUnregisterTest(pTst);
190
191 Assert(pThis->cTestsPlay);
192 pThis->cTestsPlay--;
193}
194
195static DECLCALLBACK(int) drvHostValKitTestSetBegin(void const *pvUser, const char *pszTag)
196{
197 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
198
199 LogRel(("Audio: Validation Kit: Beginning test set '%s'\n", pszTag));
200
201 return AudioTestSetCreate(&pThis->Set, pThis->szPathTemp, pszTag);
202
203}
204
205static DECLCALLBACK(int) drvHostValKitTestSetEnd(void const *pvUser, const char *pszTag)
206{
207 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
208
209 const PAUDIOTESTSET pSet = &pThis->Set;
210
211 LogRel(("Audio: Validation Kit: Ending test set '%s'\n", pszTag));
212
213 /* Close the test set first. */
214 AudioTestSetClose(pSet);
215
216 /* Before destroying the test environment, pack up the test set so
217 * that it's ready for transmission. */
218 char szFileOut[RTPATH_MAX];
219 int rc = AudioTestSetPack(pSet, pThis->szPathOut, szFileOut, sizeof(szFileOut));
220 if (RT_SUCCESS(rc))
221 LogRel(("Audio: Validation Kit: Packed up to '%s'\n", szFileOut));
222
223 int rc2 = AudioTestSetWipe(pSet);
224 if (RT_SUCCESS(rc))
225 rc = rc2;
226
227 AudioTestSetDestroy(pSet);
228
229 if (RT_FAILURE(rc))
230 LogRel(("Audio: Validation Kit: Test set prologue failed with %Rrc\n", rc));
231
232 return rc;
233}
234
235/** @copydoc ATSCALLBACKS::pfnTonePlay
236 *
237 * Creates and registers a new test tone recording test
238 * which later then gets recorded by the guest side.
239 */
240static DECLCALLBACK(int) drvHostValKitRegisterGuestRecTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
241{
242 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
243
244 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
245 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
246
247 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
248
249 AudioTestToneInit(&pTestData->t.TestTone.Tone, &pToneParms->Props, pTestData->t.TestTone.Parms.dbFreqHz);
250
251 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pToneParms->Props,
252 pTestData->t.TestTone.Parms.msDuration);
253 int rc = RTCritSectEnter(&pThis->CritSect);
254 if (RT_SUCCESS(rc))
255 {
256 LogRel(("Audio: Validation Kit: Registered guest recording test (%RU32ms, %RU64 bytes)\n",
257 pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
258
259 RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
260
261 pThis->cTestsRec++;
262
263 int rc2 = RTCritSectLeave(&pThis->CritSect);
264 AssertRC(rc2);
265 }
266
267 return VINF_SUCCESS;
268}
269
270/** @copydoc ATSCALLBACKS::pfnToneRecord
271 *
272 * Creates and registers a new test tone playback test
273 * which later then records audio played back by the guest side.
274 */
275static DECLCALLBACK(int) drvHostValKitRegisterGuestPlayTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
276{
277 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
278
279 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
280 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
281
282 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
283
284 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pToneParms->Props,
285 pTestData->t.TestTone.Parms.msDuration);
286 int rc = RTCritSectEnter(&pThis->CritSect);
287 if (RT_SUCCESS(rc))
288 {
289 LogRel(("Audio: Validation Kit: Registered guest playback test (%RU32ms, %RU64 bytes)\n",
290 pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
291
292 RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
293
294 pThis->cTestsPlay++;
295
296 int rc2 = RTCritSectLeave(&pThis->CritSect);
297 AssertRC(rc2);
298 }
299
300 return VINF_SUCCESS;
301}
302
303/**
304 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
305 */
306static DECLCALLBACK(int) drvHostValKitAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
307{
308 RT_NOREF(pInterface);
309 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
310
311 /*
312 * Fill in the config structure.
313 */
314 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Validation Kit");
315 pBackendCfg->cbStream = sizeof(VALKITAUDIOSTREAM);
316 pBackendCfg->fFlags = 0;
317 pBackendCfg->cMaxStreamsOut = 1; /* Output (Playback). */
318 pBackendCfg->cMaxStreamsIn = 1; /* Input (Recording). */
319
320 return VINF_SUCCESS;
321}
322
323
324/**
325 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
326 */
327static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostValKitAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
328{
329 RT_NOREF(enmDir);
330 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
331
332 return PDMAUDIOBACKENDSTS_RUNNING;
333}
334
335
336/**
337 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
338 */
339static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
340 PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
341{
342 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
343 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
344 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
345 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
346 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
347 RT_NOREF(pThis);
348
349 int rc = VINF_SUCCESS;
350 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
351 return rc;
352}
353
354
355/**
356 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
357 */
358static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
359 bool fImmediate)
360{
361 RT_NOREF(pInterface, fImmediate);
362 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
363 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
364
365 return VINF_SUCCESS;
366}
367
368
369/**
370 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
371 */
372static DECLCALLBACK(int) drvHostValKitAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
373{
374 RT_NOREF(pInterface, pStream);
375 return VINF_SUCCESS;
376}
377
378
379/**
380 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
381 */
382static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
383{
384 RT_NOREF(pInterface, pStream);
385 return VINF_SUCCESS;
386}
387
388
389/**
390 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
391 */
392static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
393{
394 RT_NOREF(pInterface, pStream);
395 return VINF_SUCCESS;
396}
397
398
399/**
400 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
401 */
402static DECLCALLBACK(int) drvHostValKitAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
403{
404 RT_NOREF(pInterface, pStream);
405 return VINF_SUCCESS;
406}
407
408
409/**
410 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
411 */
412static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
413{
414 RT_NOREF(pInterface, pStream);
415 return VINF_SUCCESS;
416}
417
418
419/**
420 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
421 */
422static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
423{
424 RT_NOREF(pInterface, pStream);
425 return UINT32_MAX;
426}
427
428
429/**
430 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
431 */
432static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
433{
434 RT_NOREF(pInterface, pStream);
435 return UINT32_MAX;
436}
437
438
439/**
440 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
441 */
442static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
443 PPDMAUDIOBACKENDSTREAM pStream)
444{
445 RT_NOREF(pInterface);
446 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
447 return PDMHOSTAUDIOSTREAMSTATE_OKAY;
448}
449
450
451/**
452 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
453 */
454static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
455 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
456{
457 RT_NOREF(pStream);
458
459 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
460
461 int rc = RTCritSectEnter(&pThis->CritSect);
462 if (RT_SUCCESS(rc))
463 {
464 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
465
466 int rc2 = RTCritSectLeave(&pThis->CritSect);
467 AssertRC(rc2);
468 }
469
470 if (pThis->pTestCur == NULL) /* Empty list? */
471 {
472 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is playing back data when no playback test is active\n"));
473#ifdef DEBUG_andy
474 AssertFailed();
475#endif
476 *pcbWritten = 0;
477 return VINF_SUCCESS;
478 }
479
480 PVALKITTESTDATA pTst = pThis->pTestCur;
481
482 if (pTst->t.TestTone.u.Play.cbRead == 0)
483 {
484 AUDIOTESTPARMS Parms;
485 RT_ZERO(Parms);
486 Parms.TestTone = pTst->t.TestTone.Parms;
487
488 Assert(pTst->pEntry == NULL);
489 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
490 &Parms, &pTst->pEntry);
491 if (RT_SUCCESS(rc))
492 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "guest-output.pcm", &pTst->pObj);
493
494 if (RT_SUCCESS(rc))
495 {
496 pTst->msStartedTS = RTTimeMilliTS();
497 LogRel(("Audio: Validation Kit: Recording audio data (%RU16Hz, %RU32ms) started\n",
498 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
499 pTst->t.TestTone.Parms.msDuration));
500 }
501 }
502
503 uint32_t cbWritten = 0;
504
505 if (RT_SUCCESS(rc))
506 {
507 uint32_t cbToRead = RT_MIN(cbBuf,
508 pTst->t.TestTone.u.Play.cbToRead- pTst->t.TestTone.u.Play.cbRead);
509
510 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToRead);
511 if (RT_SUCCESS(rc))
512 {
513 pTst->t.TestTone.u.Play.cbRead += cbToRead;
514
515 Assert(pTst->t.TestTone.u.Play.cbRead <= pTst->t.TestTone.u.Play.cbToRead);
516
517 const bool fComplete = pTst->t.TestTone.u.Play.cbToRead == pTst->t.TestTone.u.Play.cbRead;
518
519 if (fComplete)
520 {
521 LogRel(("Audio: Validation Kit: Recording audio data done (took %RU32ms)\n",
522 RTTimeMilliTS() - pTst->msStartedTS));
523
524 rc = RTCritSectEnter(&pThis->CritSect);
525 if (RT_SUCCESS(rc))
526 {
527 drvHostValKiUnregisterPlayTest(pThis, pTst);
528
529 int rc2 = RTCritSectLeave(&pThis->CritSect);
530 AssertRC(rc2);
531 }
532 }
533 }
534 }
535
536 if (RT_FAILURE(rc))
537 {
538 if (pTst->pEntry)
539 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
540 LogRel(("Audio: Validation Kit: Recording audio data failed with %Rrc\n", rc));
541 }
542
543 *pcbWritten = cbWritten;
544
545 return VINF_SUCCESS; /** @todo Return rc here? */
546}
547
548
549/**
550 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
551 */
552static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
553 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
554{
555 RT_NOREF(pStream);
556
557 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
558
559 int rc = RTCritSectEnter(&pThis->CritSect);
560 if (RT_SUCCESS(rc))
561 {
562 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
563
564 int rc2 = RTCritSectLeave(&pThis->CritSect);
565 AssertRC(rc2);
566 }
567
568 if (pThis->pTestCur == NULL) /* Empty list? */
569 {
570 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is recording audio data when no recording test is active\n"));
571#ifdef DEBUG_andy
572 AssertFailed();
573#endif
574 *pcbRead = 0;
575 return VINF_SUCCESS;
576 }
577
578 PVALKITTESTDATA pTst = pThis->pTestCur;
579
580 if (pTst->t.TestTone.u.Rec.cbWritten == 0)
581 {
582 AUDIOTESTPARMS Parms;
583 RT_ZERO(Parms);
584 Parms.TestTone = pTst->t.TestTone.Parms;
585
586 Assert(pTst->pEntry == NULL);
587 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
588 &Parms, &pTst->pEntry);
589 if (RT_SUCCESS(rc))
590 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-input.pcm", &pTst->pObj);
591
592 if (RT_SUCCESS(rc))
593 {
594 pTst->msStartedTS = RTTimeMilliTS();
595 LogRel(("Audio: Validation Kit: Injecting audio input data (%RU16Hz, %RU32ms) started\n",
596 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
597 pTst->t.TestTone.Parms.msDuration));
598 }
599 }
600
601 uint32_t cbRead = 0;
602
603 if (RT_SUCCESS(rc))
604 {
605 uint32_t cbToWrite = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
606 if (cbToWrite)
607 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, RT_MIN(cbToWrite, cbBuf), &cbRead);
608 if ( RT_SUCCESS(rc)
609 && cbToWrite)
610 {
611 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToWrite);
612 if (RT_SUCCESS(rc))
613 {
614 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
615 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
616
617 const bool fComplete = pTst->t.TestTone.u.Rec.cbToWrite == pTst->t.TestTone.u.Rec.cbWritten;
618
619 if (fComplete)
620 {
621 LogRel(("Audio: Validation Kit: Injecting audio input data done (took %RU32ms)\n",
622 RTTimeMilliTS() - pTst->msStartedTS));
623
624 rc = RTCritSectEnter(&pThis->CritSect);
625 if (RT_SUCCESS(rc))
626 {
627 drvHostValKiUnregisterRecTest(pThis, pTst);
628
629 int rc2 = RTCritSectLeave(&pThis->CritSect);
630 AssertRC(rc2);
631 }
632 }
633 }
634 }
635 }
636
637 if (RT_FAILURE(rc))
638 {
639 if (pTst->pEntry)
640 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
641 LogRel(("Audio: Validation Kit: Injecting audio input data failed with %Rrc\n", rc));
642 }
643
644 *pcbRead = cbRead;
645
646 return VINF_SUCCESS; /** @todo Return rc here? */
647}
648
649
650/**
651 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
652 */
653static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
654{
655 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
656 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
657
658 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
659 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
660 return NULL;
661}
662
663
664/**
665 * Constructs a VaKit audio driver instance.
666 *
667 * @copydoc FNPDMDRVCONSTRUCT
668 */
669static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
670{
671 RT_NOREF(pCfg, fFlags);
672 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
673 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
674 LogRel(("Audio: Initializing VALKIT driver\n"));
675
676 /*
677 * Init the static parts.
678 */
679 pThis->pDrvIns = pDrvIns;
680 /* IBase */
681 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
682 /* IHostAudio */
683 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
684 pThis->IHostAudio.pfnGetDevices = NULL;
685 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
686 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
687 pThis->IHostAudio.pfnStreamConfigHint = NULL;
688 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
689 pThis->IHostAudio.pfnStreamInitAsync = NULL;
690 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
691 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
692 pThis->IHostAudio.pfnStreamEnable = drvHostValKitAudioHA_StreamEnable;
693 pThis->IHostAudio.pfnStreamDisable = drvHostValKitAudioHA_StreamDisable;
694 pThis->IHostAudio.pfnStreamPause = drvHostValKitAudioHA_StreamPause;
695 pThis->IHostAudio.pfnStreamResume = drvHostValKitAudioHA_StreamResume;
696 pThis->IHostAudio.pfnStreamDrain = drvHostValKitAudioHA_StreamDrain;
697 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
698 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
699 pThis->IHostAudio.pfnStreamGetPending = NULL;
700 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
701 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
702 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
703
704 RTListInit(&pThis->lstTestsRec);
705 pThis->cTestsRec = 0;
706 RTListInit(&pThis->lstTestsPlay);
707 pThis->cTestsPlay = 0;
708
709 ATSCALLBACKS Callbacks;
710 Callbacks.pfnTestSetBegin = drvHostValKitTestSetBegin;
711 Callbacks.pfnTestSetEnd = drvHostValKitTestSetEnd;
712 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
713 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
714 Callbacks.pvUser = pThis;
715
716 LogRel(("Audio: Validation Kit: Starting Audio Test Service (ATS) ...\n"));
717
718 int rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
719 if (RT_SUCCESS(rc))
720 rc = AudioTestSvcStart(&pThis->Srv);
721
722 if (RT_SUCCESS(rc))
723 {
724 LogRel(("Audio: Validation Kit: Audio Test Service (ATS) running\n"));
725
726 /** @todo Let the following be customizable by CFGM later. */
727 rc = AudioTestPathCreateTemp(pThis->szPathTemp, sizeof(pThis->szPathTemp), "ValKitAudio");
728 if (RT_SUCCESS(rc))
729 {
730 LogRel(("Audio: Validation Kit: Using temp dir '%s'\n", pThis->szPathTemp));
731 rc = AudioTestPathGetTemp(pThis->szPathOut, sizeof(pThis->szPathOut));
732 if (RT_SUCCESS(rc))
733 LogRel(("Audio: Validation Kit: Using output dir '%s'\n", pThis->szPathOut));
734 }
735 }
736
737 if (RT_SUCCESS(rc))
738 rc = RTCritSectInit(&pThis->CritSect);
739
740 if (RT_FAILURE(rc))
741 LogRel(("Audio: Validation Kit: Initialization failed, rc=%Rrc\n", rc));
742
743 return rc;
744}
745
746static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
747{
748 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
749 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
750
751 LogRel(("Audio: Validation Kit: Shutting down Audio Test Service (ATS) ...\n"));
752
753 int rc = AudioTestSvcShutdown(&pThis->Srv);
754 if (RT_SUCCESS(rc))
755 rc = AudioTestSvcDestroy(&pThis->Srv);
756
757 if (RT_SUCCESS(rc))
758 {
759 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service complete\n"));
760
761 if (pThis->cTestsRec)
762 LogRel(("Audio: Validation Kit: Warning: %RU32 guest recording tests still outstanding\n", pThis->cTestsRec));
763 if (pThis->cTestsPlay)
764 LogRel(("Audio: Validation Kit: Warning: %RU32 guest playback tests still outstanding\n", pThis->cTestsPlay));
765
766 PVALKITTESTDATA pTst, pTstNext;
767 RTListForEachSafe(&pThis->lstTestsRec, pTst, pTstNext, VALKITTESTDATA, Node)
768 drvHostValKiUnregisterRecTest(pThis, pTst);
769
770 RTListForEachSafe(&pThis->lstTestsPlay, pTst, pTstNext, VALKITTESTDATA, Node)
771 drvHostValKiUnregisterPlayTest(pThis, pTst);
772
773 Assert(pThis->cTestsRec == 0);
774 Assert(pThis->cTestsPlay == 0);
775 }
776 else
777 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service failed, rc=%Rrc\n", rc));
778
779 int rc2 = RTCritSectDelete(&pThis->CritSect);
780 if (RT_SUCCESS(rc))
781 rc = rc2;
782
783 if (RT_FAILURE(rc))
784 LogRel(("Audio: Validation Kit: Destruction failed, rc=%Rrc\n", rc));
785}
786
787/**
788 * Char driver registration record.
789 */
790const PDMDRVREG g_DrvHostValidationKitAudio =
791{
792 /* u32Version */
793 PDM_DRVREG_VERSION,
794 /* szName */
795 "ValidationKitAudio",
796 /* szRCMod */
797 "",
798 /* szR0Mod */
799 "",
800 /* pszDescription */
801 "ValidationKitAudio audio host driver",
802 /* fFlags */
803 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
804 /* fClass. */
805 PDM_DRVREG_CLASS_AUDIO,
806 /* cMaxInstances */
807 ~0U,
808 /* cbInstance */
809 sizeof(DRVHOSTVALKITAUDIO),
810 /* pfnConstruct */
811 drvHostValKitAudioConstruct,
812 /* pfnDestruct */
813 drvHostValKitAudioDestruct,
814 /* pfnRelocate */
815 NULL,
816 /* pfnIOCtl */
817 NULL,
818 /* pfnPowerOn */
819 NULL,
820 /* pfnReset */
821 NULL,
822 /* pfnSuspend */
823 NULL,
824 /* pfnResume */
825 NULL,
826 /* pfnAttach */
827 NULL,
828 /* pfnDetach */
829 NULL,
830 /* pfnPowerOff */
831 NULL,
832 /* pfnSoftReset */
833 NULL,
834 /* u32EndVersion */
835 PDM_DRVREG_VERSION
836};
837
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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