Changeset 88478 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Apr 13, 2021 12:03:47 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143737
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
r88477 r88478 24 24 #include <VBox/vmm/pdmaudioifs.h> 25 25 #include <VBox/vmm/pdmaudioinline.h> 26 #include <VBox/vmm/pdmaudiohostenuminline.h> 26 27 27 28 #include <stdio.h> … … 89 90 typedef struct PULSEAUDIOENUMCBCTX 90 91 { 91 /** Pointer to host backend driver. */92 PDRVHOSTPULSEAUDIO pDrv;93 92 /** Pointer to PulseAudio's threaded main loop. */ 94 93 pa_threaded_mainloop *pMainLoop; 95 94 /** Enumeration flags, PULSEAUDIOENUMCBFLAGS_XXX. */ 96 95 uint32_t fFlags; 97 /** VBox status code for the operation. */ 96 /** VBox status code for the operation. 97 * The caller sets this to VERR_AUDIO_ENUMERATION_FAILED, the callback never 98 * uses that status code. */ 98 99 int32_t rcEnum; 99 /** Number of found input devices. */100 uint8_t cDevIn;101 /** Number of found output devices. */102 uint8_t cDevOut;103 100 /** Name of default sink being used. Must be free'd using RTStrFree(). */ 104 101 char *pszDefaultSink; 105 102 /** Name of default source being used. Must be free'd using RTStrFree(). */ 106 103 char *pszDefaultSource; 104 /** The device enumeration to fill, NULL if pfnGetConfig context. */ 105 PPDMAUDIOHOSTENUM pDeviceEnum; 107 106 } PULSEAUDIOENUMCBCTX; 108 107 /** Pointer to an enumeration callback context. */ 109 108 typedef PULSEAUDIOENUMCBCTX *PPULSEAUDIOENUMCBCTX; 109 110 111 /** 112 * Pulse audio device enumeration entry. 113 */ 114 typedef struct PULSEAUDIODEVENTRY 115 { 116 /** The part we share with others. */ 117 PDMAUDIOHOSTDEV Core; 118 /** The pulse audio name. 119 * @note Kind of must use fixed size field here as that allows 120 * PDMAudioHostDevDup() and PDMAudioHostEnumCopy() to work. */ 121 RT_FLEXIBLE_ARRAY_EXTENSION 122 char szPulseName[RT_FLEXIBLE_ARRAY]; 123 } PULSEAUDIODEVENTRY; 124 /** Pointer to a pulse audio device enumeration entry. */ 125 typedef PULSEAUDIODEVENTRY *PPULSEAUDIODEVENTRY; 110 126 111 127 … … 338 354 339 355 /** 356 * Worker for drvHostAudioPaEnumSourceCallback() and 357 * drvHostAudioPaEnumSinkCallback() that adds an entry to the enumeration 358 * result. 359 */ 360 static void drvHostAudioPaEnumAddDevice(PPULSEAUDIOENUMCBCTX pCbCtx, PDMAUDIODIR enmDir, const char *pszName, 361 const char *pszDesc, uint8_t cChannelsInput, uint8_t cChannelsOutput, 362 const char *pszDefaultName) 363 { 364 size_t const cchName = strlen(pszName); 365 PPULSEAUDIODEVENTRY pDev = (PPULSEAUDIODEVENTRY)PDMAudioHostDevAlloc(RT_UOFFSETOF(PULSEAUDIODEVENTRY, szPulseName) 366 + RT_ALIGN_Z(cchName + 1, 16)); 367 if (pDev != NULL) 368 { 369 memcpy(pDev->szPulseName, pszName, cchName); 370 pDev->szPulseName[cchName] = '\0'; 371 372 pDev->Core.enmUsage = enmDir; 373 pDev->Core.enmType = RTStrIStr(pszDesc, "built-in") != NULL 374 ? PDMAUDIODEVICETYPE_BUILTIN : PDMAUDIODEVICETYPE_UNKNOWN; 375 pDev->Core.fFlags = RTStrCmp(pszName, pszDefaultName) == 0 376 ? PDMAUDIOHOSTDEV_F_DEFAULT : PDMAUDIOHOSTDEV_F_NONE; 377 pDev->Core.cMaxInputChannels = cChannelsInput; 378 pDev->Core.cMaxOutputChannels = cChannelsOutput; 379 RTStrCopy(pDev->Core.szName, sizeof(pDev->Core.szName), 380 pszDesc && *pszDesc ? pszDesc : pszName); 381 382 PDMAudioHostEnumAppend(pCbCtx->pDeviceEnum, &pDev->Core); 383 } 384 else 385 pCbCtx->rcEnum = VERR_NO_MEMORY; 386 } 387 388 389 /** 340 390 * Enumeration callback - source info. 341 391 * … … 357 407 if (eol == 0 && pInfo != NULL) 358 408 { 359 LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name)); 360 /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */ 361 pCbCtx->cDevIn++; 409 if (pCbCtx->pDeviceEnum) 410 drvHostAudioPaEnumAddDevice(pCbCtx, PDMAUDIODIR_IN, pInfo->name, pInfo->description, 411 pInfo->sample_spec.channels, 0 /*cChannelsOutput*/, pCbCtx->pszDefaultSource); 412 else 413 { 414 LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name)); 415 /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */ 416 } 417 } 418 else if (eol == 1 && !pInfo && pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED) 362 419 pCbCtx->rcEnum = VINF_SUCCESS; 363 }364 420 365 421 /* Wake up the calling thread when done: */ … … 389 445 if (eol == 0 && pInfo != NULL) 390 446 { 391 LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name)); 392 /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */ 393 pCbCtx->cDevOut++; 447 if (pCbCtx->pDeviceEnum) 448 drvHostAudioPaEnumAddDevice(pCbCtx, PDMAUDIODIR_OUT, pInfo->name, pInfo->description, 449 0 /*cChannelsInput*/, pInfo->sample_spec.channels, pCbCtx->pszDefaultSink); 450 else 451 { 452 LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name)); 453 /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */ 454 } 455 } 456 else if (eol == 1 && !pInfo && pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED) 394 457 pCbCtx->rcEnum = VINF_SUCCESS; 395 }396 458 397 459 /* Wake up the calling thread when done: */ … … 420 482 pInfo->sample_spec.format, pInfo->sample_spec.rate, pInfo->sample_spec.channels)); 421 483 484 Assert(!pCbCtx->pszDefaultSink); 485 Assert(!pCbCtx->pszDefaultSource); 486 Assert(pCbCtx->rcEnum == VERR_AUDIO_ENUMERATION_FAILED); 422 487 pCbCtx->rcEnum = VINF_SUCCESS; 423 488 … … 446 511 * @note Called with the PA main loop locked. 447 512 */ 448 static int drvHostAudioPaEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum) 449 { 450 PULSEAUDIOENUMCBCTX CbCtx = { pThis, pThis->pMainLoop, fEnum, VERR_AUDIO_BACKEND_INIT_FAILED, 0, 0, NULL, NULL }; 513 static int drvHostAudioPaEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, 514 uint32_t fEnum, PPDMAUDIOHOSTENUM pDeviceEnum) 515 { 516 PULSEAUDIOENUMCBCTX CbCtx = { pThis->pMainLoop, fEnum, VERR_AUDIO_ENUMERATION_FAILED, NULL, NULL, pDeviceEnum }; 451 517 bool const fLog = (fEnum & PULSEAUDIOENUMCBFLAGS_LOG); 452 518 int rc; … … 457 523 */ 458 524 LogRel(("PulseAudio: Retrieving server information ...\n")); 459 CbCtx.rcEnum = VERR_AUDIO_ BACKEND_INIT_FAILED;525 CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED; 460 526 pa_operation *paOpServerInfo = pa_context_get_server_info(pThis->pContext, drvHostAudioPaEnumServerCallback, &CbCtx); 461 527 if (paOpServerInfo) … … 478 544 * Get info about the playback sink. 479 545 */ 480 if (CbCtx.pszDefaultSink) 481 { 482 if (fLog) 483 LogRel2(("PulseAudio: Default output sink is '%s'\n", CbCtx.pszDefaultSink)); 484 CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED; 485 rc = drvHostAudioPaWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, CbCtx.pszDefaultSink, 486 drvHostAudioPaEnumSinkCallback, &CbCtx)); 546 if (fLog && CbCtx.pszDefaultSink) 547 LogRel2(("PulseAudio: Default output sink is '%s'\n", CbCtx.pszDefaultSink)); 548 else if (fLog) 549 LogRel2(("PulseAudio: No default output sink found\n")); 550 551 if (CbCtx.pszDefaultSink || pDeviceEnum) 552 { 553 CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED; 554 if (pDeviceEnum) 555 rc = drvHostAudioPaWaitFor(pThis, 556 pa_context_get_sink_info_list(pThis->pContext, drvHostAudioPaEnumSinkCallback, &CbCtx)); 557 else 558 rc = drvHostAudioPaWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, CbCtx.pszDefaultSink, 559 drvHostAudioPaEnumSinkCallback, &CbCtx)); 487 560 if (RT_SUCCESS(rc)) 488 561 rc = CbCtx.rcEnum; 489 if (fLog) 490 { 491 if (RT_SUCCESS(rc)) 492 LogRel2(("PulseAudio: Found %RU8 host playback device(s)\n", CbCtx.cDevOut)); 493 else 494 LogRel(("PulseAudio: Error enumerating properties for default output sink '%s': %Rrc\n", 495 CbCtx.pszDefaultSink, rc)); 496 } 497 } 498 else if (fLog) 499 LogRel2(("PulseAudio: No default output sink found\n")); 562 if (fLog && RT_FAILURE(rc)) 563 LogRel(("PulseAudio: Error enumerating properties for default output sink '%s': %Rrc\n", 564 CbCtx.pszDefaultSink, rc)); 565 } 500 566 501 567 /* 502 568 * Get info about the recording source. 503 569 */ 504 if (CbCtx.pszDefaultSource) 505 { 506 if (fLog) 507 LogRel2(("PulseAudio: Default input source is '%s'\n", CbCtx.pszDefaultSource)); 508 CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED; 509 int rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, CbCtx.pszDefaultSource, 570 if (fLog && CbCtx.pszDefaultSource) 571 LogRel2(("PulseAudio: Default input source is '%s'\n", CbCtx.pszDefaultSource)); 572 else if (fLog) 573 LogRel2(("PulseAudio: No default input source found\n")); 574 if (CbCtx.pszDefaultSource || pDeviceEnum) 575 { 576 CbCtx.rcEnum = VERR_AUDIO_ENUMERATION_FAILED; 577 int rc2; 578 if (pDeviceEnum) 579 rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_list(pThis->pContext, 580 drvHostAudioPaEnumSourceCallback, &CbCtx)); 581 else 582 rc2 = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, CbCtx.pszDefaultSource, 510 583 drvHostAudioPaEnumSourceCallback, &CbCtx)); 511 584 if (RT_SUCCESS(rc2)) 512 585 rc2 = CbCtx.rcEnum; 513 if (fLog) 514 { 515 if (RT_SUCCESS(rc2)) 516 LogRel2(("PulseAudio: Found %RU8 host capturing device(s)\n", CbCtx.cDevIn)); 517 else 518 LogRel(("PulseAudio: Error enumerating properties for default input source '%s': %Rrc\n", 519 CbCtx.pszDefaultSource, rc)); 520 } 586 if (fLog && RT_FAILURE(rc2)) 587 LogRel(("PulseAudio: Error enumerating properties for default input source '%s': %Rrc\n", 588 CbCtx.pszDefaultSource, rc)); 521 589 if (RT_SUCCESS(rc)) 522 590 rc = rc2; 523 591 } 524 else if (fLog)525 LogRel2(("PulseAudio: No default input source found\n"));526 592 527 593 /** @todo r=bird: WTF are we making all this effort here w/o actually 528 * updating niether the backend configuration structure nor pThis? 529 * Sigh^3! */ 594 * updating neither the backend configuration structure nor pThis? 595 * Sigh^3! 596 * 597 * update: I've reused this code for actual device enumeration now, so 598 * it's not 99.5% useless anymore, but I'm still puzzled at why it's 599 * required for pfnGetConfig... */ 530 600 RT_NOREF(pCfg); 531 601 … … 556 626 /* Refine it or something (currently only some LogRel2 stuff): */ 557 627 pa_threaded_mainloop_lock(pThis->pMainLoop); 558 int rc = drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG /* fEnum*/);628 int rc = drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG, NULL /*pDeviceEnum*/); 559 629 pa_threaded_mainloop_unlock(pThis->pMainLoop); 560 630 return rc; … … 563 633 564 634 /** 635 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices} 636 */ 637 static DECLCALLBACK(int) drvHostAudioPaHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum) 638 { 639 PDRVHOSTPULSEAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio); 640 AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER); 641 PDMAudioHostEnumInit(pDeviceEnum); 642 643 /* Refine it or something (currently only some LogRel2 stuff): */ 644 pa_threaded_mainloop_lock(pThis->pMainLoop); 645 int rc = drvHostAudioPaEnumerate(pThis, NULL /*pCfg*/, PULSEAUDIOENUMCBFLAGS_NONE, pDeviceEnum); 646 pa_threaded_mainloop_unlock(pThis->pMainLoop); 647 return rc; 648 } 649 650 651 652 /** 565 653 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus} 566 654 */ 567 655 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostAudioPaHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir) 568 656 { 569 RT_NOREF(enmDir); 570 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN); 571 657 RT_NOREF(pInterface, enmDir); 572 658 return PDMAUDIOBACKENDSTS_RUNNING; 573 659 } … … 1520 1606 /* IHostAudio */ 1521 1607 pThis->IHostAudio.pfnGetConfig = drvHostAudioPaHA_GetConfig; 1522 pThis->IHostAudio.pfnGetDevices = NULL;1608 pThis->IHostAudio.pfnGetDevices = drvHostAudioPaHA_GetDevices; 1523 1609 pThis->IHostAudio.pfnGetStatus = drvHostAudioPaHA_GetStatus; 1524 1610 pThis->IHostAudio.pfnStreamCreate = drvHostAudioPaHA_StreamCreate; -
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp
r88226 r88478 77 77 (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata), 78 78 (c, name, cb, userdata)) 79 PROXY_STUB (pa_context_get_sink_info_list, pa_operation *, 80 (pa_context *c, pa_sink_info_cb_t cb, void *userdata), 81 (c, cb, userdata)) 79 82 PROXY_STUB (pa_context_get_source_info_by_name, pa_operation*, 80 83 (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata), 81 84 (c, name, cb, userdata)) 85 PROXY_STUB (pa_context_get_source_info_list, pa_operation *, 86 (pa_context *c, pa_source_info_cb_t cb, void *userdata), 87 (c, cb, userdata)) 82 88 PROXY_STUB (pa_context_get_state, pa_context_state_t, 83 89 (pa_context *c), … … 257 263 FUNC_ENTRY(pa_context_get_server_info), 258 264 FUNC_ENTRY(pa_context_get_sink_info_by_name), 265 FUNC_ENTRY(pa_context_get_sink_info_list), 259 266 FUNC_ENTRY(pa_context_get_source_info_by_name), 267 FUNC_ENTRY(pa_context_get_source_info_list), 260 268 FUNC_ENTRY(pa_context_get_state), 261 269 FUNC_ENTRY(pa_context_unref), -
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubsMangling.h
r88226 r88478 34 34 #define pa_context_get_server_info PULSE_MANGLER(pa_context_get_server_info) 35 35 #define pa_context_get_sink_info_by_name PULSE_MANGLER(pa_context_get_sink_info_by_name) 36 #define pa_context_get_sink_info_list PULSE_MANGLER(pa_context_get_sink_info_list) 36 37 #define pa_context_get_source_info_by_name PULSE_MANGLER(pa_context_get_source_info_by_name) 38 #define pa_context_get_source_info_list PULSE_MANGLER(pa_context_get_source_info_list) 37 39 #define pa_context_get_state PULSE_MANGLER(pa_context_get_state) 38 40 #define pa_context_unref PULSE_MANGLER(pa_context_unref)
Note:
See TracChangeset
for help on using the changeset viewer.