VirtualBox

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

Last change on this file since 89467 was 89463, checked in by vboxsync, 4 years ago

Audio/ValKit: More code for the Validation Kit audio driver. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.5 KB
Line 
1/* $Id: DrvHostAudioValidationKit.cpp 89463 2021-06-02 11:03: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/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 /** Current test set being handled. */
118 AUDIOTESTSET Set;
119 /** Number of tests in \a lstTestsRec. */
120 uint32_t cTestsRec;
121 /** List keeping the recording tests (FIFO). */
122 RTLISTANCHOR lstTestsRec;
123 /** Number of tests in \a lstTestsPlay. */
124 uint32_t cTestsPlay;
125 /** List keeping the recording tests (FIFO). */
126 RTLISTANCHOR lstTestsPlay;
127 /** Pointer to current test being processed. */
128 PVALKITTESTDATA pTestCur;
129 /** Critical section for serializing access across threads. */
130 RTCRITSECT CritSect;
131 /** The Audio Test Service (ATS) instance. */
132 ATSSERVER Srv;
133} DRVHOSTVALKITAUDIO;
134/** Pointer to a Validation Kit host audio driver instance. */
135typedef DRVHOSTVALKITAUDIO *PDRVHOSTVALKITAUDIO;
136
137
138
139static void drvHostValKiUnregisterTest(PVALKITTESTDATA pTst)
140{
141 RTListNodeRemove(&pTst->Node);
142
143 AudioTestSetObjClose(pTst->pObj);
144 pTst->pObj = NULL;
145 AudioTestSetTestDone(pTst->pEntry);
146 pTst->pEntry = NULL;
147
148 RTMemFree(pTst);
149 pTst = NULL;
150}
151
152static void drvHostValKiUnregisterRecTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
153{
154 drvHostValKiUnregisterTest(pTst);
155
156 Assert(pThis->cTestsRec);
157 pThis->cTestsRec--;
158}
159
160static void drvHostValKiUnregisterPlayTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
161{
162 drvHostValKiUnregisterTest(pTst);
163
164 Assert(pThis->cTestsPlay);
165 pThis->cTestsPlay--;
166}
167
168/** @copydoc ATSCALLBACKS::pfnTonePlay
169 *
170 * Creates and registers a new test tone recording test
171 * which later then gets recorded by the guest side.
172 */
173static DECLCALLBACK(int) drvHostValKitRegisterGuestRecTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
174{
175 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
176
177 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
178 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
179
180 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
181
182 AudioTestToneInit(&pTestData->t.TestTone.Tone, &pToneParms->Props, pTestData->t.TestTone.Parms.dbFreqHz);
183
184 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pToneParms->Props,
185 pTestData->t.TestTone.Parms.msDuration);
186 int rc = RTCritSectEnter(&pThis->CritSect);
187 if (RT_SUCCESS(rc))
188 {
189 LogRel(("Audio: Validation Kit: Registered guest recording test (%RU32ms, %RU64 bytes)\n",
190 pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
191
192 RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
193
194 pThis->cTestsRec++;
195
196 int rc2 = RTCritSectLeave(&pThis->CritSect);
197 AssertRC(rc2);
198 }
199
200 return VINF_SUCCESS;
201}
202
203/** @copydoc ATSCALLBACKS::pfnToneRecord
204 *
205 * Creates and registers a new test tone playback test
206 * which later then records audio played back by the guest side.
207 */
208static DECLCALLBACK(int) drvHostValKitRegisterGuestPlayTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
209{
210 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
211
212 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
213 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
214
215 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
216
217 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pToneParms->Props,
218 pTestData->t.TestTone.Parms.msDuration);
219 int rc = RTCritSectEnter(&pThis->CritSect);
220 if (RT_SUCCESS(rc))
221 {
222 LogRel(("Audio: Validation Kit: Registered guest playback test (%RU32ms, %RU64 bytes)\n",
223 pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
224
225 RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
226
227 pThis->cTestsPlay++;
228
229 int rc2 = RTCritSectLeave(&pThis->CritSect);
230 AssertRC(rc2);
231 }
232
233 return VINF_SUCCESS;
234}
235
236/**
237 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
238 */
239static DECLCALLBACK(int) drvHostValKitAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
240{
241 RT_NOREF(pInterface);
242 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
243
244 /*
245 * Fill in the config structure.
246 */
247 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Validation Kit");
248 pBackendCfg->cbStream = sizeof(VALKITAUDIOSTREAM);
249 pBackendCfg->fFlags = 0;
250 pBackendCfg->cMaxStreamsOut = 1; /* Output (Playback). */
251 pBackendCfg->cMaxStreamsIn = 1; /* Input (Recording). */
252
253 return VINF_SUCCESS;
254}
255
256
257/**
258 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
259 */
260static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostValKitAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
261{
262 RT_NOREF(enmDir);
263 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
264
265 return PDMAUDIOBACKENDSTS_RUNNING;
266}
267
268
269static int drvHostValKitAudioCreateStreamIn(PDRVHOSTVALKITAUDIO pThis, PVALKITAUDIOSTREAM pStreamDbg,
270 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
271{
272 RT_NOREF(pThis, pStreamDbg, pCfgReq, pCfgAcq);
273
274 return VINF_SUCCESS;
275}
276
277
278static int drvHostValKitAudioCreateStreamOut(PDRVHOSTVALKITAUDIO pThis, PVALKITAUDIOSTREAM pStreamDbg,
279 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
280{
281 RT_NOREF(pThis, pStreamDbg, pCfgReq, pCfgAcq);
282
283 return VINF_SUCCESS;
284}
285
286
287/**
288 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
289 */
290static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
291 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
292{
293 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
294 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
295 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
296 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
297 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
298
299 int rc;
300 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
301 rc = drvHostValKitAudioCreateStreamIn( pThis, pStreamDbg, pCfgReq, pCfgAcq);
302 else
303 rc = drvHostValKitAudioCreateStreamOut(pThis, pStreamDbg, pCfgReq, pCfgAcq);
304 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
305 return rc;
306}
307
308
309/**
310 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
311 */
312static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
313 bool fImmediate)
314{
315 RT_NOREF(pInterface, fImmediate);
316 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
317 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
318
319 return VINF_SUCCESS;
320}
321
322
323/**
324 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
325 */
326static DECLCALLBACK(int) drvHostValKitAudioHA_StreamControlStub(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
327{
328 RT_NOREF(pInterface, pStream);
329 return VINF_SUCCESS;
330}
331
332
333/**
334 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
335 */
336static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(PPDMIHOSTAUDIO pInterface,
337 PPDMAUDIOBACKENDSTREAM pStream)
338{
339 RT_NOREF(pInterface);
340 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
341 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
342
343 return VINF_SUCCESS;
344}
345
346
347/**
348 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
349 */
350static DECLCALLBACK(int) drvHostValKitAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface,
351 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
352{
353 /** @todo r=bird: I'd like to get rid of this pfnStreamControl method,
354 * replacing it with individual StreamXxxx methods. That would save us
355 * potentally huge switches and more easily see which drivers implement
356 * which operations (grep for pfnStreamXxxx). */
357 switch (enmStreamCmd)
358 {
359 case PDMAUDIOSTREAMCMD_ENABLE:
360 return drvHostValKitAudioHA_StreamControlStub(pInterface, pStream);
361 case PDMAUDIOSTREAMCMD_DISABLE:
362 return drvHostValKitAudioHA_StreamControlStub(pInterface, pStream);
363 case PDMAUDIOSTREAMCMD_PAUSE:
364 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
365 case PDMAUDIOSTREAMCMD_RESUME:
366 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
367 case PDMAUDIOSTREAMCMD_DRAIN:
368 return drvHostValKitAudioHA_StreamDisableOrPauseOrDrain(pInterface, pStream);
369
370 case PDMAUDIOSTREAMCMD_END:
371 case PDMAUDIOSTREAMCMD_32BIT_HACK:
372 case PDMAUDIOSTREAMCMD_INVALID:
373 /* no default*/
374 break;
375 }
376 return VERR_NOT_SUPPORTED;
377}
378
379
380/**
381 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
382 */
383static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
384{
385 RT_NOREF(pInterface, pStream);
386 return UINT32_MAX;
387}
388
389
390/**
391 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
392 */
393static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
394{
395 RT_NOREF(pInterface, pStream);
396 return UINT32_MAX;
397}
398
399
400/**
401 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
402 */
403static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
404 PPDMAUDIOBACKENDSTREAM pStream)
405{
406 RT_NOREF(pInterface);
407 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
408 return PDMHOSTAUDIOSTREAMSTATE_OKAY;
409}
410
411
412/**
413 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
414 */
415static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
416 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
417{
418 RT_NOREF(pStream);
419
420 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
421
422 int rc = RTCritSectEnter(&pThis->CritSect);
423 if (RT_SUCCESS(rc))
424 {
425 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
426
427 int rc2 = RTCritSectLeave(&pThis->CritSect);
428 AssertRC(rc2);
429 }
430
431 if (pThis->pTestCur == NULL) /* Empty list? */
432 {
433 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is playing back data when no playback test is active\n"));
434#ifdef DEBUG_andy
435 AssertFailed();
436#endif
437 *pcbWritten = 0;
438 return VINF_SUCCESS;
439 }
440
441 PVALKITTESTDATA pTst = pThis->pTestCur;
442
443 if (pTst->t.TestTone.u.Play.cbRead == 0)
444 {
445 AUDIOTESTPARMS Parms;
446 RT_ZERO(Parms);
447 Parms.TestTone = pTst->t.TestTone.Parms;
448
449 Assert(pTst->pEntry == NULL);
450 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
451 &Parms, &pTst->pEntry);
452 if (RT_SUCCESS(rc))
453 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "guest-output.pcm", &pTst->pObj);
454
455 if (RT_SUCCESS(rc))
456 {
457 pTst->msStartedTS = RTTimeMilliTS();
458 LogRel(("Audio: Validation Kit: Recording audio data (%RU16Hz, %RU32ms) started\n",
459 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
460 pTst->t.TestTone.Parms.msDuration));
461 }
462 }
463
464 uint32_t cbWritten = 0;
465
466 if (RT_SUCCESS(rc))
467 {
468 uint32_t cbToRead = RT_MIN(cbBuf,
469 pTst->t.TestTone.u.Play.cbToRead- pTst->t.TestTone.u.Play.cbRead);
470
471 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToRead);
472 if (RT_SUCCESS(rc))
473 {
474 pTst->t.TestTone.u.Play.cbRead += cbToRead;
475
476 Assert(pTst->t.TestTone.u.Play.cbRead <= pTst->t.TestTone.u.Play.cbToRead);
477
478 const bool fComplete = pTst->t.TestTone.u.Play.cbToRead == pTst->t.TestTone.u.Play.cbRead;
479
480 if (fComplete)
481 {
482 LogRel(("Audio: Validation Kit: Recording audio data done (took %RU32ms)\n",
483 RTTimeMilliTS() - pTst->msStartedTS));
484
485 rc = RTCritSectEnter(&pThis->CritSect);
486 if (RT_SUCCESS(rc))
487 {
488 drvHostValKiUnregisterPlayTest(pThis, pTst);
489
490 int rc2 = RTCritSectLeave(&pThis->CritSect);
491 AssertRC(rc2);
492 }
493 }
494 }
495 }
496
497 if (RT_FAILURE(rc))
498 {
499 if (pTst->pEntry)
500 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
501 LogRel(("Audio: Validation Kit: Recording audio data failed with %Rrc\n", rc));
502 }
503
504 *pcbWritten = cbWritten;
505
506 return VINF_SUCCESS; /** @todo Return rc here? */
507}
508
509
510/**
511 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
512 */
513static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
514 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
515{
516 RT_NOREF(pStream);
517
518 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
519
520 int rc = RTCritSectEnter(&pThis->CritSect);
521 if (RT_SUCCESS(rc))
522 {
523 pThis->pTestCur = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
524
525 int rc2 = RTCritSectLeave(&pThis->CritSect);
526 AssertRC(rc2);
527 }
528
529 if (pThis->pTestCur == NULL) /* Empty list? */
530 {
531 LogRelMax(64, ("Audio: Validation Kit: Warning: Guest is recording audio data when no recording test is active\n"));
532#ifdef DEBUG_andy
533 AssertFailed();
534#endif
535 *pcbRead = 0;
536 return VINF_SUCCESS;
537 }
538
539 PVALKITTESTDATA pTst = pThis->pTestCur;
540
541 if (pTst->t.TestTone.u.Rec.cbWritten == 0)
542 {
543 AUDIOTESTPARMS Parms;
544 RT_ZERO(Parms);
545 Parms.TestTone = pTst->t.TestTone.Parms;
546
547 Assert(pTst->pEntry == NULL);
548 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
549 &Parms, &pTst->pEntry);
550 if (RT_SUCCESS(rc))
551 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-input.pcm", &pTst->pObj);
552
553 if (RT_SUCCESS(rc))
554 {
555 pTst->msStartedTS = RTTimeMilliTS();
556 LogRel(("Audio: Validation Kit: Injecting audio input data (%RU16Hz, %RU32ms) started\n",
557 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
558 pTst->t.TestTone.Parms.msDuration));
559 }
560 }
561
562 uint32_t cbRead = 0;
563
564 if (RT_SUCCESS(rc))
565 {
566 uint32_t cbToWrite = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
567 if (cbToWrite)
568 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, RT_MIN(cbToWrite, cbBuf), &cbRead);
569 if ( RT_SUCCESS(rc)
570 && cbToWrite)
571 {
572 rc = AudioTestSetObjWrite(pTst->pObj, pvBuf, cbToWrite);
573 if (RT_SUCCESS(rc))
574 {
575 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
576 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
577
578 const bool fComplete = pTst->t.TestTone.u.Rec.cbToWrite == pTst->t.TestTone.u.Rec.cbWritten;
579
580 if (fComplete)
581 {
582 LogRel(("Audio: Validation Kit: Injecting audio input data done (took %RU32ms)\n",
583 RTTimeMilliTS() - pTst->msStartedTS));
584
585 rc = RTCritSectEnter(&pThis->CritSect);
586 if (RT_SUCCESS(rc))
587 {
588 drvHostValKiUnregisterRecTest(pThis, pTst);
589
590 int rc2 = RTCritSectLeave(&pThis->CritSect);
591 AssertRC(rc2);
592 }
593 }
594 }
595 }
596 }
597
598 if (RT_FAILURE(rc))
599 {
600 if (pTst->pEntry)
601 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
602 LogRel(("Audio: Validation Kit: Injecting audio input data failed with %Rrc\n", rc));
603 }
604
605 *pcbRead = cbRead;
606
607 return VINF_SUCCESS; /** @todo Return rc here? */
608}
609
610
611/**
612 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
613 */
614static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
615{
616 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
617 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
618
619 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
620 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
621 return NULL;
622}
623
624
625/**
626 * Constructs a VaKit audio driver instance.
627 *
628 * @copydoc FNPDMDRVCONSTRUCT
629 */
630static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
631{
632 RT_NOREF(pCfg, fFlags);
633 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
634 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
635 LogRel(("Audio: Initializing VALKIT driver\n"));
636
637 /*
638 * Init the static parts.
639 */
640 pThis->pDrvIns = pDrvIns;
641 /* IBase */
642 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
643 /* IHostAudio */
644 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
645 pThis->IHostAudio.pfnGetDevices = NULL;
646 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
647 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
648 pThis->IHostAudio.pfnStreamConfigHint = NULL;
649 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
650 pThis->IHostAudio.pfnStreamInitAsync = NULL;
651 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
652 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
653 pThis->IHostAudio.pfnStreamControl = drvHostValKitAudioHA_StreamControl;
654 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
655 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
656 pThis->IHostAudio.pfnStreamGetPending = NULL;
657 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
658 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
659 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
660
661 RTListInit(&pThis->lstTestsRec);
662 pThis->cTestsRec = 0;
663 RTListInit(&pThis->lstTestsPlay);
664 pThis->cTestsPlay = 0;
665
666 ATSCALLBACKS Callbacks;
667 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
668 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
669 Callbacks.pvUser = pThis;
670
671 LogRel(("Audio: Validation Kit: Starting Audio Test Service (ATS) ...\n"));
672
673 int rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
674 if (RT_SUCCESS(rc))
675 rc = AudioTestSvcStart(&pThis->Srv);
676
677 if (RT_FAILURE(rc))
678 {
679 LogRel(("Audio: Validation Kit: Starting Audio Test Service (ATS) failed, rc=%Rrc\n", rc));
680 }
681 else
682 LogRel(("Audio: Validation Kit: Audio Test Service (ATS) running\n"));
683
684 if (RT_SUCCESS(rc))
685 rc = RTCritSectInit(&pThis->CritSect);
686
687 return rc;
688}
689
690static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
691{
692 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
693 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
694
695 LogRel(("Audio: Validation Kit: Shutting down Audio Test Service (ATS) ...\n"));
696
697 int rc = AudioTestSvcShutdown(&pThis->Srv);
698 if (RT_SUCCESS(rc))
699 rc = AudioTestSvcDestroy(&pThis->Srv);
700
701 if (RT_SUCCESS(rc))
702 {
703 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service complete\n"));
704
705 if (pThis->cTestsRec)
706 LogRel(("Audio: Validation Kit: Warning: %RU32 guest recording tests still outstanding\n", pThis->cTestsRec));
707 if (pThis->cTestsPlay)
708 LogRel(("Audio: Validation Kit: Warning: %RU32 guest playback tests still outstanding\n", pThis->cTestsPlay));
709
710 PVALKITTESTDATA pTst, pTstNext;
711 RTListForEachSafe(&pThis->lstTestsRec, pTst, pTstNext, VALKITTESTDATA, Node)
712 drvHostValKiUnregisterRecTest(pThis, pTst);
713
714 RTListForEachSafe(&pThis->lstTestsPlay, pTst, pTstNext, VALKITTESTDATA, Node)
715 drvHostValKiUnregisterPlayTest(pThis, pTst);
716
717 Assert(pThis->cTestsRec == 0);
718 Assert(pThis->cTestsPlay == 0);
719 }
720 else
721 LogRel(("Audio: Validation Kit: Shutdown of Audio Test Service failed, rc=%Rrc\n", rc));
722
723 rc = RTCritSectDelete(&pThis->CritSect);
724 AssertRC(rc);
725}
726
727/**
728 * Char driver registration record.
729 */
730const PDMDRVREG g_DrvHostValidationKitAudio =
731{
732 /* u32Version */
733 PDM_DRVREG_VERSION,
734 /* szName */
735 "ValidationKitAudio",
736 /* szRCMod */
737 "",
738 /* szR0Mod */
739 "",
740 /* pszDescription */
741 "ValidationKitAudio audio host driver",
742 /* fFlags */
743 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
744 /* fClass. */
745 PDM_DRVREG_CLASS_AUDIO,
746 /* cMaxInstances */
747 ~0U,
748 /* cbInstance */
749 sizeof(DRVHOSTVALKITAUDIO),
750 /* pfnConstruct */
751 drvHostValKitAudioConstruct,
752 /* pfnDestruct */
753 drvHostValKitAudioDestruct,
754 /* pfnRelocate */
755 NULL,
756 /* pfnIOCtl */
757 NULL,
758 /* pfnPowerOn */
759 NULL,
760 /* pfnReset */
761 NULL,
762 /* pfnSuspend */
763 NULL,
764 /* pfnResume */
765 NULL,
766 /* pfnAttach */
767 NULL,
768 /* pfnDetach */
769 NULL,
770 /* pfnPowerOff */
771 NULL,
772 /* pfnSoftReset */
773 NULL,
774 /* u32EndVersion */
775 PDM_DRVREG_VERSION
776};
777
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