VirtualBox

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

Last change on this file since 89611 was 89584, checked in by vboxsync, 4 years ago

Audio/ValKit: More code for completely self-contained (self) testing. bugref:10008

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