VirtualBox

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

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

Audio: Changed PDMIHOSTAUDIO::pfnStreamCreate to take a pointer to a const pCfgReq parameter. bugref:9890

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 27.5 KB
 
1/* $Id: DrvHostAudioValidationKit.cpp 89487 2021-06-03 20:16:17Z 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_StreamControlStub(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_StreamDisableOrPauseOrDrain(PPDMIHOSTAUDIO pInterface,
383 PPDMAUDIOBACKENDSTREAM pStream)
384{
385 RT_NOREF(pInterface);
386 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
387 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
388
389 return VINF_SUCCESS;
390}
391
392
393/**
394 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
395 */
396static DECLCALLBACK(int) drvHostValKitAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface,
397 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
398{
399 /** @todo r=bird: I'd like to get rid of this pfnStreamControl method,
400 * replacing it with individual StreamXxxx methods. That would save us
401 * potentally huge switches and more easily see which drivers implement
402 * which operations (grep for pfnStreamXxxx). */
403 switch (enmStreamCmd)
404 {
405 case PDMAUDIOSTREAMCMD_ENABLE:
406 return drvHostValKitAudioHA_StreamControlStub(pInterface, pStream);
407 case PDMAUDIOSTREAMCMD_DISABLE:
408 return drvHostValKitAudioHA_StreamControlStub(pInterface, pStream);
409 case PDMAUDIOSTREAMCMD_PAUSE:
410 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
411 case PDMAUDIOSTREAMCMD_RESUME:
412 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
413 case PDMAUDIOSTREAMCMD_DRAIN:
414 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
415
416 case PDMAUDIOSTREAMCMD_END:
417 case PDMAUDIOSTREAMCMD_32BIT_HACK:
418 case PDMAUDIOSTREAMCMD_INVALID:
419 /* no default*/
420 break;
421 }
422 return VERR_NOT_SUPPORTED;
423}
424
425
426/**
427 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
428 */
429static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
430{
431 RT_NOREF(pInterface, pStream);
432 return UINT32_MAX;
433}
434
435
436/**
437 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
438 */
439static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
440{
441 RT_NOREF(pInterface, pStream);
442 return UINT32_MAX;
443}
444
445
446/**
447 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
448 */
449static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
450 PPDMAUDIOBACKENDSTREAM pStream)
451{
452 RT_NOREF(pInterface);
453 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
454 return PDMHOSTAUDIOSTREAMSTATE_OKAY;
455}
456
457
458/**
459 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
460 */
461static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
462 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
463{
464 RT_NOREF(pStream);
465
466 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
467
468 int rc = RTCritSectEnter(&pThis->CritSect);
469 if (RT_SUCCESS(rc))
470 {
471 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
472
473 int rc2 = RTCritSectLeave(&pThis->CritSect);
474 AssertRC(rc2);
475 }
476
477 if (pThis->pTestCur == NULL) /* Empty list? */
478 {
479 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is playing back data when no playback test is active\n"));
480#ifdef DEBUG_andy
481 AssertFailed();
482#endif
483 *pcbWritten = 0;
484 return VINF_SUCCESS;
485 }
486
487 PVALKITTESTDATA pTst = pThis->pTestCur;
488
489 if (pTst->t.TestTone.u.Play.cbRead == 0)
490 {
491 AUDIOTESTPARMS Parms;
492 RT_ZERO(Parms);
493 Parms.TestTone = pTst->t.TestTone.Parms;
494
495 Assert(pTst->pEntry == NULL);
496 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
497 &Parms, &pTst->pEntry);
498 if (RT_SUCCESS(rc))
499 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "guest-output.pcm", &pTst->pObj);
500
501 if (RT_SUCCESS(rc))
502 {
503 pTst->msStartedTS = RTTimeMilliTS();
504 LogRel(("Audio: Validation Kit: Recording audio data (%RU16Hz, %RU32ms) started\n",
505 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
506 pTst->t.TestTone.Parms.msDuration));
507 }
508 }
509
510 uint32_t cbWritten = 0;
511
512 if (RT_SUCCESS(rc))
513 {
514 uint32_t cbToRead = RT_MIN(cbBuf,
515 pTst->t.TestTone.u.Play.cbToRead- pTst->t.TestTone.u.Play.cbRead);
516
517 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToRead);
518 if (RT_SUCCESS(rc))
519 {
520 pTst->t.TestTone.u.Play.cbRead += cbToRead;
521
522 Assert(pTst->t.TestTone.u.Play.cbRead <= pTst->t.TestTone.u.Play.cbToRead);
523
524 const bool fComplete = pTst->t.TestTone.u.Play.cbToRead == pTst->t.TestTone.u.Play.cbRead;
525
526 if (fComplete)
527 {
528 LogRel(("Audio: Validation Kit: Recording audio data done (took %RU32ms)\n",
529 RTTimeMilliTS() - pTst->msStartedTS));
530
531 rc = RTCritSectEnter(&pThis->CritSect);
532 if (RT_SUCCESS(rc))
533 {
534 drvHostValKiUnregisterPlayTest(pThis, pTst);
535
536 int rc2 = RTCritSectLeave(&pThis->CritSect);
537 AssertRC(rc2);
538 }
539 }
540 }
541 }
542
543 if (RT_FAILURE(rc))
544 {
545 if (pTst->pEntry)
546 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
547 LogRel(("Audio: Validation Kit: Recording audio data failed with %Rrc\n", rc));
548 }
549
550 *pcbWritten = cbWritten;
551
552 return VINF_SUCCESS; /** @todo Return rc here? */
553}
554
555
556/**
557 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
558 */
559static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
560 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
561{
562 RT_NOREF(pStream);
563
564 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
565
566 int rc = RTCritSectEnter(&pThis->CritSect);
567 if (RT_SUCCESS(rc))
568 {
569 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
570
571 int rc2 = RTCritSectLeave(&pThis->CritSect);
572 AssertRC(rc2);
573 }
574
575 if (pThis->pTestCur == NULL) /* Empty list? */
576 {
577 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is recording audio data when no recording test is active\n"));
578#ifdef DEBUG_andy
579 AssertFailed();
580#endif
581 *pcbRead = 0;
582 return VINF_SUCCESS;
583 }
584
585 PVALKITTESTDATA pTst = pThis->pTestCur;
586
587 if (pTst->t.TestTone.u.Rec.cbWritten == 0)
588 {
589 AUDIOTESTPARMS Parms;
590 RT_ZERO(Parms);
591 Parms.TestTone = pTst->t.TestTone.Parms;
592
593 Assert(pTst->pEntry == NULL);
594 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
595 &Parms, &pTst->pEntry);
596 if (RT_SUCCESS(rc))
597 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-input.pcm", &pTst->pObj);
598
599 if (RT_SUCCESS(rc))
600 {
601 pTst->msStartedTS = RTTimeMilliTS();
602 LogRel(("Audio: Validation Kit: Injecting audio input data (%RU16Hz, %RU32ms) started\n",
603 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
604 pTst->t.TestTone.Parms.msDuration));
605 }
606 }
607
608 uint32_t cbRead = 0;
609
610 if (RT_SUCCESS(rc))
611 {
612 uint32_t cbToWrite = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
613 if (cbToWrite)
614 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, RT_MIN(cbToWrite, cbBuf), &cbRead);
615 if ( RT_SUCCESS(rc)
616 && cbToWrite)
617 {
618 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToWrite);
619 if (RT_SUCCESS(rc))
620 {
621 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
622 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
623
624 const bool fComplete = pTst->t.TestTone.u.Rec.cbToWrite == pTst->t.TestTone.u.Rec.cbWritten;
625
626 if (fComplete)
627 {
628 LogRel(("Audio: Validation Kit: Injecting audio input data done (took %RU32ms)\n",
629 RTTimeMilliTS() - pTst->msStartedTS));
630
631 rc = RTCritSectEnter(&pThis->CritSect);
632 if (RT_SUCCESS(rc))
633 {
634 drvHostValKiUnregisterRecTest(pThis, pTst);
635
636 int rc2 = RTCritSectLeave(&pThis->CritSect);
637 AssertRC(rc2);
638 }
639 }
640 }
641 }
642 }
643
644 if (RT_FAILURE(rc))
645 {
646 if (pTst->pEntry)
647 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
648 LogRel(("Audio: Validation Kit: Injecting audio input data failed with %Rrc\n", rc));
649 }
650
651 *pcbRead = cbRead;
652
653 return VINF_SUCCESS; /** @todo Return rc here? */
654}
655
656
657/**
658 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
659 */
660static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
661{
662 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
663 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
664
665 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
666 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
667 return NULL;
668}
669
670
671/**
672 * Constructs a VaKit audio driver instance.
673 *
674 * @copydoc FNPDMDRVCONSTRUCT
675 */
676static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
677{
678 RT_NOREF(pCfg, fFlags);
679 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
680 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
681 LogRel(("Audio: Initializing VALKIT driver\n"));
682
683 /*
684 * Init the static parts.
685 */
686 pThis->pDrvIns = pDrvIns;
687 /* IBase */
688 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
689 /* IHostAudio */
690 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
691 pThis->IHostAudio.pfnGetDevices = NULL;
692 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
693 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
694 pThis->IHostAudio.pfnStreamConfigHint = NULL;
695 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
696 pThis->IHostAudio.pfnStreamInitAsync = NULL;
697 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
698 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
699 pThis->IHostAudio.pfnStreamControl = drvHostValKitAudioHA_StreamControl;
700 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
701 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
702 pThis->IHostAudio.pfnStreamGetPending = NULL;
703 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
704 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
705 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
706
707 RTListInit(&pThis->lstTestsRec);
708 pThis->cTestsRec = 0;
709 RTListInit(&pThis->lstTestsPlay);
710 pThis->cTestsPlay = 0;
711
712 ATSCALLBACKS Callbacks;
713 Callbacks.pfnTestSetBegin = drvHostValKitTestSetBegin;
714 Callbacks.pfnTestSetEnd = drvHostValKitTestSetEnd;
715 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
716 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
717 Callbacks.pvUser = pThis;
718
719 LogRel(("Audio: Validation Kit: Starting Audio Test Service (ATS) ...\n"));
720
721 int rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
722 if (RT_SUCCESS(rc))
723 rc = AudioTestSvcStart(&pThis->Srv);
724
725 if (RT_SUCCESS(rc))
726 {
727 LogRel(("Audio: Validation Kit: Audio Test Service (ATS) running\n"));
728
729 /** @todo Let the following be customizable by CFGM later. */
730 rc = AudioTestPathCreateTemp(pThis->szPathTemp, sizeof(pThis->szPathTemp), "ValKitAudio");
731 if (RT_SUCCESS(rc))
732 {
733 LogRel(("Audio: Validation Kit: Using temp dir '%s'\n", pThis->szPathTemp));
734 rc = AudioTestPathGetTemp(pThis->szPathOut, sizeof(pThis->szPathOut));
735 if (RT_SUCCESS(rc))
736 LogRel(("Audio: Validation Kit: Using output dir '%s'\n", pThis->szPathOut));
737 }
738 }
739
740 if (RT_SUCCESS(rc))
741 rc = RTCritSectInit(&pThis->CritSect);
742
743 if (RT_FAILURE(rc))
744 LogRel(("Audio: Validation Kit: Initialization failed, rc=%Rrc\n", rc));
745
746 return rc;
747}
748
749static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
750{
751 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
752 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
753
754 LogRel(("Audio: Validation Kit: Shutting down Audio Test Service (ATS) ...\n"));
755
756 int rc = AudioTestSvcShutdown(&pThis->Srv);
757 if (RT_SUCCESS(rc))
758 rc = AudioTestSvcDestroy(&pThis->Srv);
759
760 if (RT_SUCCESS(rc))
761 {
762 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service complete\n"));
763
764 if (pThis->cTestsRec)
765 LogRel(("Audio: Validation Kit: Warning: %RU32 guest recording tests still outstanding\n", pThis->cTestsRec));
766 if (pThis->cTestsPlay)
767 LogRel(("Audio: Validation Kit: Warning: %RU32 guest playback tests still outstanding\n", pThis->cTestsPlay));
768
769 PVALKITTESTDATA pTst, pTstNext;
770 RTListForEachSafe(&pThis->lstTestsRec, pTst, pTstNext, VALKITTESTDATA, Node)
771 drvHostValKiUnregisterRecTest(pThis, pTst);
772
773 RTListForEachSafe(&pThis->lstTestsPlay, pTst, pTstNext, VALKITTESTDATA, Node)
774 drvHostValKiUnregisterPlayTest(pThis, pTst);
775
776 Assert(pThis->cTestsRec == 0);
777 Assert(pThis->cTestsPlay == 0);
778 }
779 else
780 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service failed, rc=%Rrc\n", rc));
781
782 int rc2 = RTCritSectDelete(&pThis->CritSect);
783 if (RT_SUCCESS(rc))
784 rc = rc2;
785
786 if (RT_FAILURE(rc))
787 LogRel(("Audio: Validation Kit: Destruction failed, rc=%Rrc\n", rc));
788}
789
790/**
791 * Char driver registration record.
792 */
793const PDMDRVREG g_DrvHostValidationKitAudio =
794{
795 /* u32Version */
796 PDM_DRVREG_VERSION,
797 /* szName */
798 "ValidationKitAudio",
799 /* szRCMod */
800 "",
801 /* szR0Mod */
802 "",
803 /* pszDescription */
804 "ValidationKitAudio audio host driver",
805 /* fFlags */
806 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
807 /* fClass. */
808 PDM_DRVREG_CLASS_AUDIO,
809 /* cMaxInstances */
810 ~0U,
811 /* cbInstance */
812 sizeof(DRVHOSTVALKITAUDIO),
813 /* pfnConstruct */
814 drvHostValKitAudioConstruct,
815 /* pfnDestruct */
816 drvHostValKitAudioDestruct,
817 /* pfnRelocate */
818 NULL,
819 /* pfnIOCtl */
820 NULL,
821 /* pfnPowerOn */
822 NULL,
823 /* pfnReset */
824 NULL,
825 /* pfnSuspend */
826 NULL,
827 /* pfnResume */
828 NULL,
829 /* pfnAttach */
830 NULL,
831 /* pfnDetach */
832 NULL,
833 /* pfnPowerOff */
834 NULL,
835 /* pfnSoftReset */
836 NULL,
837 /* u32EndVersion */
838 PDM_DRVREG_VERSION
839};
840
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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