VirtualBox

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

Last change on this file since 90211 was 90183, checked in by vboxsync, 3 years ago

Audio/ValKit: More code for guest recording tests in 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: 42.1 KB
Line 
1/* $Id: DrvHostAudioValidationKit.cpp 90183 2021-07-14 14:14:32Z 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/semaphore.h>
28#include <iprt/stream.h>
29#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
30
31#include <VBox/log.h>
32#include <VBox/vmm/pdmaudioifs.h>
33#include <VBox/vmm/pdmaudioinline.h>
34
35#include "VBoxDD.h"
36#include "AudioHlp.h"
37#include "AudioTest.h"
38#include "AudioTestService.h"
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Structure for keeping a Validation Kit input/output stream.
46 */
47typedef struct VALKITAUDIOSTREAM
48{
49 /** Common part. */
50 PDMAUDIOBACKENDSTREAM Core;
51 /** The stream's acquired configuration. */
52 PDMAUDIOSTREAMCFG Cfg;
53 /** How much bytes are available to read (only for capturing streams). */
54 uint32_t cbAvail;
55} VALKITAUDIOSTREAM;
56/** Pointer to a Validation Kit stream. */
57typedef VALKITAUDIOSTREAM *PVALKITAUDIOSTREAM;
58
59/**
60 * Test tone-specific instance data.
61 */
62typedef struct VALKITTESTTONEDATA
63{
64 union
65 {
66 struct
67 {
68 /** How many bytes to write. */
69 uint64_t cbToWrite;
70 /** How many bytes already written. */
71 uint64_t cbWritten;
72 } Rec;
73 struct
74 {
75 /** How many bytes to read. */
76 uint64_t cbToRead;
77 /** How many bytes already read. */
78 uint64_t cbRead;
79 } Play;
80 } u;
81 /** The test tone instance to use. */
82 AUDIOTESTTONE Tone;
83 /** The test tone parameters to use. */
84 AUDIOTESTTONEPARMS Parms;
85} VALKITTESTTONEDATA;
86
87/**
88 * Structure keeping a single Validation Kit test.
89 */
90typedef struct VALKITTESTDATA
91{
92 /** The list node. */
93 RTLISTNODE Node;
94 /** Index in test sequence (0-based). */
95 uint32_t idxTest;
96 /** Current test set entry to process. */
97 PAUDIOTESTENTRY pEntry;
98 /** Current test object to process. */
99 AUDIOTESTOBJ Obj;
100 /** Stream configuration to use for this test. */
101 PDMAUDIOSTREAMCFG StreamCfg;
102 union
103 {
104 /** Test tone-specific data. */
105 VALKITTESTTONEDATA TestTone;
106 } t;
107 /** Time stamp (real, in ms) when test started. */
108 uint64_t msStartedTS;
109} VALKITTESTDATA;
110/** Pointer to Validation Kit test data. */
111typedef VALKITTESTDATA *PVALKITTESTDATA;
112
113/**
114 * Validation Kit audio driver instance data.
115 * @implements PDMIAUDIOCONNECTOR
116 */
117typedef struct DRVHOSTVALKITAUDIO
118{
119 /** Pointer to the driver instance structure. */
120 PPDMDRVINS pDrvIns;
121 /** Pointer to host audio interface. */
122 PDMIHOSTAUDIO IHostAudio;
123 /** Temporary path to use. */
124 char szPathTemp[RTPATH_MAX];
125 /** Output path to use. */
126 char szPathOut[RTPATH_MAX];
127 /** Current test set being handled.
128 * At the moment only one test set can be around at a time. */
129 AUDIOTESTSET Set;
130 /** Number of total tests created. */
131 uint32_t cTestsTotal;
132 /** Number of tests in \a lstTestsRec. */
133 uint32_t cTestsRec;
134 /** List keeping the recording tests (FIFO). */
135 RTLISTANCHOR lstTestsRec;
136 /** Pointer to current recording test being processed.
137 * NULL if no current test active. */
138 PVALKITTESTDATA pTestCurRec;
139 /** Number of tests in \a lstTestsPlay. */
140 uint32_t cTestsPlay;
141 /** List keeping the recording tests (FIFO). */
142 RTLISTANCHOR lstTestsPlay;
143 /** Pointer to current playback test being processed.
144 * NULL if no current test active. */
145 PVALKITTESTDATA pTestCurPlay;
146 /** Critical section for serializing access across threads. */
147 RTCRITSECT CritSect;
148 /** Whether the test set needs to end.
149 * Needed for packing up (to archive) and termination, as capturing and playback
150 * can run in asynchronous threads. */
151 bool fTestSetEnd;
152 /** Event semaphore for waiting on the current test set to end. */
153 RTSEMEVENT EventSemEnded;
154 /** The Audio Test Service (ATS) instance. */
155 ATSSERVER Srv;
156 /** Absolute path to the packed up test set archive.
157 * Keep it simple for now and only support one (open) archive at a time. */
158 char szTestSetArchive[RTPATH_MAX];
159 /** File handle to the (opened) test set archive for reading. */
160 RTFILE hTestSetArchive;
161
162} DRVHOSTVALKITAUDIO;
163/** Pointer to a Validation Kit host audio driver instance. */
164typedef DRVHOSTVALKITAUDIO *PDRVHOSTVALKITAUDIO;
165
166
167/*********************************************************************************************************************************
168* Internal test handling code *
169*********************************************************************************************************************************/
170
171/**
172 * Unregisters a ValKit test, common code.
173 *
174 * @param pTst Test to unregister.
175 * The pointer will be invalid afterwards.
176 */
177static void drvHostValKiUnregisterTest(PVALKITTESTDATA pTst)
178{
179 AssertPtrReturnVoid(pTst);
180
181 RTListNodeRemove(&pTst->Node);
182
183 AudioTestObjClose(pTst->Obj);
184 pTst->Obj = NULL;
185
186 if (pTst->pEntry) /* Set set entry assign? Mark as done. */
187 {
188 AssertPtrReturnVoid(pTst->pEntry);
189 pTst->pEntry = NULL;
190 }
191
192 RTMemFree(pTst);
193 pTst = NULL;
194}
195
196/**
197 * Unregisters a ValKit recording test.
198 *
199 * @param pThis ValKit audio driver instance.
200 * @param pTst Test to unregister.
201 * The pointer will be invalid afterwards.
202 */
203static void drvHostValKiUnregisterRecTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
204{
205 drvHostValKiUnregisterTest(pTst);
206
207 Assert(pThis->cTestsRec);
208 pThis->cTestsRec--;
209}
210
211/**
212 * Unregisters a ValKit playback test.
213 *
214 * @param pThis ValKit audio driver instance.
215 * @param pTst Test to unregister.
216 * The pointer will be invalid afterwards.
217 */
218static void drvHostValKiUnregisterPlayTest(PDRVHOSTVALKITAUDIO pThis, PVALKITTESTDATA pTst)
219{
220 drvHostValKiUnregisterTest(pTst);
221
222 Assert(pThis->cTestsPlay);
223 pThis->cTestsPlay--;
224}
225
226/**
227 * Performs some internal cleanup / housekeeping of all registered tests.
228 *
229 * @param pThis ValKit audio driver instance.
230 */
231static void drvHostValKitCleanup(PDRVHOSTVALKITAUDIO pThis)
232{
233 LogRel(("ValKit: Cleaning up ...\n"));
234
235 if (pThis->cTestsRec)
236 LogRel(("ValKit: Warning: %RU32 guest recording tests still outstanding:\n", pThis->cTestsRec));
237
238 PVALKITTESTDATA pTst, pTstNext;
239 RTListForEachSafe(&pThis->lstTestsRec, pTst, pTstNext, VALKITTESTDATA, Node)
240 {
241 size_t const cbOutstanding = pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten;
242 if (cbOutstanding)
243 LogRel(("ValKit: \tRecording test #%RU32 has %RU64 bytes (%RU32ms) outstanding\n",
244 pTst->idxTest, cbOutstanding, PDMAudioPropsBytesToMilli(&pTst->t.TestTone.Parms.Props, (uint32_t)cbOutstanding)));
245 drvHostValKiUnregisterRecTest(pThis, pTst);
246 }
247
248 if (pThis->cTestsPlay)
249 LogRel(("ValKit: Warning: %RU32 guest playback tests still outstanding:\n", pThis->cTestsPlay));
250
251 RTListForEachSafe(&pThis->lstTestsPlay, pTst, pTstNext, VALKITTESTDATA, Node)
252 {
253 size_t const cbOutstanding = pTst->t.TestTone.u.Play.cbToRead - pTst->t.TestTone.u.Play.cbRead;
254 if (cbOutstanding)
255 LogRel(("ValKit: \tPlayback test #%RU32 has %RU64 bytes (%RU32ms) outstanding\n",
256 pTst->idxTest, cbOutstanding, PDMAudioPropsBytesToMilli(&pTst->t.TestTone.Parms.Props, (uint32_t)cbOutstanding)));
257 drvHostValKiUnregisterPlayTest(pThis, pTst);
258 }
259
260 Assert(pThis->cTestsRec == 0);
261 Assert(pThis->cTestsPlay == 0);
262}
263
264
265/*********************************************************************************************************************************
266* ATS callback implementations *
267*********************************************************************************************************************************/
268
269/** @copydoc ATSCALLBACKS::pfnTestSetBegin */
270static DECLCALLBACK(int) drvHostValKitTestSetBegin(void const *pvUser, const char *pszTag)
271{
272 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
273
274 int rc = RTCritSectEnter(&pThis->CritSect);
275 if (RT_SUCCESS(rc))
276 {
277
278 LogRel(("ValKit: Beginning test set '%s'\n", pszTag));
279 rc = AudioTestSetCreate(&pThis->Set, pThis->szPathTemp, pszTag);
280
281 int rc2 = RTCritSectLeave(&pThis->CritSect);
282 if (RT_SUCCESS(rc))
283 rc = rc2;
284 }
285
286 if (RT_FAILURE(rc))
287 LogRel(("ValKit: Beginning test set failed with %Rrc\n", rc));
288
289 return rc;
290}
291
292/** @copydoc ATSCALLBACKS::pfnTestSetEnd */
293static DECLCALLBACK(int) drvHostValKitTestSetEnd(void const *pvUser, const char *pszTag)
294{
295 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
296
297 int rc = RTCritSectEnter(&pThis->CritSect);
298 if (RT_SUCCESS(rc))
299 {
300 const PAUDIOTESTSET pSet = &pThis->Set;
301
302 if (AudioTestSetIsRunning(pSet))
303 {
304 ASMAtomicWriteBool(&pThis->fTestSetEnd, true);
305
306 rc = RTCritSectLeave(&pThis->CritSect);
307 if (RT_SUCCESS(rc))
308 {
309 LogRel(("ValKit: Waiting for runnig test set '%s' to end ...\n", pszTag));
310 rc = RTSemEventWait(pThis->EventSemEnded, RT_MS_30SEC);
311
312 int rc2 = RTCritSectEnter(&pThis->CritSect);
313 if (RT_SUCCESS(rc))
314 rc = rc2;
315 }
316 }
317
318 if (RT_SUCCESS(rc))
319 {
320 LogRel(("ValKit: Ending test set '%s'\n", pszTag));
321
322 /* Close the test set first. */
323 rc = AudioTestSetClose(pSet);
324 if (RT_SUCCESS(rc))
325 {
326 /* Before destroying the test environment, pack up the test set so
327 * that it's ready for transmission. */
328 rc = AudioTestSetPack(pSet, pThis->szPathOut, pThis->szTestSetArchive, sizeof(pThis->szTestSetArchive));
329 if (RT_SUCCESS(rc))
330 LogRel(("ValKit: Packed up to '%s'\n", pThis->szTestSetArchive));
331
332 /* Do some internal housekeeping. */
333 drvHostValKitCleanup(pThis);
334
335#ifndef DEBUG_andy
336 int rc2 = AudioTestSetWipe(pSet);
337 if (RT_SUCCESS(rc))
338 rc = rc2;
339#endif
340 }
341
342 AudioTestSetDestroy(pSet);
343 }
344
345 int rc2 = RTCritSectLeave(&pThis->CritSect);
346 if (RT_SUCCESS(rc))
347 rc = rc2;
348 }
349
350 if (RT_FAILURE(rc))
351 LogRel(("ValKit: Ending test set failed with %Rrc\n", rc));
352
353 return rc;
354}
355
356/** @copydoc ATSCALLBACKS::pfnTonePlay
357 *
358 * Creates and registers a new test tone guest recording test.
359 * This backend will play (inject) input data to the guest.
360 */
361static DECLCALLBACK(int) drvHostValKitRegisterGuestRecTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
362{
363 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
364
365 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
366 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
367
368 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
369
370 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
371 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
372
373 AudioTestToneInit(&pTestData->t.TestTone.Tone, &pTestData->t.TestTone.Parms.Props, pTestData->t.TestTone.Parms.dbFreqHz);
374
375 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
376 pTestData->t.TestTone.Parms.msDuration);
377 int rc = RTCritSectEnter(&pThis->CritSect);
378 if (RT_SUCCESS(rc))
379 {
380 LogRel(("ValKit: Registered guest recording test #%RU32 (%RU32ms, %RU64 bytes)\n",
381 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
382
383 RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
384
385 pTestData->idxTest = pThis->cTestsTotal++;
386
387 pThis->cTestsRec++;
388
389 int rc2 = RTCritSectLeave(&pThis->CritSect);
390 AssertRC(rc2);
391 }
392
393 return VINF_SUCCESS;
394}
395
396/** @copydoc ATSCALLBACKS::pfnToneRecord
397 *
398 * Creates and registers a new test tone guest playback test.
399 * This backend will record the guest output data.
400 */
401static DECLCALLBACK(int) drvHostValKitRegisterGuestPlayTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
402{
403 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
404
405 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
406 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
407
408 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
409
410 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
411 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
412
413 pTestData->t.TestTone.u.Play.cbToRead = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
414 pTestData->t.TestTone.Parms.msDuration);
415 int rc = RTCritSectEnter(&pThis->CritSect);
416 if (RT_SUCCESS(rc))
417 {
418 LogRel(("ValKit: Registered guest playback test #%RU32 (%RU32ms, %RU64 bytes)\n",
419 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Play.cbToRead));
420
421 RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
422
423 pTestData->idxTest = pThis->cTestsTotal++;
424
425 pThis->cTestsPlay++;
426
427 int rc2 = RTCritSectLeave(&pThis->CritSect);
428 AssertRC(rc2);
429 }
430
431 return VINF_SUCCESS;
432}
433
434/** @copydoc ATSCALLBACKS::pfnTestSetSendBegin */
435static DECLCALLBACK(int) drvHostValKitTestSetSendBeginCallback(void const *pvUser, const char *pszTag)
436{
437 RT_NOREF(pszTag);
438
439 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
440
441 int rc = RTCritSectEnter(&pThis->CritSect);
442 if (RT_SUCCESS(rc))
443 {
444 if (RTFileExists(pThis->szTestSetArchive)) /* Has the archive successfully been created yet? */
445 {
446 rc = RTFileOpen(&pThis->hTestSetArchive, pThis->szTestSetArchive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
447 if (RT_SUCCESS(rc))
448 {
449 uint64_t uSize;
450 rc = RTFileQuerySize(pThis->hTestSetArchive, &uSize);
451 if (RT_SUCCESS(rc))
452 LogRel(("ValKit: Sending test set '%s' (%zu bytes)\n", pThis->szTestSetArchive, uSize));
453 }
454 }
455 else
456 rc = VERR_FILE_NOT_FOUND;
457
458 int rc2 = RTCritSectLeave(&pThis->CritSect);
459 if (RT_SUCCESS(rc))
460 rc = rc2;
461 }
462
463 if (RT_FAILURE(rc))
464 LogRel(("ValKit: Beginning to send test set failed with %Rrc\n", rc));
465
466 return rc;
467}
468
469/** @copydoc ATSCALLBACKS::pfnTestSetSendRead */
470static DECLCALLBACK(int) drvHostValKitTestSetSendReadCallback(void const *pvUser,
471 const char *pszTag, void *pvBuf, size_t cbBuf, size_t *pcbRead)
472{
473 RT_NOREF(pszTag);
474
475 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
476
477 int rc = RTCritSectEnter(&pThis->CritSect);
478 if (RT_SUCCESS(rc))
479 {
480 if (RTFileIsValid(pThis->hTestSetArchive))
481 {
482 rc = RTFileRead(pThis->hTestSetArchive, pvBuf, cbBuf, pcbRead);
483 }
484 else
485 rc = VERR_WRONG_ORDER;
486
487 int rc2 = RTCritSectLeave(&pThis->CritSect);
488 if (RT_SUCCESS(rc))
489 rc = rc2;
490 }
491
492 if (RT_FAILURE(rc))
493 LogRel(("ValKit: Reading from test set failed with %Rrc\n", rc));
494
495 return rc;
496}
497
498/** @copydoc ATSCALLBACKS::pfnTestSetSendEnd */
499static DECLCALLBACK(int) drvHostValKitTestSetSendEndCallback(void const *pvUser, const char *pszTag)
500{
501 RT_NOREF(pszTag);
502
503 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
504
505 int rc = RTCritSectEnter(&pThis->CritSect);
506 if (RT_SUCCESS(rc))
507 {
508 if (RTFileIsValid(pThis->hTestSetArchive))
509 {
510 rc = RTFileClose(pThis->hTestSetArchive);
511 if (RT_SUCCESS(rc))
512 pThis->hTestSetArchive = NIL_RTFILE;
513 }
514
515 int rc2 = RTCritSectLeave(&pThis->CritSect);
516 if (RT_SUCCESS(rc))
517 rc = rc2;
518 }
519
520 if (RT_FAILURE(rc))
521 LogRel(("ValKit: Ending to send test set failed with %Rrc\n", rc));
522
523 return rc;
524}
525
526
527/*********************************************************************************************************************************
528* PDMIHOSTAUDIO interface implementation *
529*********************************************************************************************************************************/
530
531/**
532 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
533 */
534static DECLCALLBACK(int) drvHostValKitAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
535{
536 RT_NOREF(pInterface);
537 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
538
539 /*
540 * Fill in the config structure.
541 */
542 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Validation Kit");
543 pBackendCfg->cbStream = sizeof(VALKITAUDIOSTREAM);
544 pBackendCfg->fFlags = 0;
545 pBackendCfg->cMaxStreamsOut = 1; /* Output (Playback). */
546 pBackendCfg->cMaxStreamsIn = 1; /* Input (Recording). */
547
548 return VINF_SUCCESS;
549}
550
551
552/**
553 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
554 */
555static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostValKitAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
556{
557 RT_NOREF(enmDir);
558 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
559
560 return PDMAUDIOBACKENDSTS_RUNNING;
561}
562
563
564/**
565 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
566 */
567static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
568 PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
569{
570 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
571 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
572 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
573 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
574 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
575 RT_NOREF(pThis);
576
577 int rc = VINF_SUCCESS;
578 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
579 return rc;
580}
581
582/**
583 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
584 */
585static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
586 bool fImmediate)
587{
588 RT_NOREF(pInterface, fImmediate);
589 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
590 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
591
592 return VINF_SUCCESS;
593}
594
595
596/**
597 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
598 */
599static DECLCALLBACK(int) drvHostValKitAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
600{
601 RT_NOREF(pInterface, pStream);
602 return VINF_SUCCESS;
603}
604
605
606/**
607 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
608 */
609static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
610{
611 RT_NOREF(pInterface, pStream);
612 return VINF_SUCCESS;
613}
614
615
616/**
617 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
618 */
619static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
620{
621 RT_NOREF(pInterface, pStream);
622 return VINF_SUCCESS;
623}
624
625
626/**
627 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
628 */
629static DECLCALLBACK(int) drvHostValKitAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
630{
631 RT_NOREF(pInterface, pStream);
632 return VINF_SUCCESS;
633}
634
635
636/**
637 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
638 */
639static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
640{
641 RT_NOREF(pStream);
642
643 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
644
645 int rc = RTCritSectEnter(&pThis->CritSect);
646 if (RT_SUCCESS(rc))
647 {
648 PVALKITTESTDATA pTst = pThis->pTestCurPlay;
649
650 if (pTst)
651 {
652 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
653 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
654
655 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
656 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
657 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
658
659 AudioTestSetTestDone(pTst->pEntry);
660
661 pThis->pTestCurPlay = NULL;
662 pTst = NULL;
663
664 if (ASMAtomicReadBool(&pThis->fTestSetEnd))
665 rc = RTSemEventSignal(pThis->EventSemEnded);
666 }
667
668 int rc2 = RTCritSectLeave(&pThis->CritSect);
669 AssertRC(rc2);
670 }
671
672 return VINF_SUCCESS;
673}
674
675
676/**
677 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
678 */
679static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
680{
681 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
682 PVALKITAUDIOSTREAM pStrmValKit = (PVALKITAUDIOSTREAM)pStream;
683 PVALKITTESTDATA pTst = NULL;
684
685 int rc = RTCritSectEnter(&pThis->CritSect);
686 if (RT_SUCCESS(rc))
687 {
688 if (pThis->pTestCurRec == NULL)
689 {
690 pThis->pTestCurRec = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
691 if (pThis->pTestCurRec)
692 LogRel(("ValKit: Next guest recording test in queue is test #%RU32\n", pThis->pTestCurRec->idxTest));
693 }
694
695 pTst = pThis->pTestCurRec;
696
697 int rc2 = RTCritSectLeave(&pThis->CritSect);
698 AssertRC(rc2);
699 }
700
701 if ( pTst
702 && pTst->pEntry == NULL) /* Test not started yet? */
703 {
704 AUDIOTESTPARMS Parms;
705 RT_ZERO(Parms);
706 Parms.enmDir = PDMAUDIODIR_OUT;
707 Parms.enmType = AUDIOTESTTYPE_TESTTONE_PLAY;
708 Parms.TestTone = pTst->t.TestTone.Parms;
709
710 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
711 &Parms, &pTst->pEntry);
712 if (RT_SUCCESS(rc))
713 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-play.pcm", &pTst->Obj);
714
715 if (RT_SUCCESS(rc))
716 {
717 pTst->msStartedTS = RTTimeMilliTS();
718 LogRel(("ValKit: Injecting audio input data (%RU16Hz, %RU32ms, %RU32 bytes) started\n",
719 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
720 pTst->t.TestTone.Parms.msDuration, pTst->t.TestTone.u.Rec.cbToWrite));
721 }
722
723 pStrmValKit->cbAvail += pTst->t.TestTone.u.Rec.cbToWrite;
724 LogRel(("ValKit: Now total of %RU32 bytes available for capturing\n", pStrmValKit->cbAvail));
725 }
726
727 LogRel(("ValKit: Test #%RU32: Reporting %RU32 bytes as available\n",
728 pTst ? pTst->idxTest : 9999, pStrmValKit->cbAvail));
729 return pStrmValKit->cbAvail;
730}
731
732
733/**
734 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
735 */
736static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
737{
738 RT_NOREF(pInterface, pStream);
739 return UINT32_MAX;
740}
741
742
743/**
744 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
745 */
746static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
747 PPDMAUDIOBACKENDSTREAM pStream)
748{
749 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
750
751 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
752 PDMHOSTAUDIOSTREAMSTATE enmState = PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING;
753
754 if (pStream->pStream->Cfg.enmDir == PDMAUDIODIR_IN)
755 {
756 int rc2 = RTCritSectEnter(&pThis->CritSect);
757 if (RT_SUCCESS(rc2))
758 {
759 enmState = pThis->cTestsRec == 0
760 ? PDMHOSTAUDIOSTREAMSTATE_INACTIVE : PDMHOSTAUDIOSTREAMSTATE_OKAY;
761
762 rc2 = RTCritSectLeave(&pThis->CritSect);
763 AssertRC(rc2);
764 }
765 }
766 else
767 enmState = PDMHOSTAUDIOSTREAMSTATE_OKAY;
768
769 return enmState;
770}
771
772
773/**
774 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
775 */
776static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
777 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
778{
779 if (cbBuf == 0)
780 {
781 /* Fend off draining calls. */
782 *pcbWritten = 0;
783 return VINF_SUCCESS;
784 }
785
786 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
787 PVALKITTESTDATA pTst = NULL;
788
789 bool const fIsSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBuf, cbBuf);
790
791 int rc = RTCritSectEnter(&pThis->CritSect);
792 if (RT_SUCCESS(rc))
793 {
794 if (pThis->pTestCurPlay == NULL)
795 {
796 pThis->pTestCurPlay = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
797 if (pThis->pTestCurPlay)
798 LogRel(("ValKit: Next guest playback test in queue is test #%RU32\n", pThis->pTestCurPlay->idxTest));
799 }
800
801 pTst = pThis->pTestCurPlay;
802
803 int rc2 = RTCritSectLeave(&pThis->CritSect);
804 AssertRC(rc2);
805 }
806
807 if (pTst == NULL) /* Empty list? */
808 {
809#ifdef DEBUG_andy
810 if (!fIsSilence)
811#endif
812 LogRel(("ValKit: Warning: Guest is playing back audio (%s, %RU32 bytes, %RU64ms) when no playback test is active\n",
813 fIsSilence ? "silence" : "audible", cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
814
815 *pcbWritten = cbBuf;
816 return VINF_SUCCESS;
817 }
818
819#ifndef DEBUG_andy
820 if (fIsSilence)
821 LogRel2(("ValKit: Guest is playing back %RU32 bytes (%RU64ms) silence\n",
822 cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
823#endif
824
825 const bool fHandleSilence = false; /** @todo Skip blocks of entire silence for now. */
826
827 if (pTst->pEntry == NULL) /* Test not started yet? */
828 {
829 AUDIOTESTPARMS Parms;
830 RT_ZERO(Parms);
831 Parms.enmDir = PDMAUDIODIR_IN;
832 Parms.enmType = AUDIOTESTTYPE_TESTTONE_RECORD;
833 Parms.TestTone = pTst->t.TestTone.Parms;
834
835 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
836 &Parms, &pTst->pEntry);
837 if (RT_SUCCESS(rc))
838 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-rec.pcm", &pTst->Obj);
839
840 if (RT_SUCCESS(rc))
841 {
842 pTst->msStartedTS = RTTimeMilliTS();
843 LogRel(("ValKit: Test #%RU32: Recording audio data (%RU16Hz, %RU32ms) started\n",
844 pTst->idxTest, (uint16_t)Parms.TestTone.dbFreqHz, Parms.TestTone.msDuration));
845 }
846 }
847
848 uint32_t cbWritten = 0;
849
850 if (RT_SUCCESS(rc))
851 {
852 if ( !fIsSilence
853 || (fIsSilence && fHandleSilence))
854 {
855 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbBuf);
856 pTst->t.TestTone.u.Play.cbRead += cbBuf;
857
858 const bool fComplete = pTst->t.TestTone.u.Play.cbRead >= pTst->t.TestTone.u.Play.cbToRead;
859 if (fComplete)
860 {
861 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
862 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
863
864 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
865 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
866 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
867
868 AudioTestSetTestDone(pTst->pEntry);
869
870 rc = RTCritSectEnter(&pThis->CritSect);
871 if (RT_SUCCESS(rc))
872 {
873 drvHostValKiUnregisterPlayTest(pThis, pTst);
874
875 pThis->pTestCurPlay = NULL;
876 pTst = NULL;
877
878 int rc2 = RTCritSectLeave(&pThis->CritSect);
879 if (RT_SUCCESS(rc))
880 rc = rc2;
881 }
882 }
883 }
884
885 /* Always report everything as being played. */
886 cbWritten = cbBuf;
887 }
888
889 if (RT_FAILURE(rc))
890 {
891 if ( pTst
892 && pTst->pEntry)
893 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
894 LogRel(("ValKit: Recording audio data failed with %Rrc\n", rc));
895 }
896
897 *pcbWritten = cbWritten;
898
899 return VINF_SUCCESS; /** @todo Return rc here? */
900}
901
902
903/**
904 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
905 */
906static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
907 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
908{
909 RT_NOREF(pStream);
910
911 if (cbBuf == 0)
912 {
913 /* Fend off draining calls. */
914 *pcbRead = 0;
915 return VINF_SUCCESS;
916 }
917
918 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
919 PVALKITAUDIOSTREAM pStrmValKit = (PVALKITAUDIOSTREAM)pStream;
920 PVALKITTESTDATA pTst = NULL;
921
922 int rc = RTCritSectEnter(&pThis->CritSect);
923 if (RT_SUCCESS(rc))
924 {
925 if (pThis->pTestCurRec == NULL)
926 {
927 pThis->pTestCurRec = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
928 if (pThis->pTestCurRec)
929 LogRel(("ValKit: Next guest recording test in queue is test #%RU32\n", pThis->pTestCurRec->idxTest));
930 }
931
932 pTst = pThis->pTestCurRec;
933
934 int rc2 = RTCritSectLeave(&pThis->CritSect);
935 AssertRC(rc2);
936 }
937
938 if (pTst == NULL) /* Empty list? */
939 {
940 LogRel(("ValKit: Warning: Guest is trying to record %RU32 bytes (%RU32ms) of audio data when no recording test is active (%RU32 bytes available)\n",
941 cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf), pStrmValKit->cbAvail));
942
943 /** @todo Not sure yet why this happens after all data has been captured sometimes,
944 * but the guest side just will record silence and the audio test verification
945 * will have to deal with (and/or report) it then. */
946 PDMAudioPropsClearBuffer(&pStream->pStream->Cfg.Props, pvBuf, cbBuf,
947 PDMAudioPropsBytesToFrames(&pStream->pStream->Cfg.Props, cbBuf));
948
949 *pcbRead = cbBuf; /* Just report back stuff as being "recorded" (silence). */
950 return VINF_SUCCESS;
951 }
952
953 uint32_t cbRead = 0;
954
955 if (RT_SUCCESS(rc))
956 {
957 uint32_t cbToWrite = RT_MIN(cbBuf,
958 pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten);
959 if (cbToWrite)
960 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, cbToWrite, &cbRead);
961 if ( RT_SUCCESS(rc)
962 && cbRead)
963 {
964 Assert(cbRead == cbToWrite);
965
966 if (cbRead > pStrmValKit->cbAvail)
967 LogRel(("ValKit: Warning: Test #%RU32: Reading more from capturing stream than availabe for (%RU32 vs. %RU32)\n",
968 pTst->idxTest, cbRead, pStrmValKit->cbAvail));
969
970 pStrmValKit->cbAvail -= RT_MIN(pStrmValKit->cbAvail, cbRead);
971
972 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbRead);
973 if (RT_SUCCESS(rc))
974 {
975 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
976 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
977
978 LogRel(("ValKit: Test #%RU32: Read %RU32 bytes of (capturing) audio data (%RU32 bytes left)\n",
979 pTst->idxTest, cbRead, pStrmValKit->cbAvail));
980
981 const bool fComplete = pTst->t.TestTone.u.Rec.cbWritten >= pTst->t.TestTone.u.Rec.cbToWrite;
982 if (fComplete)
983 {
984 LogRel(("ValKit: Test #%RU32: Recording done (took %RU32ms)\n",
985 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
986
987 AudioTestSetTestDone(pTst->pEntry);
988
989 rc = RTCritSectEnter(&pThis->CritSect);
990 if (RT_SUCCESS(rc))
991 {
992 drvHostValKiUnregisterRecTest(pThis, pTst);
993
994 pThis->pTestCurRec = NULL;
995 pTst = NULL;
996
997 int rc2 = RTCritSectLeave(&pThis->CritSect);
998 AssertRC(rc2);
999 }
1000 }
1001 }
1002 }
1003 }
1004
1005 if (ASMAtomicReadBool(&pThis->fTestSetEnd))
1006 {
1007 int rc2 = RTSemEventSignal(pThis->EventSemEnded);
1008 AssertRC(rc2);
1009 }
1010
1011 if (RT_FAILURE(rc))
1012 {
1013 if (pTst->pEntry)
1014 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
1015 LogRel(("ValKit: Test #%RU32: Failed with %Rrc\n", pTst->idxTest, rc));
1016 }
1017
1018 *pcbRead = cbRead;
1019
1020 return VINF_SUCCESS; /** @todo Return rc here? */
1021}
1022
1023
1024/**
1025 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1026 */
1027static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1028{
1029 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1030 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1031
1032 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1033 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
1034 return NULL;
1035}
1036
1037
1038/**
1039 * Constructs a VaKit audio driver instance.
1040 *
1041 * @copydoc FNPDMDRVCONSTRUCT
1042 */
1043static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1044{
1045 RT_NOREF(pCfg, fFlags);
1046 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1047 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1048 LogRel(("Audio: Initializing VALKIT driver\n"));
1049
1050 /*
1051 * Init the static parts.
1052 */
1053 pThis->pDrvIns = pDrvIns;
1054 /* IBase */
1055 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
1056 /* IHostAudio */
1057 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
1058 pThis->IHostAudio.pfnGetDevices = NULL;
1059 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
1060 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
1061 pThis->IHostAudio.pfnStreamConfigHint = NULL;
1062 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
1063 pThis->IHostAudio.pfnStreamInitAsync = NULL;
1064 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
1065 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
1066 pThis->IHostAudio.pfnStreamEnable = drvHostValKitAudioHA_StreamEnable;
1067 pThis->IHostAudio.pfnStreamDisable = drvHostValKitAudioHA_StreamDisable;
1068 pThis->IHostAudio.pfnStreamPause = drvHostValKitAudioHA_StreamPause;
1069 pThis->IHostAudio.pfnStreamResume = drvHostValKitAudioHA_StreamResume;
1070 pThis->IHostAudio.pfnStreamDrain = drvHostValKitAudioHA_StreamDrain;
1071 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
1072 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
1073 pThis->IHostAudio.pfnStreamGetPending = NULL;
1074 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
1075 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
1076 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
1077
1078 int rc = RTCritSectInit(&pThis->CritSect);
1079 AssertRCReturn(rc, rc);
1080 rc = RTSemEventCreate(&pThis->EventSemEnded);
1081 AssertRCReturn(rc, rc);
1082
1083 pThis->fTestSetEnd = false;
1084
1085 RTListInit(&pThis->lstTestsRec);
1086 pThis->cTestsRec = 0;
1087 RTListInit(&pThis->lstTestsPlay);
1088 pThis->cTestsPlay = 0;
1089
1090 ATSCALLBACKS Callbacks;
1091 RT_ZERO(Callbacks);
1092 Callbacks.pfnTestSetBegin = drvHostValKitTestSetBegin;
1093 Callbacks.pfnTestSetEnd = drvHostValKitTestSetEnd;
1094 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
1095 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
1096 Callbacks.pfnTestSetSendBegin = drvHostValKitTestSetSendBeginCallback;
1097 Callbacks.pfnTestSetSendRead = drvHostValKitTestSetSendReadCallback;
1098 Callbacks.pfnTestSetSendEnd = drvHostValKitTestSetSendEndCallback;
1099 Callbacks.pvUser = pThis;
1100
1101 /** @todo Make this configurable via CFGM. */
1102 const char *pszTcpAddr = "127.0.0.1"; /* Only reachable for localhost for now. */
1103 uint32_t uTcpPort = ATS_TCP_DEF_BIND_PORT_VALKIT;
1104
1105 LogRel(("ValKit: Starting Audio Test Service (ATS) at %s:%RU32...\n",
1106 pszTcpAddr, uTcpPort));
1107
1108 rc = AudioTestSvcCreate(&pThis->Srv);
1109 if (RT_SUCCESS(rc))
1110 {
1111 RTGETOPTUNION Val;
1112 RT_ZERO(Val);
1113
1114 Val.psz = "server"; /** @ŧodo No client connection mode needed here (yet). Make this configurable via CFGM. */
1115 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_MODE, &Val);
1116 AssertRC(rc);
1117
1118 Val.psz = pszTcpAddr;
1119 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_ADDRESS, &Val);
1120 AssertRC(rc);
1121
1122 Val.u16 = uTcpPort;
1123 rc = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_PORT, &Val);
1124 AssertRC(rc);
1125
1126 rc = AudioTestSvcInit(&pThis->Srv, &Callbacks);
1127 if (RT_SUCCESS(rc))
1128 rc = AudioTestSvcStart(&pThis->Srv);
1129 }
1130
1131 if (RT_SUCCESS(rc))
1132 {
1133 LogRel(("ValKit: Audio Test Service (ATS) running\n"));
1134
1135 /** @todo Let the following be customizable by CFGM later. */
1136 rc = AudioTestPathCreateTemp(pThis->szPathTemp, sizeof(pThis->szPathTemp), "ValKitAudio");
1137 if (RT_SUCCESS(rc))
1138 {
1139 LogRel(("ValKit: Using temp dir '%s'\n", pThis->szPathTemp));
1140 rc = AudioTestPathGetTemp(pThis->szPathOut, sizeof(pThis->szPathOut));
1141 if (RT_SUCCESS(rc))
1142 LogRel(("ValKit: Using output dir '%s'\n", pThis->szPathOut));
1143 }
1144 }
1145
1146 if (RT_FAILURE(rc))
1147 LogRel(("ValKit: Initialization failed, rc=%Rrc\n", rc));
1148
1149 return rc;
1150}
1151
1152static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
1153{
1154 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1155 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1156
1157 LogRel(("ValKit: Shutting down Audio Test Service (ATS) ...\n"));
1158
1159 int rc = AudioTestSvcShutdown(&pThis->Srv);
1160 if (RT_SUCCESS(rc))
1161 rc = AudioTestSvcDestroy(&pThis->Srv);
1162
1163 if (RT_SUCCESS(rc))
1164 {
1165 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) complete\n"));
1166 drvHostValKitCleanup(pThis);
1167 }
1168 else
1169 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) failed, rc=%Rrc\n", rc));
1170
1171 /* Try cleaning up a bit. */
1172 RTDirRemove(pThis->szPathTemp);
1173 RTDirRemove(pThis->szPathOut);
1174
1175 RTSemEventDestroy(pThis->EventSemEnded);
1176
1177 if (RTCritSectIsInitialized(&pThis->CritSect))
1178 {
1179 int rc2 = RTCritSectDelete(&pThis->CritSect);
1180 if (RT_SUCCESS(rc))
1181 rc = rc2;
1182 }
1183
1184 if (RT_FAILURE(rc))
1185 LogRel(("ValKit: Destruction failed, rc=%Rrc\n", rc));
1186}
1187
1188/**
1189 * Char driver registration record.
1190 */
1191const PDMDRVREG g_DrvHostValidationKitAudio =
1192{
1193 /* u32Version */
1194 PDM_DRVREG_VERSION,
1195 /* szName */
1196 "ValidationKitAudio",
1197 /* szRCMod */
1198 "",
1199 /* szR0Mod */
1200 "",
1201 /* pszDescription */
1202 "ValidationKitAudio audio host driver",
1203 /* fFlags */
1204 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1205 /* fClass. */
1206 PDM_DRVREG_CLASS_AUDIO,
1207 /* cMaxInstances */
1208 ~0U,
1209 /* cbInstance */
1210 sizeof(DRVHOSTVALKITAUDIO),
1211 /* pfnConstruct */
1212 drvHostValKitAudioConstruct,
1213 /* pfnDestruct */
1214 drvHostValKitAudioDestruct,
1215 /* pfnRelocate */
1216 NULL,
1217 /* pfnIOCtl */
1218 NULL,
1219 /* pfnPowerOn */
1220 NULL,
1221 /* pfnReset */
1222 NULL,
1223 /* pfnSuspend */
1224 NULL,
1225 /* pfnResume */
1226 NULL,
1227 /* pfnAttach */
1228 NULL,
1229 /* pfnDetach */
1230 NULL,
1231 /* pfnPowerOff */
1232 NULL,
1233 /* pfnSoftReset */
1234 NULL,
1235 /* u32EndVersion */
1236 PDM_DRVREG_VERSION
1237};
1238
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