Changeset 88460 in vbox
- Timestamp:
- Apr 12, 2021 10:51:18 AM (3 years ago)
- File:
-
- 1 edited
-
trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp
r88390 r88460 44 44 *********************************************************************************************************************************/ 45 45 /** 46 * Audio VRDE driver instance data. 46 * VRDE stream. 47 */ 48 typedef struct VRDESTREAM 49 { 50 /** The stream's acquired configuration. */ 51 PDMAUDIOSTREAMCFG Cfg; 52 union 53 { 54 struct 55 { 56 /** Circular buffer for holding the recorded audio frames from the host. */ 57 PRTCIRCBUF pCircBuf; 58 } In; 59 }; 60 } VRDESTREAM; 61 /** Pointer to a VRDE stream. */ 62 typedef VRDESTREAM *PVRDESTREAM; 63 64 /** 65 * VRDE (host) audio driver instance data. 47 66 */ 48 67 typedef struct DRVAUDIOVRDE … … 52 71 /** Pointer to the driver instance structure. */ 53 72 PPDMDRVINS pDrvIns; 54 /** Pointer to host audio interface. */55 PDMIHOSTAUDIO IHostAudio;56 73 /** Pointer to the VRDP's console object. */ 57 74 ConsoleVRDPServer *pConsoleVRDPServer; … … 60 77 /** Number of connected clients to this VRDE instance. */ 61 78 uint32_t cClients; 62 } DRVAUDIOVRDE, *PDRVAUDIOVRDE; 63 64 typedef struct VRDESTREAM 65 { 66 /** The stream's acquired configuration. */ 67 PPDMAUDIOSTREAMCFG pCfg; 68 union 69 { 70 struct 71 { 72 /** Circular buffer for holding the recorded audio frames from the host. */ 73 PRTCIRCBUF pCircBuf; 74 } In; 75 }; 76 } VRDESTREAM, *PVRDESTREAM; 79 /** Pointer to host audio interface. */ 80 PDMIHOSTAUDIO IHostAudio; 81 } DRVAUDIOVRDE; 82 /** Pointer to the instance data for an VRDE audio driver. */ 83 typedef DRVAUDIOVRDE *PDRVAUDIOVRDE; 77 84 78 85 /* Sanity. */ 79 86 AssertCompileSize(PDMAUDIOFRAME, sizeof(int64_t) * 2 /* st_sample_t using by VRDP server */); 80 87 81 static int vrdeCreateStreamIn(PVRDESTREAM pStreamVRDE, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 82 { 83 RT_NOREF(pCfgReq); 84 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 85 88 89 90 /********************************************************************************************************************************* 91 * Class AudioVRDE * 92 *********************************************************************************************************************************/ 93 94 AudioVRDE::AudioVRDE(Console *pConsole) 95 : AudioDriver(pConsole) 96 , mpDrv(NULL) 97 { 98 } 99 100 101 AudioVRDE::~AudioVRDE(void) 102 { 103 if (mpDrv) 104 { 105 mpDrv->pAudioVRDE = NULL; 106 mpDrv = NULL; 107 } 108 } 109 110 111 /** 112 * @copydoc AudioDriver::configureDriver 113 */ 114 int AudioVRDE::configureDriver(PCFGMNODE pLunCfg) 115 { 116 int rc = CFGMR3InsertInteger(pLunCfg, "Object", (uintptr_t)this); 117 AssertRCReturn(rc, rc); 118 CFGMR3InsertInteger(pLunCfg, "ObjectVRDPServer", (uintptr_t)mpConsole->i_consoleVRDPServer()); 119 AssertRCReturn(rc, rc); 120 121 return AudioDriver::configureDriver(pLunCfg); 122 } 123 124 125 void AudioVRDE::onVRDEClientConnect(uint32_t uClientID) 126 { 127 RT_NOREF(uClientID); 128 129 LogRel2(("Audio: VRDE client connected\n")); 130 if (mpDrv) 131 mpDrv->cClients++; 132 } 133 134 135 void AudioVRDE::onVRDEClientDisconnect(uint32_t uClientID) 136 { 137 RT_NOREF(uClientID); 138 139 LogRel2(("Audio: VRDE client disconnected\n")); 140 Assert(mpDrv->cClients); 141 if (mpDrv) 142 mpDrv->cClients--; 143 } 144 145 146 int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags) 147 { 148 RT_NOREF(fEnable, uFlags); 149 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags)); 150 151 if (mpDrv == NULL) 152 return VERR_INVALID_STATE; 153 154 return VINF_SUCCESS; /* Never veto. */ 155 } 156 157 158 /** 159 * Marks the beginning of sending captured audio data from a connected 160 * RDP client. 161 * 162 * @returns VBox status code. 163 * @param pvContext The context; in this case a pointer to a 164 * VRDESTREAMIN structure. 165 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure. 166 */ 167 int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin) 168 { 169 AssertPtrReturn(pvContext, VERR_INVALID_POINTER); 170 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER); 171 PVRDESTREAM pVRDEStrmIn = (PVRDESTREAM)pvContext; 172 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER); 173 174 #ifdef LOG_ENABLED 175 VRDEAUDIOFORMAT const audioFmt = pVRDEAudioBegin->fmt; 176 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n", 177 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt), 178 VRDE_AUDIO_FMT_CHANNELS(audioFmt), VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt), VRDE_AUDIO_FMT_SIGNED(audioFmt))); 179 #endif 180 181 return VINF_SUCCESS; 182 } 183 184 185 int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData) 186 { 187 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pvContext; 188 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER); 189 190 void *pvBuf = NULL; 191 size_t cbBuf = 0; 192 RTCircBufAcquireWriteBlock(pStreamVRDE->In.pCircBuf, cbData, &pvBuf, &cbBuf); 193 194 if (cbBuf) 195 memcpy(pvBuf, pvData, cbBuf); 196 197 RTCircBufReleaseWriteBlock(pStreamVRDE->In.pCircBuf, cbBuf); 198 199 if (cbBuf < cbData) 200 LogRelMax(999, ("VRDE: Capturing audio data lost %zu bytes\n", cbData - cbBuf)); /** @todo Use an error counter. */ 201 202 return VINF_SUCCESS; /** @todo r=andy How to tell the caller if we were not able to handle *all* input data? */ 203 } 204 205 206 int AudioVRDE::onVRDEInputEnd(void *pvContext) 207 { 208 RT_NOREF(pvContext); 209 return VINF_SUCCESS; 210 } 211 212 213 int AudioVRDE::onVRDEInputIntercept(bool fEnabled) 214 { 215 RT_NOREF(fEnabled); 216 return VINF_SUCCESS; /* Never veto. */ 217 } 218 219 220 221 /********************************************************************************************************************************* 222 * PDMIHOSTAUDIO * 223 *********************************************************************************************************************************/ 224 225 /** 226 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig} 227 */ 228 static DECLCALLBACK(int) drvAudioVrdeHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) 229 { 230 RT_NOREF(pInterface); 231 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER); 232 233 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "VRDE"); 234 pBackendCfg->cbStreamOut = sizeof(VRDESTREAM); 235 pBackendCfg->cbStreamIn = sizeof(VRDESTREAM); 236 pBackendCfg->cMaxStreamsIn = UINT32_MAX; 237 pBackendCfg->cMaxStreamsOut = UINT32_MAX; 238 239 return VINF_SUCCESS; 240 } 241 242 243 /** 244 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus} 245 */ 246 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVrdeHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir) 247 { 248 RT_NOREF(pInterface, enmDir); 249 return PDMAUDIOBACKENDSTS_RUNNING; 250 } 251 252 253 static int vrdeCreateStreamIn(PVRDESTREAM pStreamVRDE, PPDMAUDIOSTREAMCFG pCfgAcq) 254 { 86 255 /* 87 256 * The VRDP server does its own mixing and resampling as it may server … … 111 280 112 281 113 static int vrdeCreateStreamOut(PVRDESTREAM pStreamVRDE, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 114 { 115 RT_NOREF(pStreamVRDE, pCfgReq); 116 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 117 282 static int vrdeCreateStreamOut(PPDMAUDIOSTREAMCFG pCfgAcq) 283 { 118 284 /* 119 285 * The VRDP server does its own mixing and resampling because it may be … … 139 305 140 306 141 static int vrdeControlStreamOut(PDRVAUDIOVRDE pDrv, PVRDESTREAM pStreamVRDE, PDMAUDIOSTREAMCMD enmStreamCmd) 142 { 143 RT_NOREF(pDrv, pStreamVRDE, enmStreamCmd); 144 145 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd)); 146 147 return VINF_SUCCESS; 148 } 149 150 151 static int vrdeControlStreamIn(PDRVAUDIOVRDE pDrv, PVRDESTREAM pStreamVRDE, PDMAUDIOSTREAMCMD enmStreamCmd) 152 { 153 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd)); 154 307 /** 308 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 309 */ 310 static DECLCALLBACK(int) drvAudioVrdeHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 311 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 312 { 313 RT_NOREF(pInterface); 314 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 315 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER); 316 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 317 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 318 319 int rc; 320 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 321 rc = vrdeCreateStreamIn(pStreamVRDE, pCfgAcq); 322 else 323 rc = vrdeCreateStreamOut(pCfgAcq); 324 PDMAudioStrmCfgCopy(&pStreamVRDE->Cfg, pCfgAcq); 325 return rc; 326 } 327 328 329 /** 330 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 331 */ 332 static DECLCALLBACK(int) drvAudioVrdeHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 333 { 334 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 335 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 336 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER); 337 338 if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_OUT) 339 { 340 if (pDrv->pConsoleVRDPServer) 341 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL); 342 343 if (pStreamVRDE->In.pCircBuf) 344 { 345 RTCircBufDestroy(pStreamVRDE->In.pCircBuf); 346 pStreamVRDE->In.pCircBuf = NULL; 347 } 348 } 349 pDrv->pConsoleVRDPServer = NULL; 350 351 return VINF_SUCCESS; 352 } 353 354 355 /** 356 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable} 357 */ 358 static DECLCALLBACK(int) drvAudioVrdeHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 359 { 360 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 361 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 362 363 int rc; 155 364 if (!pDrv->pConsoleVRDPServer) 156 365 { 157 LogRel(("Audio: VRDP console not ready yet\n")); 366 LogRelMax(32, ("Audio: VRDP console not ready (enable)\n")); 367 rc = VERR_AUDIO_STREAM_NOT_READY; 368 } 369 else if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN) 370 { 371 rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pStreamVRDE, 372 PDMAudioPropsMilliToFrames(&pStreamVRDE->Cfg.Props, 200 /*ms*/), 373 PDMAudioPropsHz(&pStreamVRDE->Cfg.Props), 374 PDMAudioPropsChannels(&pStreamVRDE->Cfg.Props), 375 PDMAudioPropsSampleBits(&pStreamVRDE->Cfg.Props)); 376 if (rc == VERR_NOT_SUPPORTED) 377 { 378 LogRelMax(64, ("Audio: No VRDE client connected, so no input recording available\n")); 379 rc = VERR_AUDIO_STREAM_NOT_READY; 380 } 381 } 382 else 383 rc = VINF_SUCCESS; 384 LogFlowFunc(("returns %Rrc\n", rc)); 385 return rc; 386 } 387 388 389 /** 390 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable} 391 */ 392 static DECLCALLBACK(int) drvAudioVrdeHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 393 { 394 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 395 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 396 397 int rc; 398 if (!pDrv->pConsoleVRDPServer) 399 { 400 LogRelMax(32, ("Audio: VRDP console not ready (disable)\n")); 401 rc = VERR_AUDIO_STREAM_NOT_READY; 402 } 403 else if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN) 404 { 405 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */); 406 rc = VINF_SUCCESS; 407 } 408 else 409 rc = VINF_SUCCESS; 410 LogFlowFunc(("returns %Rrc\n", rc)); 411 return rc; 412 } 413 414 415 /** 416 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause} 417 */ 418 static DECLCALLBACK(int) drvAudioVrdeHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 419 { 420 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 421 RT_NOREF(pStream); 422 423 if (!pDrv->pConsoleVRDPServer) 424 { 425 LogRelMax(32, ("Audio: VRDP console not ready (pause)\n")); 158 426 return VERR_AUDIO_STREAM_NOT_READY; 159 427 } 160 161 int rc; 162 163 /* Initialize only if not already done. */ 428 LogFlowFunc(("returns VINF_SUCCESS\n")); 429 return VINF_SUCCESS; 430 } 431 432 433 /** 434 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume} 435 */ 436 static DECLCALLBACK(int) drvAudioVrdeHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 437 { 438 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 439 RT_NOREF(pStream); 440 441 if (!pDrv->pConsoleVRDPServer) 442 { 443 LogRelMax(32, ("Audio: VRDP console not ready (resume)\n")); 444 return VERR_AUDIO_STREAM_NOT_READY; 445 } 446 LogFlowFunc(("returns VINF_SUCCESS\n")); 447 return VINF_SUCCESS; 448 } 449 450 451 /** 452 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain} 453 */ 454 static DECLCALLBACK(int) drvAudioVrdeHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 455 { 456 RT_NOREF(pInterface, pStream); 457 LogFlowFunc(("returns VINF_SUCCESS\n")); 458 return VINF_SUCCESS; 459 } 460 461 462 /** 463 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} 464 */ 465 static DECLCALLBACK(int) drvAudioVrdeHA_StreamControl(PPDMIHOSTAUDIO pInterface, 466 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) 467 { 468 /** @todo r=bird: I'd like to get rid of this pfnStreamControl method, 469 * replacing it with individual StreamXxxx methods. That would save us 470 * potentally huge switches and more easily see which drivers implement 471 * which operations (grep for pfnStreamXxxx). */ 164 472 switch (enmStreamCmd) 165 473 { 166 474 case PDMAUDIOSTREAMCMD_ENABLE: 167 { 168 rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pStreamVRDE, 169 PDMAudioPropsMilliToFrames(&pStreamVRDE->pCfg->Props, 200 /*ms*/), 170 PDMAudioPropsHz(&pStreamVRDE->pCfg->Props), 171 PDMAudioPropsChannels(&pStreamVRDE->pCfg->Props), 172 PDMAudioPropsSampleBits(&pStreamVRDE->pCfg->Props)); 173 if (rc == VERR_NOT_SUPPORTED) 174 { 175 LogRel(("Audio: No VRDE client connected, so no input recording available\n")); 176 rc = VERR_AUDIO_STREAM_NOT_READY; 177 } 178 475 return drvAudioVrdeHA_StreamEnable(pInterface, pStream); 476 case PDMAUDIOSTREAMCMD_DISABLE: 477 return drvAudioVrdeHA_StreamDisable(pInterface, pStream); 478 case PDMAUDIOSTREAMCMD_PAUSE: 479 return drvAudioVrdeHA_StreamPause(pInterface, pStream); 480 case PDMAUDIOSTREAMCMD_RESUME: 481 return drvAudioVrdeHA_StreamResume(pInterface, pStream); 482 case PDMAUDIOSTREAMCMD_DRAIN: 483 return drvAudioVrdeHA_StreamDrain(pInterface, pStream); 484 485 case PDMAUDIOSTREAMCMD_END: 486 case PDMAUDIOSTREAMCMD_32BIT_HACK: 487 case PDMAUDIOSTREAMCMD_INVALID: 488 /* no default*/ 179 489 break; 180 } 181 182 case PDMAUDIOSTREAMCMD_DISABLE: 183 { 184 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */); 185 rc = VINF_SUCCESS; 186 187 break; 188 } 189 190 case PDMAUDIOSTREAMCMD_PAUSE: 191 { 192 rc = VINF_SUCCESS; 193 break; 194 } 195 196 case PDMAUDIOSTREAMCMD_RESUME: 197 { 198 rc = VINF_SUCCESS; 199 break; 200 } 201 202 default: 203 { 204 rc = VERR_NOT_SUPPORTED; 205 break; 206 } 207 } 208 209 if (RT_FAILURE(rc)) 210 LogFunc(("Failed with %Rrc\n", rc)); 211 212 return rc; 213 } 214 215 /** 216 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture} 217 */ 218 static DECLCALLBACK(int) drvAudioVrdeHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 219 void *pvBuf, uint32_t uBufSize, uint32_t *puRead) 220 { 221 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 222 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 223 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 224 AssertReturn(uBufSize, VERR_INVALID_PARAMETER); 225 /* puRead is optional. */ 226 490 } 491 return VERR_NOT_SUPPORTED; 492 } 493 494 495 /** 496 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} 497 */ 498 static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 499 { 500 RT_NOREF(pInterface); 227 501 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 228 502 229 size_t cbData = 0; 230 231 if (RTCircBufUsed(pStreamVRDE->In.pCircBuf)) 232 { 233 void *pvData; 234 235 RTCircBufAcquireReadBlock(pStreamVRDE->In.pCircBuf, uBufSize, &pvData, &cbData); 236 237 if (cbData) 238 memcpy(pvBuf, pvData, cbData); 239 240 RTCircBufReleaseReadBlock(pStreamVRDE->In.pCircBuf, cbData); 241 } 242 243 if (puRead) 244 *puRead = (uint32_t)cbData; 245 246 return VINF_SUCCESS; 503 if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN) 504 { 505 /* Return frames instead of bytes here 506 * (since we specified PDMAUDIOSTREAMLAYOUT_RAW as the audio data layout). */ 507 return (uint32_t)PDMAudioPropsBytesToFrames(&pStreamVRDE->Cfg.Props, RTCircBufUsed(pStreamVRDE->In.pCircBuf)); 508 } 509 return 0; 510 } 511 512 513 /** 514 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable} 515 */ 516 static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 517 { 518 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 519 RT_NOREF(pStream); 520 521 /** @todo Find some sane value here. We probably need a VRDE API VRDE to specify this. */ 522 if (pDrv->cClients) 523 return _16K * sizeof(PDMAUDIOFRAME); 524 return 0; 525 } 526 527 528 /** 529 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus} 530 */ 531 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvAudioVrdeHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 532 { 533 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 534 RT_NOREF(pStream); 535 536 PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED; 537 538 if (pDrv->cClients) /* If any clients are connected, flag the stream as enabled. */ 539 fStrmStatus |= PDMAUDIOSTREAMSTS_FLAGS_ENABLED; 540 541 return fStrmStatus; 247 542 } 248 543 … … 266 561 267 562 /* Prepate the format. */ 268 PPDMAUDIOPCMPROPS pProps = &pStreamVRDE-> pCfg->Props;563 PPDMAUDIOPCMPROPS pProps = &pStreamVRDE->Cfg.Props; 269 564 VRDEAUDIOFORMAT const uVrdpFormat = VRDE_AUDIO_FMT_MAKE(PDMAudioPropsHz(pProps), 270 565 PDMAudioPropsChannels(pProps), … … 307 602 308 603 309 static int vrdeDestroyStreamIn(PDRVAUDIOVRDE pDrv, PVRDESTREAM pStreamVRDE) 310 { 311 if (pDrv->pConsoleVRDPServer) 312 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL); 313 314 if (pStreamVRDE->In.pCircBuf) 315 { 316 RTCircBufDestroy(pStreamVRDE->In.pCircBuf); 317 pStreamVRDE->In.pCircBuf = NULL; 318 } 319 320 return VINF_SUCCESS; 321 } 322 323 324 static int vrdeDestroyStreamOut(PDRVAUDIOVRDE pDrv, PVRDESTREAM pStreamVRDE) 325 { 326 RT_NOREF(pDrv, pStreamVRDE); 327 328 return VINF_SUCCESS; 329 } 330 331 332 /** 333 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig} 334 */ 335 static DECLCALLBACK(int) drvAudioVrdeHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) 604 /** 605 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture} 606 */ 607 static DECLCALLBACK(int) drvAudioVrdeHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 608 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 336 609 { 337 610 RT_NOREF(pInterface); 338 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);339 340 RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "VRDE");341 342 pBackendCfg->cbStreamOut = sizeof(VRDESTREAM);343 pBackendCfg->cbStreamIn = sizeof(VRDESTREAM);344 pBackendCfg->cMaxStreamsIn = UINT32_MAX;345 pBackendCfg->cMaxStreamsOut = UINT32_MAX;346 347 return VINF_SUCCESS;348 }349 350 351 /**352 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}353 */354 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVrdeHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)355 {356 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);357 AssertPtrReturn(pDrv, PDMAUDIOBACKENDSTS_ERROR);358 359 RT_NOREF(enmDir);360 361 return PDMAUDIOBACKENDSTS_RUNNING;362 }363 364 365 /**366 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}367 */368 static DECLCALLBACK(int) drvAudioVrdeHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,369 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)370 {371 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);372 AssertPtrReturn(pStream, VERR_INVALID_POINTER);373 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);374 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);375 376 RT_NOREF(pInterface);377 378 611 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 379 380 int rc; 381 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 382 rc = vrdeCreateStreamIn( pStreamVRDE, pCfgReq, pCfgAcq); 383 else 384 rc = vrdeCreateStreamOut(pStreamVRDE, pCfgReq, pCfgAcq); 385 386 if (RT_SUCCESS(rc)) 387 { 388 pStreamVRDE->pCfg = PDMAudioStrmCfgDup(pCfgAcq); 389 if (!pStreamVRDE->pCfg) 390 rc = VERR_NO_MEMORY; 391 } 392 393 return rc; 394 } 395 396 397 /** 398 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 399 */ 400 static DECLCALLBACK(int) drvAudioVrdeHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 401 { 402 RT_NOREF(pInterface); 403 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 404 405 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 406 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 407 408 if (!pStreamVRDE->pCfg) /* Not (yet) configured? Skip. */ 409 return VINF_SUCCESS; 410 411 int rc; 412 if (pStreamVRDE->pCfg->enmDir == PDMAUDIODIR_IN) 413 rc = vrdeDestroyStreamIn(pDrv, pStreamVRDE); 414 else 415 rc = vrdeDestroyStreamOut(pDrv, pStreamVRDE); 416 417 if (RT_SUCCESS(rc)) 418 { 419 PDMAudioStrmCfgFree(pStreamVRDE->pCfg); 420 pStreamVRDE->pCfg = NULL; 421 } 422 423 return rc; 424 } 425 426 427 /** 428 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} 429 */ 430 static DECLCALLBACK(int) drvAudioVrdeHA_StreamControl(PPDMIHOSTAUDIO pInterface, 431 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd) 432 { 433 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 434 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 435 436 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 437 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 438 439 if (!pStreamVRDE->pCfg) /* Not (yet) configured? Skip. */ 440 return VINF_SUCCESS; 441 442 int rc; 443 if (pStreamVRDE->pCfg->enmDir == PDMAUDIODIR_IN) 444 rc = vrdeControlStreamIn(pDrv, pStreamVRDE, enmStreamCmd); 445 else 446 rc = vrdeControlStreamOut(pDrv, pStreamVRDE, enmStreamCmd); 447 448 return rc; 449 } 450 451 452 /** 453 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} 454 */ 455 static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 456 { 457 RT_NOREF(pInterface); 458 459 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream; 460 461 if (pStreamVRDE->pCfg->enmDir == PDMAUDIODIR_IN) 462 { 463 /* Return frames instead of bytes here 464 * (since we specified PDMAUDIOSTREAMLAYOUT_RAW as the audio data layout). */ 465 return (uint32_t)PDMAUDIOSTREAMCFG_B2F(pStreamVRDE->pCfg, RTCircBufUsed(pStreamVRDE->In.pCircBuf)); 466 } 467 468 return 0; 469 } 470 471 472 /** 473 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable} 474 */ 475 static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 476 { 477 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 478 RT_NOREF(pStream); 479 480 /** @todo Find some sane value here. We probably need a VRDE API VRDE to specify this. */ 481 if (pDrv->cClients) 482 return _16K * sizeof(PDMAUDIOFRAME); 483 return 0; 484 } 485 486 487 /** 488 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus} 489 */ 490 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvAudioVrdeHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 491 { 492 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio); 493 RT_NOREF(pStream); 494 495 PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED; 496 497 if (pDrv->cClients) /* If any clients are connected, flag the stream as enabled. */ 498 fStrmStatus |= PDMAUDIOSTREAMSTS_FLAGS_ENABLED; 499 500 return fStrmStatus; 501 } 502 612 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER); 613 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 614 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 615 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER); 616 617 size_t cbData = 0; 618 if (RTCircBufUsed(pStreamVRDE->In.pCircBuf)) 619 { 620 void *pvData = NULL; 621 RTCircBufAcquireReadBlock(pStreamVRDE->In.pCircBuf, cbBuf, &pvData, &cbData); 622 623 if (cbData) 624 memcpy(pvBuf, pvData, cbData); 625 626 RTCircBufReleaseReadBlock(pStreamVRDE->In.pCircBuf, cbData); 627 } 628 629 *pcbRead = (uint32_t)cbData; 630 return VINF_SUCCESS; 631 } 632 633 634 /********************************************************************************************************************************* 635 * PDMIBASE * 636 *********************************************************************************************************************************/ 503 637 504 638 /** … … 516 650 517 651 518 AudioVRDE::AudioVRDE(Console *pConsole) 519 : AudioDriver(pConsole) 520 , mpDrv(NULL) 521 { 522 } 523 524 525 AudioVRDE::~AudioVRDE(void) 526 { 527 if (mpDrv) 528 { 529 mpDrv->pAudioVRDE = NULL; 530 mpDrv = NULL; 531 } 532 } 533 534 535 /** 536 * @copydoc AudioDriver::configureDriver 537 */ 538 int AudioVRDE::configureDriver(PCFGMNODE pLunCfg) 539 { 540 int rc = CFGMR3InsertInteger(pLunCfg, "Object", (uintptr_t)this); 541 AssertRCReturn(rc, rc); 542 CFGMR3InsertInteger(pLunCfg, "ObjectVRDPServer", (uintptr_t)mpConsole->i_consoleVRDPServer()); 543 AssertRCReturn(rc, rc); 544 545 return AudioDriver::configureDriver(pLunCfg); 546 } 547 548 549 void AudioVRDE::onVRDEClientConnect(uint32_t uClientID) 550 { 551 RT_NOREF(uClientID); 552 553 LogRel2(("Audio: VRDE client connected\n")); 554 if (mpDrv) 555 mpDrv->cClients++; 556 } 557 558 559 void AudioVRDE::onVRDEClientDisconnect(uint32_t uClientID) 560 { 561 RT_NOREF(uClientID); 562 563 LogRel2(("Audio: VRDE client disconnected\n")); 564 Assert(mpDrv->cClients); 565 if (mpDrv) 566 mpDrv->cClients--; 567 } 568 569 570 int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags) 571 { 572 RT_NOREF(fEnable, uFlags); 573 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags)); 574 575 if (mpDrv == NULL) 576 return VERR_INVALID_STATE; 577 578 return VINF_SUCCESS; /* Never veto. */ 579 } 580 581 582 /** 583 * Marks the beginning of sending captured audio data from a connected 584 * RDP client. 585 * 586 * @returns VBox status code. 587 * @param pvContext The context; in this case a pointer to a 588 * VRDESTREAMIN structure. 589 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure. 590 */ 591 int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin) 592 { 593 AssertPtrReturn(pvContext, VERR_INVALID_POINTER); 594 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER); 595 596 PVRDESTREAM pVRDEStrmIn = (PVRDESTREAM)pvContext; 597 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER); 598 599 VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt; 600 601 int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt); RT_NOREF(iSampleHz); 602 int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt); RT_NOREF(cChannels); 603 int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt); RT_NOREF(cBits); 604 bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt); RT_NOREF(fUnsigned); 605 606 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n", 607 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned)); 608 609 return VINF_SUCCESS; 610 } 611 612 613 int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData) 614 { 615 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pvContext; 616 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER); 617 618 void *pvBuf; 619 size_t cbBuf; 620 621 RTCircBufAcquireWriteBlock(pStreamVRDE->In.pCircBuf, cbData, &pvBuf, &cbBuf); 622 623 if (cbBuf) 624 memcpy(pvBuf, pvData, cbBuf); 625 626 RTCircBufReleaseWriteBlock(pStreamVRDE->In.pCircBuf, cbBuf); 627 628 if (cbBuf < cbData) 629 LogRel(("VRDE: Capturing audio data lost %zu bytes\n", cbData - cbBuf)); /** @todo Use an error counter. */ 630 631 return VINF_SUCCESS; /** @todo r=andy How to tell the caller if we were not able to handle *all* input data? */ 632 } 633 634 635 int AudioVRDE::onVRDEInputEnd(void *pvContext) 636 { 637 RT_NOREF(pvContext); 638 639 return VINF_SUCCESS; 640 } 641 642 643 int AudioVRDE::onVRDEInputIntercept(bool fEnabled) 644 { 645 RT_NOREF(fEnabled); 646 return VINF_SUCCESS; /* Never veto. */ 647 } 648 652 /********************************************************************************************************************************* 653 * PDMDRVREG * 654 *********************************************************************************************************************************/ 649 655 650 656 /** … … 737 743 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */ 738 744 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser; 745 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pConsoleVRDPServer) || !pThis->pConsoleVRDPServer, 746 ("pConsoleVRDPServer=%p\n", pThis->pConsoleVRDPServer), VERR_INVALID_POINTER); 739 747 pThis->cClients = 0; 740 748 … … 747 755 748 756 pThis->pAudioVRDE = (AudioVRDE *)pvUser; 757 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pAudioVRDE), ("pAudioVRDE=%p\n", pThis->pAudioVRDE), VERR_INVALID_POINTER); 749 758 pThis->pAudioVRDE->mpDrv = pThis; 750 759
Note:
See TracChangeset
for help on using the changeset viewer.

