- Timestamp:
- Apr 12, 2021 11:00:05 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp
r88467 r88477 53 53 #define VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS 64 54 54 55 56 /** @name PULSEAUDIOENUMCBFLAGS_XXX 57 * @{ */ 55 58 /** No flags specified. */ 56 59 #define PULSEAUDIOENUMCBFLAGS_NONE 0 57 60 /** (Release) log found devices. */ 58 61 #define PULSEAUDIOENUMCBFLAGS_LOG RT_BIT(0) 62 /** @} */ 59 63 60 64 … … 62 66 * Structures * 63 67 *********************************************************************************************************************************/ 68 /** Pointer to the instance data for a pulse audio host audio driver. */ 69 typedef struct DRVHOSTPULSEAUDIO *PDRVHOSTPULSEAUDIO; 70 71 64 72 /** 65 73 * Callback context for the server init context state changed callback. … … 68 76 { 69 77 /** The event semaphore. */ 70 RTSEMEVENT 78 RTSEMEVENT hEvtInit; 71 79 /** The returned context state. */ 72 volatile pa_context_state_tenmCtxState;80 pa_context_state_t volatile enmCtxState; 73 81 } PULSEAUDIOSTATECHGCTX; 74 82 /** Pointer to a server init context state changed callback context. */ 75 83 typedef PULSEAUDIOSTATECHGCTX *PPULSEAUDIOSTATECHGCTX; 76 84 77 /** 78 * Host Pulse audio driver instance data. 79 * @implements PDMIAUDIOCONNECTOR80 */ 81 typedef struct DRVHOSTPULSEAUDIO82 { 83 /** Pointer to the driver instance structure. */84 P PDMDRVINS pDrvIns;85 86 /** 87 * Enumeration callback context used by the pfnGetConfig code. 88 */ 89 typedef struct PULSEAUDIOENUMCBCTX 90 { 91 /** Pointer to host backend driver. */ 92 PDRVHOSTPULSEAUDIO pDrv; 85 93 /** Pointer to PulseAudio's threaded main loop. */ 86 pa_threaded_mainloop *pMainLoop; 87 /** 88 * Pointer to our PulseAudio context. 89 * Note: We use a pMainLoop in a separate thread (pContext). 90 * So either use callback functions or protect these functions 91 * by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock(). 92 */ 93 pa_context *pContext; 94 /** Shutdown indicator. */ 95 volatile bool fAbortLoop; 96 /** Enumeration operation successful? */ 97 volatile bool fEnumOpSuccess; 98 /** Pointer to host audio interface. */ 99 PDMIHOSTAUDIO IHostAudio; 100 /** Error count for not flooding the release log. 101 * Specify UINT32_MAX for unlimited logging. */ 102 uint32_t cLogErrors; 103 /** The stream (base) name; needed for distinguishing 104 * streams in the PulseAudio mixer controls if multiple 105 * VMs are running at the same time. */ 106 char szStreamName[64]; 107 108 /** Don't want to put this on the stack... */ 109 PULSEAUDIOSTATECHGCTX InitStateChgCtx; 110 } DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO; 111 94 pa_threaded_mainloop *pMainLoop; 95 /** Enumeration flags, PULSEAUDIOENUMCBFLAGS_XXX. */ 96 uint32_t fFlags; 97 /** VBox status code for the operation. */ 98 int32_t rcEnum; 99 /** Number of found input devices. */ 100 uint8_t cDevIn; 101 /** Number of found output devices. */ 102 uint8_t cDevOut; 103 /** Name of default sink being used. Must be free'd using RTStrFree(). */ 104 char *pszDefaultSink; 105 /** Name of default source being used. Must be free'd using RTStrFree(). */ 106 char *pszDefaultSource; 107 } PULSEAUDIOENUMCBCTX; 108 /** Pointer to an enumeration callback context. */ 109 typedef PULSEAUDIOENUMCBCTX *PPULSEAUDIOENUMCBCTX; 110 111 112 /** 113 * Pulse audio stream data. 114 */ 112 115 typedef struct PULSEAUDIOSTREAM 113 116 { … … 141 144 pa_usec_t tsLastReadWrittenUs; 142 145 #endif 143 } PULSEAUDIOSTREAM, *PPULSEAUDIOSTREAM; 144 145 /** 146 * Callback context for server enumeration callbacks. 147 */ 148 typedef struct PULSEAUDIOENUMCBCTX 149 { 150 /** Pointer to host backend driver. */ 151 PDRVHOSTPULSEAUDIO pDrv; 152 /** Enumeration flags. */ 153 uint32_t fFlags; 154 /** Number of found input devices. */ 155 uint8_t cDevIn; 156 /** Number of found output devices. */ 157 uint8_t cDevOut; 158 /** Name of default sink being used. Must be free'd using RTStrFree(). */ 159 char *pszDefaultSink; 160 /** Name of default source being used. Must be free'd using RTStrFree(). */ 161 char *pszDefaultSource; 162 } PULSEAUDIOENUMCBCTX, *PPULSEAUDIOENUMCBCTX; 146 } PULSEAUDIOSTREAM; 147 /** Pointer to pulse audio stream data. */ 148 typedef PULSEAUDIOSTREAM *PPULSEAUDIOSTREAM; 149 150 151 /** 152 * Pulse audio host audio driver instance data. 153 * @implements PDMIAUDIOCONNECTOR 154 */ 155 typedef struct DRVHOSTPULSEAUDIO 156 { 157 /** Pointer to the driver instance structure. */ 158 PPDMDRVINS pDrvIns; 159 /** Pointer to PulseAudio's threaded main loop. */ 160 pa_threaded_mainloop *pMainLoop; 161 /** 162 * Pointer to our PulseAudio context. 163 * @note We use a pMainLoop in a separate thread (pContext). 164 * So either use callback functions or protect these functions 165 * by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock(). 166 */ 167 pa_context *pContext; 168 /** Shutdown indicator. */ 169 volatile bool fAbortLoop; 170 /** Error count for not flooding the release log. 171 * Specify UINT32_MAX for unlimited logging. */ 172 uint32_t cLogErrors; 173 /** The stream (base) name; needed for distinguishing 174 * streams in the PulseAudio mixer controls if multiple 175 * VMs are running at the same time. */ 176 char szStreamName[64]; 177 /** Don't want to put this on the stack... */ 178 PULSEAUDIOSTATECHGCTX InitStateChgCtx; 179 /** Pointer to host audio interface. */ 180 PDMIHOSTAUDIO IHostAudio; 181 } DRVHOSTPULSEAUDIO; 163 182 164 183 … … 212 231 static void drvHostAudioPaSignalWaiter(PDRVHOSTPULSEAUDIO pThis) 213 232 { 214 if ( !pThis)215 return;216 217 pThis->fAbortLoop = true;218 pa_threaded_mainloop_signal(pThis->pMainLoop, 0);233 if (pThis) 234 { 235 pThis->fAbortLoop = true; 236 pa_threaded_mainloop_signal(pThis->pMainLoop, 0); 237 } 219 238 } 220 239 … … 276 295 while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING) 277 296 { 278 if (!pThis->fAbortLoop) 297 if (!pThis->fAbortLoop) /** @todo r=bird: I do _not_ get the logic behind this fAbortLoop mechanism, it looks more 298 * than a little mixed up and too much generalized see drvHostAudioPaSignalWaiter. */ 279 299 { 280 300 AssertPtr(pThis->pMainLoop); … … 283 303 || pa_context_get_state(pThis->pContext) != PA_CONTEXT_READY) 284 304 { 305 pa_operation_cancel(pOP); 285 306 LogRel(("PulseAudio: pa_context_get_state context not ready\n")); 307 rc = VERR_INVALID_STATE; 286 308 break; 287 309 } … … 292 314 if (u64ElapsedMs >= cMsTimeout) 293 315 { 316 pa_operation_cancel(pOP); 294 317 rc = VERR_TIMEOUT; 295 318 break; … … 309 332 310 333 311 static void drvHostAudioPaEnumSinkCallback(pa_context *pCtx, const pa_sink_info *pInfo, int eol, void *pvUserData) 312 { 313 if (eol > 0) 314 return; 315 334 335 /********************************************************************************************************************************* 336 * PDMIHOSTAUDIO * 337 *********************************************************************************************************************************/ 338 339 /** 340 * Enumeration callback - source info. 341 * 342 * @param pCtx The context (DRVHOSTPULSEAUDIO::pContext). 343 * @param pInfo The info. NULL when @a eol is not zero. 344 * @param eol Error-or-last indicator or something like that: 345 * - 0: Normal call with info. 346 * - 1: End of list, no info. 347 * - -1: Error callback, no info. 348 */ 349 static void drvHostAudioPaEnumSourceCallback(pa_context *pCtx, const pa_source_info *pInfo, int eol, void *pvUserData) 350 { 351 LogFlowFunc(("pCtx=%p pInfo=%p eol=%d pvUserData=%p\n", pCtx, pInfo, eol, pvUserData)); 316 352 PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData; 317 353 AssertPtrReturnVoid(pCbCtx); 318 PDRVHOSTPULSEAUDIO pThis = pCbCtx->pDrv; 319 AssertPtrReturnVoid(pThis); 320 if (eol < 0) 321 { 322 pThis->fEnumOpSuccess = false; 323 pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0); 324 return; 325 } 326 327 AssertPtrReturnVoid(pCtx); 328 AssertPtrReturnVoid(pInfo); 329 330 LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name)); 331 332 /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */ 333 pCbCtx->cDevOut++; 334 335 pThis->fEnumOpSuccess = true; 336 pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0); 337 } 338 339 340 static void drvHostAudioPaEnumSourceCallback(pa_context *pCtx, const pa_source_info *pInfo, int eol, void *pvUserData) 341 { 342 if (eol > 0) 343 return; 344 354 Assert((pInfo == NULL) == (eol != 0)); 355 RT_NOREF(pCtx); 356 357 if (eol == 0 && pInfo != NULL) 358 { 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++; 362 pCbCtx->rcEnum = VINF_SUCCESS; 363 } 364 365 /* Wake up the calling thread when done: */ 366 if (eol != 0) 367 pa_threaded_mainloop_signal(pCbCtx->pMainLoop, 0); 368 } 369 370 371 /** 372 * Enumeration callback - sink info. 373 * 374 * @param pCtx The context (DRVHOSTPULSEAUDIO::pContext). 375 * @param pInfo The info. NULL when @a eol is not zero. 376 * @param eol Error-or-last indicator or something like that: 377 * - 0: Normal call with info. 378 * - 1: End of list, no info. 379 * - -1: Error callback, no info. 380 */ 381 static void drvHostAudioPaEnumSinkCallback(pa_context *pCtx, const pa_sink_info *pInfo, int eol, void *pvUserData) 382 { 383 LogFlowFunc(("pCtx=%p pInfo=%p eol=%d pvUserData=%p\n", pCtx, pInfo, eol, pvUserData)); 345 384 PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData; 346 385 AssertPtrReturnVoid(pCbCtx); 347 PDRVHOSTPULSEAUDIO pThis = pCbCtx->pDrv;348 AssertPtrReturnVoid(pThis);349 if (eol < 0) 350 {351 pThis->fEnumOpSuccess = false;352 pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0);353 return;354 }355 356 AssertPtrReturnVoid(pCtx);357 AssertPtrReturnVoid(pInfo); 358 359 LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name));360 361 /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */ 362 pCbCtx->cDevIn++; 363 364 pThis->fEnumOpSuccess = true; 365 pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0);366 } 367 368 386 Assert((pInfo == NULL) == (eol != 0)); 387 RT_NOREF(pCtx); 388 389 if (eol == 0 && pInfo != NULL) 390 { 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++; 394 pCbCtx->rcEnum = VINF_SUCCESS; 395 } 396 397 /* Wake up the calling thread when done: */ 398 if (eol != 0) 399 pa_threaded_mainloop_signal(pCbCtx->pMainLoop, 0); 400 } 401 402 403 /** 404 * Enumeration callback - service info. 405 * 406 * Copy down the default names. 407 */ 369 408 static void drvHostAudioPaEnumServerCallback(pa_context *pCtx, const pa_server_info *pInfo, void *pvUserData) 370 409 { 371 AssertPtrReturnVoid(pCtx);410 LogFlowFunc(("pCtx=%p pInfo=%p pvUserData=%p\n", pCtx, pInfo, pvUserData)); 372 411 PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData; 373 412 AssertPtrReturnVoid(pCbCtx); 374 PDRVHOSTPULSEAUDIO pThis = pCbCtx->pDrv; 375 AssertPtrReturnVoid(pThis); 376 377 if (!pInfo) 378 { 379 pThis->fEnumOpSuccess = false; 380 pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0); 381 return; 382 } 383 384 if (pInfo->default_sink_name) 385 { 386 Assert(RTStrIsValidEncoding(pInfo->default_sink_name)); 387 pCbCtx->pszDefaultSink = RTStrDup(pInfo->default_sink_name); 388 } 389 390 if (pInfo->default_sink_name) 391 { 392 Assert(RTStrIsValidEncoding(pInfo->default_source_name)); 393 pCbCtx->pszDefaultSource = RTStrDup(pInfo->default_source_name); 394 } 395 396 pThis->fEnumOpSuccess = true; 397 pa_threaded_mainloop_signal(pThis->pMainLoop, 0); 398 } 399 400 413 RT_NOREF(pCtx); 414 415 if (pInfo) 416 { 417 LogRel2(("PulseAudio: Server info: user=%s host=%s ver=%s name=%s defsink=%s defsrc=%s spec: %d %uHz %uch\n", 418 pInfo->user_name, pInfo->host_name, pInfo->server_version, pInfo->server_name, 419 pInfo->default_sink_name, pInfo->default_source_name, 420 pInfo->sample_spec.format, pInfo->sample_spec.rate, pInfo->sample_spec.channels)); 421 422 pCbCtx->rcEnum = VINF_SUCCESS; 423 424 if (pInfo->default_sink_name) 425 { 426 Assert(RTStrIsValidEncoding(pInfo->default_sink_name)); 427 pCbCtx->pszDefaultSink = RTStrDup(pInfo->default_sink_name); 428 AssertStmt(pCbCtx->pszDefaultSink, pCbCtx->rcEnum = VERR_NO_STR_MEMORY); 429 } 430 431 if (pInfo->default_source_name) 432 { 433 Assert(RTStrIsValidEncoding(pInfo->default_source_name)); 434 pCbCtx->pszDefaultSource = RTStrDup(pInfo->default_source_name); 435 AssertStmt(pCbCtx->pszDefaultSource, pCbCtx->rcEnum = VERR_NO_STR_MEMORY); 436 } 437 } 438 else 439 pCbCtx->rcEnum = VERR_INVALID_POINTER; 440 441 pa_threaded_mainloop_signal(pCbCtx->pMainLoop, 0); 442 } 443 444 445 /** 446 * @note Called with the PA main loop locked. 447 */ 401 448 static int drvHostAudioPaEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum) 402 449 { 403 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 404 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 405 406 PDMAUDIOBACKENDCFG Cfg; 407 RT_ZERO(Cfg); 408 409 RTStrPrintf2(Cfg.szName, sizeof(Cfg.szName), "PulseAudio"); 410 411 Cfg.cbStreamOut = sizeof(PULSEAUDIOSTREAM); 412 Cfg.cbStreamIn = sizeof(PULSEAUDIOSTREAM); 413 Cfg.cMaxStreamsOut = UINT32_MAX; 414 Cfg.cMaxStreamsIn = UINT32_MAX; 415 416 PULSEAUDIOENUMCBCTX CbCtx; 417 RT_ZERO(CbCtx); 418 419 CbCtx.pDrv = pThis; 420 CbCtx.fFlags = fEnum; 421 422 bool fLog = (fEnum & PULSEAUDIOENUMCBFLAGS_LOG); 423 424 pa_threaded_mainloop_lock(pThis->pMainLoop); 425 426 pThis->fEnumOpSuccess = false; 427 450 PULSEAUDIOENUMCBCTX CbCtx = { pThis, pThis->pMainLoop, fEnum, VERR_AUDIO_BACKEND_INIT_FAILED, 0, 0, NULL, NULL }; 451 bool const fLog = (fEnum & PULSEAUDIOENUMCBFLAGS_LOG); 452 int rc; 453 454 /* 455 * Check if server information is available and bail out early if it isn't. 456 * This should give us a default (playback) sink and (recording) source. 457 */ 428 458 LogRel(("PulseAudio: Retrieving server information ...\n")); 429 430 /* Check if server information is available and bail out early if it isn't. */ 459 CbCtx.rcEnum = VERR_AUDIO_BACKEND_INIT_FAILED; 431 460 pa_operation *paOpServerInfo = pa_context_get_server_info(pThis->pContext, drvHostAudioPaEnumServerCallback, &CbCtx); 432 if ( !paOpServerInfo)433 {434 pa_threaded_mainloop_unlock(pThis->pMainLoop);435 436 LogRel(("PulseAudio: Server information not available, skipping enumeration \n"));461 if (paOpServerInfo) 462 rc = drvHostAudioPaWaitFor(pThis, paOpServerInfo); 463 else 464 { 465 LogRel(("PulseAudio: Server information not available, skipping enumeration.\n")); 437 466 return VINF_SUCCESS; 438 467 } 439 440 int rc = drvHostAudioPaWaitFor(pThis, paOpServerInfo);441 if (RT_SUCCESS(rc) && !pThis->fEnumOpSuccess)442 rc = VERR_AUDIO_BACKEND_INIT_FAILED; /* error code does not matter */443 468 if (RT_SUCCESS(rc)) 444 { 445 if (CbCtx.pszDefaultSink) 446 { 447 if (fLog) 448 LogRel2(("PulseAudio: Default output sink is '%s'\n", CbCtx.pszDefaultSink)); 449 450 pThis->fEnumOpSuccess = false; 451 rc = drvHostAudioPaWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, CbCtx.pszDefaultSink, 452 drvHostAudioPaEnumSinkCallback, &CbCtx)); 453 if (RT_SUCCESS(rc) && !pThis->fEnumOpSuccess) 454 rc = VERR_AUDIO_BACKEND_INIT_FAILED; /* error code does not matter */ 455 if ( RT_FAILURE(rc) 456 && fLog) 457 { 458 LogRel(("PulseAudio: Error enumerating properties for default output sink '%s'\n", CbCtx.pszDefaultSink)); 459 } 460 } 461 else if (fLog) 462 LogRel2(("PulseAudio: No default output sink found\n")); 463 469 rc = CbCtx.rcEnum; 470 if (RT_FAILURE(rc)) 471 { 472 if (fLog) 473 LogRel(("PulseAudio: Error enumerating PulseAudio server properties: %Rrc\n", rc)); 474 return rc; 475 } 476 477 /* 478 * Get info about the playback sink. 479 */ 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)); 464 487 if (RT_SUCCESS(rc)) 465 { 466 if (CbCtx.pszDefaultSource) 467 { 468 if (fLog) 469 LogRel2(("PulseAudio: Default input source is '%s'\n", CbCtx.pszDefaultSource)); 470 471 pThis->fEnumOpSuccess = false; 472 rc = drvHostAudioPaWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, CbCtx.pszDefaultSource, 473 drvHostAudioPaEnumSourceCallback, &CbCtx)); 474 if ( (RT_FAILURE(rc) || !pThis->fEnumOpSuccess) 475 && fLog) 476 { 477 LogRel(("PulseAudio: Error enumerating properties for default input source '%s'\n", CbCtx.pszDefaultSource)); 478 } 479 } 480 else if (fLog) 481 LogRel2(("PulseAudio: No default input source found\n")); 482 } 483 488 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")); 500 501 /* 502 * Get info about the recording source. 503 */ 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, 510 drvHostAudioPaEnumSourceCallback, &CbCtx)); 511 if (RT_SUCCESS(rc2)) 512 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 } 484 521 if (RT_SUCCESS(rc)) 485 { 486 if (fLog) 487 { 488 LogRel2(("PulseAudio: Found %RU8 host playback device(s)\n", CbCtx.cDevOut)); 489 LogRel2(("PulseAudio: Found %RU8 host capturing device(s)\n", CbCtx.cDevIn)); 490 } 491 492 if (pCfg) 493 memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG)); 494 } 495 496 if (CbCtx.pszDefaultSink) 497 { 498 RTStrFree(CbCtx.pszDefaultSink); 499 CbCtx.pszDefaultSink = NULL; 500 } 501 502 if (CbCtx.pszDefaultSource) 503 { 504 RTStrFree(CbCtx.pszDefaultSource); 505 CbCtx.pszDefaultSource = NULL; 506 } 522 rc = rc2; 507 523 } 508 524 else if (fLog) 509 LogRel(("PulseAudio: Error enumerating PulseAudio server properties\n")); 510 511 pa_threaded_mainloop_unlock(pThis->pMainLoop); 525 LogRel2(("PulseAudio: No default input source found\n")); 526 527 /** @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! */ 530 RT_NOREF(pCfg); 531 532 /* clean up */ 533 RTStrFree(CbCtx.pszDefaultSink); 534 RTStrFree(CbCtx.pszDefaultSource); 512 535 513 536 LogFlowFuncLeaveRC(rc); … … 524 547 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER); 525 548 526 return drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG /* fEnum */); 549 /* Basic init: */ 550 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "PulseAudio"); 551 pBackendCfg->cbStreamOut = sizeof(PULSEAUDIOSTREAM); 552 pBackendCfg->cbStreamIn = sizeof(PULSEAUDIOSTREAM); 553 pBackendCfg->cMaxStreamsOut = UINT32_MAX; 554 pBackendCfg->cMaxStreamsIn = UINT32_MAX; 555 556 /* Refine it or something (currently only some LogRel2 stuff): */ 557 pa_threaded_mainloop_lock(pThis->pMainLoop); 558 int rc = drvHostAudioPaEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG /* fEnum */); 559 pa_threaded_mainloop_unlock(pThis->pMainLoop); 560 return rc; 527 561 } 528 562
Note:
See TracChangeset
for help on using the changeset viewer.