VirtualBox

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

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

Audio/Validation Kit: More logging 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: 43.0 KB
Line 
1/* $Id: DrvHostAudioValidationKit.cpp 90983 2021-08-29 14:24:31Z 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 LogRel(("ValKit: Beginning test set '%s'\n", pszTag));
275
276 int rc = RTCritSectEnter(&pThis->CritSect);
277 if (RT_SUCCESS(rc))
278 {
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 LogRel(("ValKit: Ending test set '%s'\n", pszTag));
298
299 int rc = RTCritSectEnter(&pThis->CritSect);
300 if (RT_SUCCESS(rc))
301 {
302 const PAUDIOTESTSET pSet = &pThis->Set;
303
304 if (AudioTestSetIsRunning(pSet))
305 {
306 ASMAtomicWriteBool(&pThis->fTestSetEnd, true);
307
308 rc = RTCritSectLeave(&pThis->CritSect);
309 if (RT_SUCCESS(rc))
310 {
311 LogRel(("ValKit: Waiting for runnig test set '%s' to end ...\n", pszTag));
312 rc = RTSemEventWait(pThis->EventSemEnded, RT_MS_30SEC);
313 if (RT_FAILURE(rc))
314 LogRel(("ValKit: Waiting for runnig test set '%s' failed with %Rrc\n", pszTag, rc));
315
316 int rc2 = RTCritSectEnter(&pThis->CritSect);
317 if (RT_SUCCESS(rc))
318 rc = rc2;
319 }
320 }
321
322 if (RT_SUCCESS(rc))
323 {
324 LogRel(("ValKit: Closing test set '%s' ...\n", pszTag));
325
326 /* Close the test set first. */
327 rc = AudioTestSetClose(pSet);
328 if (RT_SUCCESS(rc))
329 {
330 /* Before destroying the test environment, pack up the test set so
331 * that it's ready for transmission. */
332 rc = AudioTestSetPack(pSet, pThis->szPathOut, pThis->szTestSetArchive, sizeof(pThis->szTestSetArchive));
333 if (RT_SUCCESS(rc))
334 {
335 LogRel(("ValKit: Packed up to '%s'\n", pThis->szTestSetArchive));
336 }
337 else
338 LogRel(("ValKit: Packing up test set failed with %Rrc\n", rc));
339
340 /* Do some internal housekeeping. */
341 drvHostValKitCleanup(pThis);
342
343#ifndef DEBUG_andy
344 int rc2 = AudioTestSetWipe(pSet);
345 if (RT_SUCCESS(rc))
346 rc = rc2;
347#endif
348 }
349 else
350 LogRel(("ValKit: Closing test set failed with %Rrc\n", rc));
351
352 int rc2 = AudioTestSetDestroy(pSet);
353 if (RT_FAILURE(rc2))
354 {
355 LogRel(("ValKit: Destroying test set failed with %Rrc\n", rc));
356 if (RT_SUCCESS(rc))
357 rc = rc2;
358 }
359 }
360
361 int rc2 = RTCritSectLeave(&pThis->CritSect);
362 if (RT_SUCCESS(rc))
363 rc = rc2;
364 }
365
366 if (RT_FAILURE(rc))
367 LogRel(("ValKit: Ending test set failed with %Rrc\n", rc));
368
369 return rc;
370}
371
372/** @copydoc ATSCALLBACKS::pfnTonePlay
373 *
374 * Creates and registers a new test tone guest recording test.
375 * This backend will play (inject) input data to the guest.
376 */
377static DECLCALLBACK(int) drvHostValKitRegisterGuestRecTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
378{
379 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
380
381 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
382 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
383
384 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
385
386 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
387 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
388
389 AudioTestToneInit(&pTestData->t.TestTone.Tone, &pTestData->t.TestTone.Parms.Props, pTestData->t.TestTone.Parms.dbFreqHz);
390
391 pTestData->t.TestTone.u.Rec.cbToWrite = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
392 pTestData->t.TestTone.Parms.msDuration);
393 int rc = RTCritSectEnter(&pThis->CritSect);
394 if (RT_SUCCESS(rc))
395 {
396 LogRel(("ValKit: Registering guest recording test #%RU32 (%RU32ms, %RU64 bytes)\n",
397 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite));
398
399 RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
400
401 pTestData->idxTest = pThis->cTestsTotal++;
402
403 pThis->cTestsRec++;
404
405 int rc2 = RTCritSectLeave(&pThis->CritSect);
406 AssertRC(rc2);
407 }
408
409 return VINF_SUCCESS;
410}
411
412/** @copydoc ATSCALLBACKS::pfnToneRecord
413 *
414 * Creates and registers a new test tone guest playback test.
415 * This backend will record the guest output data.
416 */
417static DECLCALLBACK(int) drvHostValKitRegisterGuestPlayTest(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
418{
419 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
420
421 PVALKITTESTDATA pTestData = (PVALKITTESTDATA)RTMemAllocZ(sizeof(VALKITTESTDATA));
422 AssertPtrReturn(pTestData, VERR_NO_MEMORY);
423
424 memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
425
426 AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
427 AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
428
429 pTestData->t.TestTone.u.Play.cbToRead = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
430 pTestData->t.TestTone.Parms.msDuration);
431 int rc = RTCritSectEnter(&pThis->CritSect);
432 if (RT_SUCCESS(rc))
433 {
434 LogRel(("ValKit: Registering guest playback test #%RU32 (%RU32ms, %RU64 bytes)\n",
435 pThis->cTestsTotal, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Play.cbToRead));
436
437 RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
438
439 pTestData->idxTest = pThis->cTestsTotal++;
440
441 pThis->cTestsPlay++;
442
443 int rc2 = RTCritSectLeave(&pThis->CritSect);
444 AssertRC(rc2);
445 }
446
447 return VINF_SUCCESS;
448}
449
450/** @copydoc ATSCALLBACKS::pfnTestSetSendBegin */
451static DECLCALLBACK(int) drvHostValKitTestSetSendBeginCallback(void const *pvUser, const char *pszTag)
452{
453 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
454
455 int rc = RTCritSectEnter(&pThis->CritSect);
456 if (RT_SUCCESS(rc))
457 {
458 if (RTFileExists(pThis->szTestSetArchive)) /* Has the archive successfully been created yet? */
459 {
460 rc = RTFileOpen(&pThis->hTestSetArchive, pThis->szTestSetArchive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
461 if (RT_SUCCESS(rc))
462 {
463 uint64_t uSize;
464 rc = RTFileQuerySize(pThis->hTestSetArchive, &uSize);
465 if (RT_SUCCESS(rc))
466 LogRel(("ValKit: Sending test set '%s' (%zu bytes)\n", pThis->szTestSetArchive, uSize));
467 }
468 }
469 else
470 rc = VERR_FILE_NOT_FOUND;
471
472 int rc2 = RTCritSectLeave(&pThis->CritSect);
473 if (RT_SUCCESS(rc))
474 rc = rc2;
475 }
476
477 if (RT_FAILURE(rc))
478 LogRel(("ValKit: Beginning to send test set '%s' failed with %Rrc\n", pszTag, rc));
479
480 return rc;
481}
482
483/** @copydoc ATSCALLBACKS::pfnTestSetSendRead */
484static DECLCALLBACK(int) drvHostValKitTestSetSendReadCallback(void const *pvUser,
485 const char *pszTag, void *pvBuf, size_t cbBuf, size_t *pcbRead)
486{
487 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
488
489 int rc = RTCritSectEnter(&pThis->CritSect);
490 if (RT_SUCCESS(rc))
491 {
492 if (RTFileIsValid(pThis->hTestSetArchive))
493 {
494 rc = RTFileRead(pThis->hTestSetArchive, pvBuf, cbBuf, pcbRead);
495 }
496 else
497 rc = VERR_WRONG_ORDER;
498
499 int rc2 = RTCritSectLeave(&pThis->CritSect);
500 if (RT_SUCCESS(rc))
501 rc = rc2;
502 }
503
504 if (RT_FAILURE(rc))
505 LogRel(("ValKit: Reading from test set '%s' failed with %Rrc\n", pszTag, rc));
506
507 return rc;
508}
509
510/** @copydoc ATSCALLBACKS::pfnTestSetSendEnd */
511static DECLCALLBACK(int) drvHostValKitTestSetSendEndCallback(void const *pvUser, const char *pszTag)
512{
513 PDRVHOSTVALKITAUDIO pThis = (PDRVHOSTVALKITAUDIO)pvUser;
514
515 int rc = RTCritSectEnter(&pThis->CritSect);
516 if (RT_SUCCESS(rc))
517 {
518 if (RTFileIsValid(pThis->hTestSetArchive))
519 {
520 rc = RTFileClose(pThis->hTestSetArchive);
521 if (RT_SUCCESS(rc))
522 pThis->hTestSetArchive = NIL_RTFILE;
523 }
524
525 int rc2 = RTCritSectLeave(&pThis->CritSect);
526 if (RT_SUCCESS(rc))
527 rc = rc2;
528 }
529
530 if (RT_FAILURE(rc))
531 LogRel(("ValKit: Ending to send test set '%s' failed with %Rrc\n", pszTag, rc));
532
533 return rc;
534}
535
536
537/*********************************************************************************************************************************
538* PDMIHOSTAUDIO interface implementation *
539*********************************************************************************************************************************/
540
541/**
542 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
543 */
544static DECLCALLBACK(int) drvHostValKitAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
545{
546 RT_NOREF(pInterface);
547 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
548
549 /*
550 * Fill in the config structure.
551 */
552 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "Validation Kit");
553 pBackendCfg->cbStream = sizeof(VALKITAUDIOSTREAM);
554 pBackendCfg->fFlags = 0;
555 pBackendCfg->cMaxStreamsOut = 1; /* Output (Playback). */
556 pBackendCfg->cMaxStreamsIn = 1; /* Input (Recording). */
557
558 return VINF_SUCCESS;
559}
560
561
562/**
563 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
564 */
565static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostValKitAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
566{
567 RT_NOREF(enmDir);
568 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
569
570 return PDMAUDIOBACKENDSTS_RUNNING;
571}
572
573
574/**
575 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
576 */
577static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
578 PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
579{
580 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
581 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
582 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
583 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
584 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
585 RT_NOREF(pThis);
586
587 int rc = VINF_SUCCESS;
588 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
589 return rc;
590}
591
592/**
593 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
594 */
595static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
596 bool fImmediate)
597{
598 RT_NOREF(pInterface, fImmediate);
599 PVALKITAUDIOSTREAM pStreamDbg = (PVALKITAUDIOSTREAM)pStream;
600 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
601
602 return VINF_SUCCESS;
603}
604
605
606/**
607 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
608 */
609static DECLCALLBACK(int) drvHostValKitAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
610{
611 RT_NOREF(pInterface, pStream);
612 return VINF_SUCCESS;
613}
614
615
616/**
617 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
618 */
619static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
620{
621 RT_NOREF(pInterface, pStream);
622 return VINF_SUCCESS;
623}
624
625
626/**
627 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
628 */
629static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
630{
631 RT_NOREF(pInterface, pStream);
632 return VINF_SUCCESS;
633}
634
635
636/**
637 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
638 */
639static DECLCALLBACK(int) drvHostValKitAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
640{
641 RT_NOREF(pInterface, pStream);
642 return VINF_SUCCESS;
643}
644
645
646/**
647 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
648 */
649static DECLCALLBACK(int) drvHostValKitAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
650{
651 RT_NOREF(pStream);
652
653 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
654
655 int rc = RTCritSectEnter(&pThis->CritSect);
656 if (RT_SUCCESS(rc))
657 {
658 PVALKITTESTDATA pTst = pThis->pTestCurPlay;
659
660 if (pTst)
661 {
662 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
663 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
664
665 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
666 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
667 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
668
669 AudioTestSetTestDone(pTst->pEntry);
670
671 pThis->pTestCurPlay = NULL;
672 pTst = NULL;
673
674 if (ASMAtomicReadBool(&pThis->fTestSetEnd))
675 rc = RTSemEventSignal(pThis->EventSemEnded);
676 }
677
678 int rc2 = RTCritSectLeave(&pThis->CritSect);
679 AssertRC(rc2);
680 }
681
682 return VINF_SUCCESS;
683}
684
685
686/**
687 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
688 */
689static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
690{
691 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
692 PVALKITAUDIOSTREAM pStrmValKit = (PVALKITAUDIOSTREAM)pStream;
693 PVALKITTESTDATA pTst = NULL;
694
695 int rc = RTCritSectEnter(&pThis->CritSect);
696 if (RT_SUCCESS(rc))
697 {
698 if (pThis->pTestCurRec == NULL)
699 {
700 pThis->pTestCurRec = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
701 if (pThis->pTestCurRec)
702 LogRel(("ValKit: Next guest recording test in queue is test #%RU32\n", pThis->pTestCurRec->idxTest));
703 }
704
705 pTst = pThis->pTestCurRec;
706
707 int rc2 = RTCritSectLeave(&pThis->CritSect);
708 AssertRC(rc2);
709 }
710
711 if ( pTst
712 && pTst->pEntry == NULL) /* Test not started yet? */
713 {
714 AUDIOTESTPARMS Parms;
715 RT_ZERO(Parms);
716 Parms.enmDir = PDMAUDIODIR_OUT;
717 Parms.enmType = AUDIOTESTTYPE_TESTTONE_PLAY;
718 Parms.TestTone = pTst->t.TestTone.Parms;
719
720 rc = AudioTestSetTestBegin(&pThis->Set, "Injecting audio input data to guest",
721 &Parms, &pTst->pEntry);
722 if (RT_SUCCESS(rc))
723 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-play.pcm", &pTst->Obj);
724
725 if (RT_SUCCESS(rc))
726 {
727 pTst->msStartedTS = RTTimeMilliTS();
728 LogRel(("ValKit: Injecting audio input data (%RU16Hz, %RU32ms, %RU32 bytes) started\n",
729 (uint16_t)pTst->t.TestTone.Tone.rdFreqHz,
730 pTst->t.TestTone.Parms.msDuration, pTst->t.TestTone.u.Rec.cbToWrite));
731 }
732
733 pStrmValKit->cbAvail += pTst->t.TestTone.u.Rec.cbToWrite;
734 LogRel(("ValKit: Now total of %RU32 bytes available for capturing\n", pStrmValKit->cbAvail));
735 }
736
737 LogRel(("ValKit: Test #%RU32: Reporting %RU32 bytes as available\n",
738 pTst ? pTst->idxTest : 9999, pStrmValKit->cbAvail));
739 return pStrmValKit->cbAvail;
740}
741
742
743/**
744 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
745 */
746static DECLCALLBACK(uint32_t) drvHostValKitAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
747{
748 RT_NOREF(pInterface, pStream);
749 return UINT32_MAX;
750}
751
752
753/**
754 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
755 */
756static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostValKitAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
757 PPDMAUDIOBACKENDSTREAM pStream)
758{
759 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
760
761 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
762 PDMHOSTAUDIOSTREAMSTATE enmState = PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING;
763
764 if (pStream->pStream->Cfg.enmDir == PDMAUDIODIR_IN)
765 {
766 int rc2 = RTCritSectEnter(&pThis->CritSect);
767 if (RT_SUCCESS(rc2))
768 {
769 enmState = pThis->cTestsRec == 0
770 ? PDMHOSTAUDIOSTREAMSTATE_INACTIVE : PDMHOSTAUDIOSTREAMSTATE_OKAY;
771
772 rc2 = RTCritSectLeave(&pThis->CritSect);
773 AssertRC(rc2);
774 }
775 }
776 else
777 enmState = PDMHOSTAUDIOSTREAMSTATE_OKAY;
778
779 return enmState;
780}
781
782
783/**
784 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
785 */
786static DECLCALLBACK(int) drvHostValKitAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
787 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
788{
789 if (cbBuf == 0)
790 {
791 /* Fend off draining calls. */
792 *pcbWritten = 0;
793 return VINF_SUCCESS;
794 }
795
796 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
797 PVALKITTESTDATA pTst = NULL;
798
799 bool const fIsSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBuf, cbBuf);
800
801 int rc = RTCritSectEnter(&pThis->CritSect);
802 if (RT_SUCCESS(rc))
803 {
804 if (pThis->pTestCurPlay == NULL)
805 {
806 pThis->pTestCurPlay = RTListGetFirst(&pThis->lstTestsPlay, VALKITTESTDATA, Node);
807 if (pThis->pTestCurPlay)
808 LogRel(("ValKit: Next guest playback test in queue is test #%RU32\n", pThis->pTestCurPlay->idxTest));
809 }
810
811 pTst = pThis->pTestCurPlay;
812
813 int rc2 = RTCritSectLeave(&pThis->CritSect);
814 AssertRC(rc2);
815 }
816
817 if (pTst == NULL) /* Empty list? */
818 {
819#ifdef DEBUG_andy
820 if (!fIsSilence)
821#endif
822 LogRel(("ValKit: Warning: Guest is playing back audio (%s, %RU32 bytes, %RU64ms) when no playback test is active\n",
823 fIsSilence ? "silence" : "audible", cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
824
825 *pcbWritten = cbBuf;
826 return VINF_SUCCESS;
827 }
828
829#ifndef DEBUG_andy
830 if (fIsSilence)
831 LogRel2(("ValKit: Guest is playing back %RU32 bytes (%RU64ms) silence\n",
832 cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf)));
833#endif
834
835 const bool fHandleSilence = false; /** @todo Skip blocks of entire silence for now. */
836
837 if (pTst->pEntry == NULL) /* Test not started yet? */
838 {
839 AUDIOTESTPARMS Parms;
840 RT_ZERO(Parms);
841 Parms.enmDir = PDMAUDIODIR_IN;
842 Parms.enmType = AUDIOTESTTYPE_TESTTONE_RECORD;
843 Parms.TestTone = pTst->t.TestTone.Parms;
844
845 rc = AudioTestSetTestBegin(&pThis->Set, "Recording audio data from guest",
846 &Parms, &pTst->pEntry);
847 if (RT_SUCCESS(rc))
848 rc = AudioTestSetObjCreateAndRegister(&pThis->Set, "host-tone-rec.pcm", &pTst->Obj);
849
850 if (RT_SUCCESS(rc))
851 {
852 pTst->msStartedTS = RTTimeMilliTS();
853 LogRel(("ValKit: Test #%RU32: Recording audio data (%RU16Hz, %RU32ms) started\n",
854 pTst->idxTest, (uint16_t)Parms.TestTone.dbFreqHz, Parms.TestTone.msDuration));
855 }
856 }
857
858 uint32_t cbWritten = 0;
859
860 if (RT_SUCCESS(rc))
861 {
862 if ( !fIsSilence
863 || (fIsSilence && fHandleSilence))
864 {
865 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbBuf);
866 pTst->t.TestTone.u.Play.cbRead += cbBuf;
867
868 const bool fComplete = pTst->t.TestTone.u.Play.cbRead >= pTst->t.TestTone.u.Play.cbToRead;
869 if (fComplete)
870 {
871 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
872 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
873
874 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
875 LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
876 pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
877
878 AudioTestSetTestDone(pTst->pEntry);
879
880 rc = RTCritSectEnter(&pThis->CritSect);
881 if (RT_SUCCESS(rc))
882 {
883 drvHostValKiUnregisterPlayTest(pThis, pTst);
884
885 pThis->pTestCurPlay = NULL;
886 pTst = NULL;
887
888 int rc2 = RTCritSectLeave(&pThis->CritSect);
889 if (RT_SUCCESS(rc))
890 rc = rc2;
891 }
892 }
893 }
894
895 /* Always report everything as being played. */
896 cbWritten = cbBuf;
897 }
898
899 if (RT_FAILURE(rc))
900 {
901 if ( pTst
902 && pTst->pEntry)
903 AudioTestSetTestFailed(pTst->pEntry, rc, "Recording audio data failed");
904 LogRel(("ValKit: Recording audio data failed with %Rrc\n", rc));
905 }
906
907 *pcbWritten = cbWritten;
908
909 return VINF_SUCCESS; /** @todo Return rc here? */
910}
911
912
913/**
914 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
915 */
916static DECLCALLBACK(int) drvHostValKitAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
917 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
918{
919 RT_NOREF(pStream);
920
921 if (cbBuf == 0)
922 {
923 /* Fend off draining calls. */
924 *pcbRead = 0;
925 return VINF_SUCCESS;
926 }
927
928 PDRVHOSTVALKITAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTVALKITAUDIO, IHostAudio);
929 PVALKITAUDIOSTREAM pStrmValKit = (PVALKITAUDIOSTREAM)pStream;
930 PVALKITTESTDATA pTst = NULL;
931
932 int rc = RTCritSectEnter(&pThis->CritSect);
933 if (RT_SUCCESS(rc))
934 {
935 if (pThis->pTestCurRec == NULL)
936 {
937 pThis->pTestCurRec = RTListGetFirst(&pThis->lstTestsRec, VALKITTESTDATA, Node);
938 if (pThis->pTestCurRec)
939 LogRel(("ValKit: Next guest recording test in queue is test #%RU32\n", pThis->pTestCurRec->idxTest));
940 }
941
942 pTst = pThis->pTestCurRec;
943
944 int rc2 = RTCritSectLeave(&pThis->CritSect);
945 AssertRC(rc2);
946 }
947
948 if (pTst == NULL) /* Empty list? */
949 {
950 LogRel(("ValKit: Warning: Guest is trying to record %RU32 bytes (%RU32ms) of audio data when no recording test is active (%RU32 bytes available)\n",
951 cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf), pStrmValKit->cbAvail));
952
953 /** @todo Not sure yet why this happens after all data has been captured sometimes,
954 * but the guest side just will record silence and the audio test verification
955 * will have to deal with (and/or report) it then. */
956 PDMAudioPropsClearBuffer(&pStream->pStream->Cfg.Props, pvBuf, cbBuf,
957 PDMAudioPropsBytesToFrames(&pStream->pStream->Cfg.Props, cbBuf));
958
959 *pcbRead = cbBuf; /* Just report back stuff as being "recorded" (silence). */
960 return VINF_SUCCESS;
961 }
962
963 uint32_t cbRead = 0;
964
965 if (RT_SUCCESS(rc))
966 {
967 uint32_t cbToWrite = RT_MIN(cbBuf,
968 pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten);
969 if (cbToWrite)
970 rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, cbToWrite, &cbRead);
971 if ( RT_SUCCESS(rc)
972 && cbRead)
973 {
974 Assert(cbRead == cbToWrite);
975
976 if (cbRead > pStrmValKit->cbAvail)
977 LogRel(("ValKit: Warning: Test #%RU32: Reading more from capturing stream than availabe for (%RU32 vs. %RU32)\n",
978 pTst->idxTest, cbRead, pStrmValKit->cbAvail));
979
980 pStrmValKit->cbAvail -= RT_MIN(pStrmValKit->cbAvail, cbRead);
981
982 rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbRead);
983 if (RT_SUCCESS(rc))
984 {
985 pTst->t.TestTone.u.Rec.cbWritten += cbRead;
986 Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
987
988 LogRel(("ValKit: Test #%RU32: Read %RU32 bytes of (capturing) audio data (%RU32 bytes left)\n",
989 pTst->idxTest, cbRead, pStrmValKit->cbAvail));
990
991 const bool fComplete = pTst->t.TestTone.u.Rec.cbWritten >= pTst->t.TestTone.u.Rec.cbToWrite;
992 if (fComplete)
993 {
994 LogRel(("ValKit: Test #%RU32: Recording done (took %RU32ms)\n",
995 pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
996
997 AudioTestSetTestDone(pTst->pEntry);
998
999 rc = RTCritSectEnter(&pThis->CritSect);
1000 if (RT_SUCCESS(rc))
1001 {
1002 drvHostValKiUnregisterRecTest(pThis, pTst);
1003
1004 pThis->pTestCurRec = NULL;
1005 pTst = NULL;
1006
1007 int rc2 = RTCritSectLeave(&pThis->CritSect);
1008 AssertRC(rc2);
1009 }
1010 }
1011 }
1012 }
1013 }
1014
1015 if (ASMAtomicReadBool(&pThis->fTestSetEnd))
1016 {
1017 int rc2 = RTSemEventSignal(pThis->EventSemEnded);
1018 AssertRC(rc2);
1019 }
1020
1021 if (RT_FAILURE(rc))
1022 {
1023 if (pTst->pEntry)
1024 AudioTestSetTestFailed(pTst->pEntry, rc, "Injecting audio input data failed");
1025 LogRel(("ValKit: Test #%RU32: Failed with %Rrc\n", pTst->idxTest, rc));
1026 }
1027
1028 *pcbRead = cbRead;
1029
1030 return VINF_SUCCESS; /** @todo Return rc here? */
1031}
1032
1033
1034/**
1035 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1036 */
1037static DECLCALLBACK(void *) drvHostValKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1038{
1039 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1040 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1041
1042 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1043 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
1044 return NULL;
1045}
1046
1047
1048/**
1049 * Constructs a VaKit audio driver instance.
1050 *
1051 * @copydoc FNPDMDRVCONSTRUCT
1052 */
1053static DECLCALLBACK(int) drvHostValKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1054{
1055 RT_NOREF(pCfg, fFlags);
1056 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1057 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1058 LogRel(("Audio: Initializing VALKIT driver\n"));
1059
1060 /*
1061 * Init the static parts.
1062 */
1063 pThis->pDrvIns = pDrvIns;
1064 /* IBase */
1065 pDrvIns->IBase.pfnQueryInterface = drvHostValKitAudioQueryInterface;
1066 /* IHostAudio */
1067 pThis->IHostAudio.pfnGetConfig = drvHostValKitAudioHA_GetConfig;
1068 pThis->IHostAudio.pfnGetDevices = NULL;
1069 pThis->IHostAudio.pfnGetStatus = drvHostValKitAudioHA_GetStatus;
1070 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
1071 pThis->IHostAudio.pfnStreamConfigHint = NULL;
1072 pThis->IHostAudio.pfnStreamCreate = drvHostValKitAudioHA_StreamCreate;
1073 pThis->IHostAudio.pfnStreamInitAsync = NULL;
1074 pThis->IHostAudio.pfnStreamDestroy = drvHostValKitAudioHA_StreamDestroy;
1075 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
1076 pThis->IHostAudio.pfnStreamEnable = drvHostValKitAudioHA_StreamEnable;
1077 pThis->IHostAudio.pfnStreamDisable = drvHostValKitAudioHA_StreamDisable;
1078 pThis->IHostAudio.pfnStreamPause = drvHostValKitAudioHA_StreamPause;
1079 pThis->IHostAudio.pfnStreamResume = drvHostValKitAudioHA_StreamResume;
1080 pThis->IHostAudio.pfnStreamDrain = drvHostValKitAudioHA_StreamDrain;
1081 pThis->IHostAudio.pfnStreamGetReadable = drvHostValKitAudioHA_StreamGetReadable;
1082 pThis->IHostAudio.pfnStreamGetWritable = drvHostValKitAudioHA_StreamGetWritable;
1083 pThis->IHostAudio.pfnStreamGetPending = NULL;
1084 pThis->IHostAudio.pfnStreamGetState = drvHostValKitAudioHA_StreamGetState;
1085 pThis->IHostAudio.pfnStreamPlay = drvHostValKitAudioHA_StreamPlay;
1086 pThis->IHostAudio.pfnStreamCapture = drvHostValKitAudioHA_StreamCapture;
1087
1088 int rc = RTCritSectInit(&pThis->CritSect);
1089 AssertRCReturn(rc, rc);
1090 rc = RTSemEventCreate(&pThis->EventSemEnded);
1091 AssertRCReturn(rc, rc);
1092
1093 pThis->fTestSetEnd = false;
1094
1095 RTListInit(&pThis->lstTestsRec);
1096 pThis->cTestsRec = 0;
1097 RTListInit(&pThis->lstTestsPlay);
1098 pThis->cTestsPlay = 0;
1099
1100 ATSCALLBACKS Callbacks;
1101 RT_ZERO(Callbacks);
1102 Callbacks.pfnTestSetBegin = drvHostValKitTestSetBegin;
1103 Callbacks.pfnTestSetEnd = drvHostValKitTestSetEnd;
1104 Callbacks.pfnTonePlay = drvHostValKitRegisterGuestRecTest;
1105 Callbacks.pfnToneRecord = drvHostValKitRegisterGuestPlayTest;
1106 Callbacks.pfnTestSetSendBegin = drvHostValKitTestSetSendBeginCallback;
1107 Callbacks.pfnTestSetSendRead = drvHostValKitTestSetSendReadCallback;
1108 Callbacks.pfnTestSetSendEnd = drvHostValKitTestSetSendEndCallback;
1109 Callbacks.pvUser = pThis;
1110
1111 /** @todo Make this configurable via CFGM. */
1112 const char *pszTcpAddr = "127.0.0.1"; /* Only reachable for localhost for now. */
1113 uint32_t uTcpPort = ATS_TCP_DEF_BIND_PORT_VALKIT;
1114
1115 LogRel(("ValKit: Starting Audio Test Service (ATS) at %s:%RU32...\n",
1116 pszTcpAddr, uTcpPort));
1117
1118 /* Dont' use rc here, as this will be reported back to PDM and will prevent VBox
1119 * from starting -- not critical but warn the user though. */
1120 int rc2 = AudioTestSvcInit(&pThis->Srv, &Callbacks);
1121 if (RT_SUCCESS(rc2))
1122 {
1123 RTGETOPTUNION Val;
1124 RT_ZERO(Val);
1125
1126 Val.u32 = ATSCONNMODE_SERVER; /** @todo No client connection mode needed here (yet). Make this configurable via CFGM. */
1127 rc2 = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_CONN_MODE, &Val);
1128 AssertRC(rc2);
1129
1130 Val.psz = pszTcpAddr;
1131 rc2 = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_ADDRESS, &Val);
1132 AssertRC(rc2);
1133
1134 Val.u16 = uTcpPort;
1135 rc2 = AudioTestSvcHandleOption(&pThis->Srv, ATSTCPOPT_BIND_PORT, &Val);
1136 AssertRC(rc2);
1137
1138 rc2 = AudioTestSvcStart(&pThis->Srv);
1139 }
1140
1141 if (RT_SUCCESS(rc2))
1142 {
1143 LogRel(("ValKit: Audio Test Service (ATS) running\n"));
1144
1145 /** @todo Let the following be customizable by CFGM later. */
1146 rc2 = AudioTestPathCreateTemp(pThis->szPathTemp, sizeof(pThis->szPathTemp), "ValKitAudio");
1147 if (RT_SUCCESS(rc2))
1148 {
1149 LogRel(("ValKit: Using temp dir '%s'\n", pThis->szPathTemp));
1150 rc2 = AudioTestPathGetTemp(pThis->szPathOut, sizeof(pThis->szPathOut));
1151 if (RT_SUCCESS(rc2))
1152 LogRel(("ValKit: Using output dir '%s'\n", pThis->szPathOut));
1153 }
1154 }
1155
1156 if (RT_FAILURE(rc2))
1157 LogRel(("ValKit: Error starting Audio Test Service (ATS), rc=%Rrc -- tests *will* fail!\n", rc2));
1158
1159 if (RT_FAILURE(rc)) /* This one *is* critical though. */
1160 LogRel(("ValKit: Initialization failed, rc=%Rrc\n", rc));
1161
1162 return rc;
1163}
1164
1165static DECLCALLBACK(void) drvHostValKitAudioDestruct(PPDMDRVINS pDrvIns)
1166{
1167 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1168 PDRVHOSTVALKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVALKITAUDIO);
1169
1170 LogRel(("ValKit: Shutting down Audio Test Service (ATS) ...\n"));
1171
1172 int rc = AudioTestSvcStop(&pThis->Srv);
1173 if (RT_SUCCESS(rc))
1174 rc = AudioTestSvcDestroy(&pThis->Srv);
1175
1176 if (RT_SUCCESS(rc))
1177 {
1178 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) complete\n"));
1179 drvHostValKitCleanup(pThis);
1180 }
1181 else
1182 LogRel(("ValKit: Shutdown of Audio Test Service (ATS) failed, rc=%Rrc\n", rc));
1183
1184 /* Try cleaning up a bit. */
1185 RTDirRemove(pThis->szPathTemp);
1186 RTDirRemove(pThis->szPathOut);
1187
1188 RTSemEventDestroy(pThis->EventSemEnded);
1189
1190 if (RTCritSectIsInitialized(&pThis->CritSect))
1191 {
1192 int rc2 = RTCritSectDelete(&pThis->CritSect);
1193 if (RT_SUCCESS(rc))
1194 rc = rc2;
1195 }
1196
1197 if (RT_FAILURE(rc))
1198 LogRel(("ValKit: Destruction failed, rc=%Rrc\n", rc));
1199}
1200
1201/**
1202 * Char driver registration record.
1203 */
1204const PDMDRVREG g_DrvHostValidationKitAudio =
1205{
1206 /* u32Version */
1207 PDM_DRVREG_VERSION,
1208 /* szName */
1209 "ValidationKitAudio",
1210 /* szRCMod */
1211 "",
1212 /* szR0Mod */
1213 "",
1214 /* pszDescription */
1215 "ValidationKitAudio audio host driver",
1216 /* fFlags */
1217 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1218 /* fClass. */
1219 PDM_DRVREG_CLASS_AUDIO,
1220 /* cMaxInstances */
1221 ~0U,
1222 /* cbInstance */
1223 sizeof(DRVHOSTVALKITAUDIO),
1224 /* pfnConstruct */
1225 drvHostValKitAudioConstruct,
1226 /* pfnDestruct */
1227 drvHostValKitAudioDestruct,
1228 /* pfnRelocate */
1229 NULL,
1230 /* pfnIOCtl */
1231 NULL,
1232 /* pfnPowerOn */
1233 NULL,
1234 /* pfnReset */
1235 NULL,
1236 /* pfnSuspend */
1237 NULL,
1238 /* pfnResume */
1239 NULL,
1240 /* pfnAttach */
1241 NULL,
1242 /* pfnDetach */
1243 NULL,
1244 /* pfnPowerOff */
1245 NULL,
1246 /* pfnSoftReset */
1247 NULL,
1248 /* u32EndVersion */
1249 PDM_DRVREG_VERSION
1250};
1251
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