Changeset 65670 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Feb 7, 2017 5:31:30 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostValidationKit.cpp
r65624 r65670 1 /* $Id$ */2 1 /** @file 3 * Validation Kit audio driver. 2 * VaKit audio driver -- host backend for dumping and injecting audio data 3 * from/to the device emulation. 4 4 */ 5 5 … … 29 29 30 30 /** 31 * Structure for keeping a debuginput/output stream.31 * Structure for keeping a VAKIT input/output stream. 32 32 */ 33 33 typedef struct VAKITAUDIOSTREAM 34 34 { 35 35 /** The stream's acquired configuration. */ 36 P DMAUDIOSTREAMCFGCfg;36 PPDMAUDIOSTREAMCFG pCfg; 37 37 /** Audio file to dump output to or read input from. */ 38 38 PDMAUDIOFILE File; … … 54 54 /** Timestamp of last played samples. */ 55 55 uint64_t tsLastPlayed; 56 uint64_t cMaxSamplesInPlayBuffer;57 56 uint8_t *pu8PlayBuffer; 57 uint32_t cbPlayBuffer; 58 58 } Out; 59 59 }; 60 61 60 } VAKITAUDIOSTREAM, *PVAKITAUDIOSTREAM; 62 61 63 62 /** 64 * V alidation Kitaudio driver instance data.63 * VAKIT audio driver instance data. 65 64 * @implements PDMIAUDIOCONNECTOR 66 65 */ … … 81 80 static DECLCALLBACK(int) drvHostVaKitAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) 82 81 { 83 NOREF(pInterface);82 RT_NOREF(pInterface); 84 83 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER); 85 84 … … 99 98 static DECLCALLBACK(int) drvHostVaKitAudioInit(PPDMIHOSTAUDIO pInterface) 100 99 { 101 NOREF(pInterface);102 100 RT_NOREF(pInterface); 101 103 102 LogFlowFuncLeaveRC(VINF_SUCCESS); 104 103 return VINF_SUCCESS; … … 111 110 static DECLCALLBACK(void) drvHostVaKitAudioShutdown(PPDMIHOSTAUDIO pInterface) 112 111 { 113 NOREF(pInterface);112 RT_NOREF(pInterface); 114 113 } 115 114 … … 127 126 128 127 129 static int debugCreateStreamIn(PPDMIHOSTAUDIO pInterface, 130 PPDMAUDIOBACKENDSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 131 { 132 RT_NOREF(pInterface, pStream); 133 134 /* Just adopt the wanted stream configuration. */ 135 PDMAUDIOPCMPROPS Props; 136 int rc = DrvAudioHlpStreamCfgDup(pCfgReq, &Props); 137 if (RT_SUCCESS(rc)) 138 { 139 if (pCfgAcq) 140 pCfgAcq->cSampleBufferHint = _1K; 141 } 142 143 LogFlowFuncLeaveRC(rc); 144 return rc; 145 } 146 147 148 static int debugCreateStreamOut(PPDMIHOSTAUDIO pInterface, 149 PPDMAUDIOBACKENDSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 150 { 151 NOREF(pInterface); 152 153 PVAKITAUDIOSTREAM pDbgStream = (PVAKITAUDIOSTREAM)pStream; 154 155 /* Just adopt the wanted stream configuration. */ 156 PDMAUDIOPCMPROPS Props; 157 int rc = DrvAudioHlpStreamCfgDup(pCfgReq, &Props); 158 if (RT_SUCCESS(rc)) 159 { 160 pDbgStream->tsStarted = 0; 161 pDbgStream->uSamplesSinceStarted = 0; 162 pDbgStream->Out.tsLastPlayed = 0; 163 pDbgStream->Out.cMaxSamplesInPlayBuffer = 16 * _1K; 164 pDbgStream->Out.pu8PlayBuffer = (uint8_t *)RTMemAlloc(pDbgStream->Out.cMaxSamplesInPlayBuffer << Props.cShift); 165 if (!pDbgStream->Out.pu8PlayBuffer) 166 rc = VERR_NO_MEMORY; 167 } 128 static int debugCreateStreamIn(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg, 129 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 130 { 131 RT_NOREF(pDrv, pStreamDbg, pCfgReq); 132 133 if (pCfgAcq) 134 pCfgAcq->cSampleBufferHint = _1K; 135 136 return VINF_SUCCESS; 137 } 138 139 140 static int debugCreateStreamOut(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg, 141 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 142 { 143 RT_NOREF(pDrv); 144 145 int rc = VINF_SUCCESS; 146 147 pStreamDbg->tsStarted = 0; 148 pStreamDbg->uSamplesSinceStarted = 0; 149 pStreamDbg->Out.tsLastPlayed = 0; 150 pStreamDbg->Out.cbPlayBuffer = 16 * _1K * PDMAUDIOSTREAMCFG_S2B(pCfgReq, 1); /** @todo Make this configurable? */ 151 pStreamDbg->Out.pu8PlayBuffer = (uint8_t *)RTMemAlloc(pStreamDbg->Out.cbPlayBuffer); 152 if (!pStreamDbg->Out.pu8PlayBuffer) 153 rc = VERR_NO_MEMORY; 168 154 169 155 if (RT_SUCCESS(rc)) … … 181 167 { 182 168 LogFlowFunc(("%s\n", szFile)); 183 rc = DrvAudioHlpWAVFileOpen(&p DbgStream->File, szFile,169 rc = DrvAudioHlpWAVFileOpen(&pStreamDbg->File, szFile, 184 170 RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE, 185 & Props, PDMAUDIOFILEFLAG_NONE);171 &pCfgReq->Props, PDMAUDIOFILEFLAG_NONE); 186 172 if (RT_FAILURE(rc)) 187 LogRel((" DebugAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));173 LogRel(("VaKitAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc)); 188 174 189 175 RTStrCat(szFile, sizeof(szFile), ".timing"); 190 rc = RTFileOpen(&pDbgStream->hFileTiming, szFile, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE); 191 176 rc = RTFileOpen(&pStreamDbg->hFileTiming, szFile, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE); 192 177 193 178 if (RT_FAILURE(rc)) 194 LogRel((" DebugAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));179 LogRel(("VaKitAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc)); 195 180 } 196 181 else 197 LogRel((" DebugAudio: Unable to build file name for temp dir '%s': %Rrc\n", szTemp, rc));182 LogRel(("VaKitAudio: Unable to build file name for temp dir '%s': %Rrc\n", szTemp, rc)); 198 183 } 199 184 else 200 LogRel((" DebugAudio: Unable to retrieve temp dir: %Rrc\n", rc));185 LogRel(("VaKitAudio: Unable to retrieve temp dir: %Rrc\n", rc)); 201 186 } 202 187 … … 204 189 { 205 190 if (pCfgAcq) 206 pCfgAcq->cSampleBufferHint = pDbgStream->Out.cMaxSamplesInPlayBuffer; 207 } 208 209 LogFlowFuncLeaveRC(rc); 191 pCfgAcq->cSampleBufferHint = PDMAUDIOSTREAMCFG_B2S(pCfgAcq, pStreamDbg->Out.cbPlayBuffer); 192 } 193 210 194 return rc; 211 195 } … … 222 206 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 223 207 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 208 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 209 210 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio); 211 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream; 224 212 225 213 int rc; 226 214 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 227 rc = debugCreateStreamIn( p Interface, pStream, pCfgReq, pCfgAcq);215 rc = debugCreateStreamIn( pDrv, pStreamDbg, pCfgReq, pCfgAcq); 228 216 else 229 rc = debugCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq); 230 231 LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc)); 217 rc = debugCreateStreamOut(pDrv, pStreamDbg, pCfgReq, pCfgAcq); 218 219 if (RT_SUCCESS(rc)) 220 { 221 pStreamDbg->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq); 222 if (!pStreamDbg->pCfg) 223 rc = VERR_NO_MEMORY; 224 } 225 232 226 return rc; 233 227 } … … 241 235 uint32_t *pcbWritten) 242 236 { 243 RT_NOREF(pvBuf, cbBuf);244 245 237 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio); 246 PVAKITAUDIOSTREAM pDbgStream = (PVAKITAUDIOSTREAM)pStream; 247 248 /* Consume as many samples as would be played at the current frequency since last call. */ 249 /*uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);*/ 250 251 uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns); 252 // uint64_t u64TicksElapsed = u64TicksNow - pDbgStream->Out.tsLastPlayed; 253 // uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns); 254 255 /* 256 * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5). 257 * If rounding is not taken into account then the playback rate will be consistently lower that expected. 258 */ 259 // uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2; 260 261 /* Don't play more than available. */ 262 /*if (cSamplesPlayed > cLive) 263 cSamplesPlayed = cLive;*/ 238 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream; 239 RT_NOREF(pDrv); 264 240 265 241 uint64_t tsSinceStart; … … 267 243 char szTimingInfo[128]; 268 244 269 if (p DbgStream->tsStarted == 0)270 { 271 p DbgStream->tsStarted = RTTimeNanoTS();245 if (pStreamDbg->tsStarted == 0) 246 { 247 pStreamDbg->tsStarted = RTTimeNanoTS(); 272 248 tsSinceStart = 0; 273 249 } 274 250 else 275 251 { 276 tsSinceStart = RTTimeNanoTS() - pDbgStream->tsStarted; 277 } 278 279 uint32_t uSamplesReady = AudioMixBufUsed(&pStream->MixBuf); 280 cch = RTStrPrintf(szTimingInfo, sizeof(szTimingInfo), "%d %d %d %d\n", 281 // Host time (in mcs) elapsed since Guest submitted the first buffer for playback 282 (uint32_t)(tsSinceStart / 1000), 283 // how long (in mcs) all the samples submitted previously were played 284 (uint32_t)(pDbgStream->uSamplesSinceStarted * 1.0E6 / pStream->Cfg.uHz), 285 // how long (in mcs) a new uSamplesReady samples should\will be played 286 (uint32_t)(uSamplesReady * 1.0E6 / pStream->Cfg.uHz), 287 uSamplesReady); 288 RTFileWrite(pDbgStream->hFileTiming, szTimingInfo, cch, NULL); 289 pDbgStream->uSamplesSinceStarted += uSamplesReady; 290 291 uint32_t cSamplesPlayed = 0; 292 uint32_t cSamplesAvail = RT_MIN(AudioMixBufUsed(&pStream->MixBuf), pDbgStream->Out.cMaxSamplesInPlayBuffer); 293 294 while (cSamplesAvail) 295 { 296 uint32_t cSamplesRead = 0; 297 int rc2 = AudioMixBufReadCirc(&pStream->MixBuf, pDbgStream->Out.pu8PlayBuffer, 298 AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesAvail), &cSamplesRead); 299 300 if (RT_FAILURE(rc2)) 301 LogRel(("DebugAudio: Reading output failed with %Rrc\n", rc2)); 302 303 if (!cSamplesRead) 304 break; 305 #if 0 306 RTFILE fh; 307 RTFileOpen(&fh, "/tmp/AudioDebug-Output.pcm", 308 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 309 RTFileWrite(fh, pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead), NULL); 310 RTFileClose(fh); 311 #endif 312 rc2 = DrvAudioHlpWAVFileWrite(&pDbgStream->File, 313 pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead), 314 0 /* fFlags */); 315 if (RT_FAILURE(rc2)) 316 LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc2)); 317 318 AudioMixBufFinish(&pStream->MixBuf, cSamplesRead); 319 320 Assert(cSamplesAvail >= cSamplesRead); 321 cSamplesAvail -= cSamplesRead; 322 323 cSamplesPlayed += cSamplesRead; 324 } 252 tsSinceStart = RTTimeNanoTS() - pStreamDbg->tsStarted; 253 } 254 255 // Microseconds are used everythere below 256 uint32_t sBuf = cbBuf >> pStreamDbg->pCfg->Props.cShift; 257 cch = RTStrPrintf(szTimingInfo, sizeof(szTimingInfo), "%d %d %d %d\n", 258 (uint32_t)(tsSinceStart / 1000), // Host time elapsed since Guest submitted the first buffer for playback 259 (uint32_t)(pStreamDbg->uSamplesSinceStarted * 1.0E6 / pStreamDbg->pCfg->Props.uHz), // how long all the samples submitted previously were played 260 (uint32_t)(sBuf * 1.0E6 / pStreamDbg->pCfg->Props.uHz), // how long a new uSamplesReady samples should\will be played 261 sBuf); 262 RTFileWrite(pStreamDbg->hFileTiming, szTimingInfo, cch, NULL); 263 pStreamDbg->uSamplesSinceStarted += sBuf; 325 264 326 265 /* Remember when samples were consumed. */ 327 pDbgStream->Out.tsLastPlayed = u64TicksNow; 328 329 if (pcbWritten) 330 *pcbWritten = cSamplesPlayed; 266 // pStreamDbg->Out.tsLastPlayed = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);; 267 268 int rc2 = DrvAudioHlpWAVFileWrite(&pStreamDbg->File, pvBuf, cbBuf, 0 /* fFlags */); 269 if (RT_FAILURE(rc2)) 270 LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc2)); 271 272 *pcbWritten = cbBuf; 331 273 332 274 return VINF_SUCCESS; … … 350 292 351 293 352 static int debugDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 353 { 354 RT_NOREF(pInterface, pStream); 355 LogFlowFuncLeaveRC(VINF_SUCCESS); 356 return VINF_SUCCESS; 357 } 358 359 360 static int debugDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 361 { 362 RT_NOREF(pInterface); 363 PVAKITAUDIOSTREAM pDbgStream = (PVAKITAUDIOSTREAM)pStream; 364 if ( pDbgStream 365 && pDbgStream->Out.pu8PlayBuffer) 366 { 367 RTMemFree(pDbgStream->Out.pu8PlayBuffer); 368 pDbgStream->Out.pu8PlayBuffer = NULL; 369 } 370 371 size_t cbDataSize = DrvAudioHlpWAVFileGetDataSize(&pDbgStream->File); 372 373 int rc = DrvAudioHlpWAVFileClose(&pDbgStream->File); 374 375 RTFileClose(pDbgStream->hFileTiming); 376 294 static int debugDestroyStreamIn(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg) 295 { 296 RT_NOREF(pDrv, pStreamDbg); 297 return VINF_SUCCESS; 298 } 299 300 301 static int debugDestroyStreamOut(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg) 302 { 303 RT_NOREF(pDrv); 304 305 if (pStreamDbg->Out.pu8PlayBuffer) 306 { 307 RTMemFree(pStreamDbg->Out.pu8PlayBuffer); 308 pStreamDbg->Out.pu8PlayBuffer = NULL; 309 } 310 311 size_t cbDataSize = DrvAudioHlpWAVFileGetDataSize(&pStreamDbg->File); 312 313 int rc = DrvAudioHlpWAVFileClose(&pStreamDbg->File); 377 314 if (RT_SUCCESS(rc)) 378 315 { … … 385 322 char szFile[RTPATH_MAX]; 386 323 387 RTStrCopy(szFile, sizeof(szFile), p DbgStream->File.szName);324 RTStrCopy(szFile, sizeof(szFile), pStreamDbg->File.szName); 388 325 rc = RTFileDelete(szFile); 389 326 390 327 RTStrCat(szFile, sizeof(szFile), ".timing"); 391 328 rc = RTFileDelete(szFile); 329 392 330 } 393 331 else 394 LogRel(("DebugAudio: Created output file '%s' (%zu bytes)\n", pDbgStream->File.szName, cbDataSize)); 395 } 396 397 LogFlowFuncLeaveRC(rc); 332 LogRel(("VaKitAudio: Created output file '%s' (%zu bytes)\n", pStreamDbg->File.szName, cbDataSize)); 333 } 334 398 335 return rc; 399 336 } … … 402 339 static DECLCALLBACK(int) drvHostVaKitAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 403 340 { 341 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 342 343 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio); 344 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream; 345 346 if (!pStreamDbg->pCfg) /* Not (yet) configured? Skip. */ 347 return VINF_SUCCESS; 348 349 int rc; 350 if (pStreamDbg->pCfg->enmDir == PDMAUDIODIR_IN) 351 rc = debugDestroyStreamIn (pDrv, pStreamDbg); 352 else 353 rc = debugDestroyStreamOut(pDrv, pStreamDbg); 354 355 if (RT_SUCCESS(rc)) 356 { 357 DrvAudioHlpStreamCfgFree(pStreamDbg->pCfg); 358 pStreamDbg->pCfg = NULL; 359 } 360 361 return rc; 362 } 363 364 static DECLCALLBACK(int) drvHostVaKitAudioStreamControl(PPDMIHOSTAUDIO pInterface, 365 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) 366 { 367 RT_NOREF(enmStreamCmd); 404 368 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 405 369 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 406 370 407 int rc;408 if (pStream->enmDir == PDMAUDIODIR_IN)409 rc = debugDestroyStreamIn(pInterface, pStream);410 else411 rc = debugDestroyStreamOut(pInterface, pStream);412 413 return rc;414 }415 416 static DECLCALLBACK(int) drvHostVaKitAudioStreamControl(PPDMIHOSTAUDIO pInterface,417 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)418 {419 RT_NOREF(enmStreamCmd);420 421 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);422 AssertPtrReturn(pStream, VERR_INVALID_POINTER);423 424 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);425 426 371 return VINF_SUCCESS; 427 372 } … … 429 374 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostVaKitAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 430 375 { 431 NOREF(pInterface); 432 NOREF(pStream); 376 RT_NOREF(pInterface, pStream); 433 377 434 378 return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED … … 438 382 static DECLCALLBACK(int) drvHostVaKitAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 439 383 { 440 NOREF(pInterface); 441 NOREF(pStream); 442 384 RT_NOREF(pInterface, pStream); 443 385 return VINF_SUCCESS; 444 386 } … … 460 402 461 403 /** 462 * Constructs a Nullaudio driver instance.404 * Constructs a VaKit audio driver instance. 463 405 * 464 406 * @copydoc FNPDMDRVCONSTRUCT … … 469 411 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); 470 412 PDRVHOSTVAKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVAKITAUDIO); 471 LogRel(("Audio: Initializing V alidationKitdriver\n"));413 LogRel(("Audio: Initializing VAKIT driver\n")); 472 414 473 415 /* … … 491 433 PDM_DRVREG_VERSION, 492 434 /* szName */ 493 "Va lidationKitAudio",435 "VaKitAudio", 494 436 /* szRCMod */ 495 437 "", … … 497 439 "", 498 440 /* pszDescription */ 499 "Va lidationKit audio host driver",441 "VaKit audio host driver", 500 442 /* fFlags */ 501 443 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, … … 503 445 PDM_DRVREG_CLASS_AUDIO, 504 446 /* cMaxInstances */ 505 1,447 ~0U, 506 448 /* cbInstance */ 507 449 sizeof(DRVHOSTVAKITAUDIO),
Note:
See TracChangeset
for help on using the changeset viewer.