VirtualBox

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

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