Changeset 88220 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Mar 21, 2021 1:55:01 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143385
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
r88214 r88220 263 263 264 264 /** 265 * Closes an ALSA stream 266 * 267 * @returns VBox status code. 268 * @param pphPCM ALSA stream to close. 269 */ 270 static int alsaStreamClose(snd_pcm_t **pphPCM) 271 { 272 if (!pphPCM || !*pphPCM) 273 return VINF_SUCCESS; 274 275 int rc; 276 int rc2 = snd_pcm_close(*pphPCM); 277 if (rc2) 278 { 279 LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2))); 280 rc = VERR_GENERAL_FAILURE; /** @todo */ 281 } 282 else 283 { 284 *pphPCM = NULL; 285 rc = VINF_SUCCESS; 286 } 287 288 LogFlowFuncLeaveRC(rc); 289 return rc; 290 } 291 292 293 /** 265 294 * Sets the software parameters of an ALSA stream. 266 295 * 267 * @returns VBox status code.296 * @returns 0 on success, negative errno on failure. 268 297 * @param phPCM ALSA stream to set software parameters for. 269 298 * @param fIn Whether this is an input stream or not. … … 278 307 snd_pcm_sw_params_t *pSWParms = NULL; 279 308 snd_pcm_sw_params_alloca(&pSWParms); 280 if (!pSWParms) 281 return VERR_NO_MEMORY; 282 283 int rc; 284 do 285 { 286 int err = snd_pcm_sw_params_current(phPCM, pSWParms); 287 if (err < 0) 288 { 289 LogRel(("ALSA: Failed to get current software parameters: %s\n", snd_strerror(err))); 290 rc = VERR_ACCESS_DENIED; 291 break; 292 } 293 294 err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, pCfgReq->threshold); 295 if (err < 0) 296 { 297 LogRel(("ALSA: Failed to set software threshold to %ld: %s\n", pCfgReq->threshold, snd_strerror(err))); 298 rc = VERR_ACCESS_DENIED; 299 break; 300 } 301 302 err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, pCfgReq->period_size); 303 if (err < 0) 304 { 305 LogRel(("ALSA: Failed to set available minimum to %ld: %s\n", pCfgReq->threshold, snd_strerror(err))); 306 rc = VERR_ACCESS_DENIED; 307 break; 308 } 309 310 err = snd_pcm_sw_params(phPCM, pSWParms); 311 if (err < 0) 312 { 313 LogRel(("ALSA: Failed to set new software parameters: %s\n", snd_strerror(err))); 314 rc = VERR_ACCESS_DENIED; 315 break; 316 } 317 318 err = snd_pcm_sw_params_get_start_threshold(pSWParms, &pCfgObt->threshold); 319 if (err < 0) 320 { 321 LogRel(("ALSA: Failed to get start threshold\n")); 322 rc = VERR_ACCESS_DENIED; 323 break; 324 } 325 326 LogFunc(("Setting threshold to %RU32 frames\n", pCfgObt->threshold)); 327 rc = VINF_SUCCESS; 328 } 329 while (0); 330 331 return rc; 332 } 333 334 335 /** 336 * Closes an ALSA stream 337 * 338 * @returns VBox status code. 339 * @param pphPCM ALSA stream to close. 340 */ 341 static int alsaStreamClose(snd_pcm_t **pphPCM) 342 { 343 if (!pphPCM || !*pphPCM) 344 return VINF_SUCCESS; 345 346 int rc; 347 int rc2 = snd_pcm_close(*pphPCM); 348 if (rc2) 349 { 350 LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2))); 351 rc = VERR_GENERAL_FAILURE; /** @todo */ 352 } 353 else 354 { 355 *pphPCM = NULL; 356 rc = VINF_SUCCESS; 357 } 358 359 LogFlowFuncLeaveRC(rc); 360 return rc; 309 AssertReturn(pSWParms, -ENOMEM); 310 311 int err = snd_pcm_sw_params_current(phPCM, pSWParms); 312 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to get current software parameters: %s\n", snd_strerror(err)), err); 313 314 /* Must make sure we don't require ALSA to prebuffer more than 315 it has buffer space for, because that means output will 316 never start. */ 317 unsigned long cFramesPreBuffer = pCfgReq->threshold; 318 if (cFramesPreBuffer >= pCfgObt->buffer_size - pCfgObt->buffer_size / 16) 319 { 320 cFramesPreBuffer = pCfgObt->buffer_size - pCfgObt->buffer_size / 16; 321 LogRel2(("ALSA: Reducing threshold from %lu to %lu due to buffer size of %lu.\n", 322 pCfgReq->threshold, cFramesPreBuffer, pCfgObt->buffer_size)); 323 } 324 err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, cFramesPreBuffer); 325 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set software threshold to %lu: %s\n", cFramesPreBuffer, snd_strerror(err)), err); 326 327 err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, pCfgReq->period_size); 328 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set available minimum to %lu: %s\n", pCfgReq->period_size, snd_strerror(err)), err); 329 330 /* Commit the software parameters: */ 331 err = snd_pcm_sw_params(phPCM, pSWParms); 332 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set new software parameters: %s\n", snd_strerror(err)), err); 333 334 /* Get the actual parameters: */ 335 err = snd_pcm_sw_params_get_start_threshold(pSWParms, &pCfgObt->threshold); 336 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to get start threshold: %s\n", snd_strerror(err)), err); 337 338 LogRel2(("ALSA: SW params: %ul frames threshold, %ul frame avail minimum\n", 339 pCfgObt->threshold, pCfgReq->period_size)); 340 return 0; 341 } 342 343 344 /** 345 * Sets the hardware parameters of an ALSA stream. 346 * 347 * @returns 0 on success, negative errno on failure. 348 * @param phPCM ALSA stream to set software parameters for. 349 * @param pCfgReq Requested configuration to set. 350 * @param pCfgObt Obtained configuration on success. Might differ from 351 * requested configuration. 352 */ 353 static int alsaStreamSetHwParams(snd_pcm_t *phPCM, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt) 354 { 355 /* 356 * Get the current hardware parameters. 357 */ 358 snd_pcm_hw_params_t *pHWParms = NULL; 359 snd_pcm_hw_params_alloca(&pHWParms); 360 AssertReturn(pHWParms, -ENOMEM); 361 362 int err = snd_pcm_hw_params_any(phPCM, pHWParms); 363 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to initialize hardware parameters: %s\n", snd_strerror(err)), err); 364 365 /* 366 * Modify them according to pCfgReq. 367 * We update pCfgObt as we go for parameters set by "near" methods. 368 */ 369 /* We'll use snd_pcm_writei/snd_pcm_readi: */ 370 err = snd_pcm_hw_params_set_access(phPCM, pHWParms, SND_PCM_ACCESS_RW_INTERLEAVED); 371 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set access type: %s\n", snd_strerror(err)), err); 372 373 /* Set the format, frequency and channel count. */ 374 err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt); 375 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set audio format to %d: %s\n", pCfgReq->fmt, snd_strerror(err)), err); 376 377 unsigned int uFreq = pCfgReq->freq; 378 err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, NULL /*dir*/); 379 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set frequency to %uHz: %s\n", pCfgReq->freq, snd_strerror(err)), err); 380 pCfgObt->freq = uFreq; 381 382 unsigned int cChannels = pCfgReq->nchannels; 383 err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels); 384 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels), err); 385 AssertLogRelMsgReturn(cChannels == 1 || cChannels == 2, ("ALSA: Number of audio channels (%u) not supported\n", cChannels), -1); 386 pCfgObt->nchannels = cChannels; 387 388 /* The period size (reportedly frame count per hw interrupt): */ 389 int dir = 0; 390 snd_pcm_uframes_t minval = pCfgReq->period_size; 391 err = snd_pcm_hw_params_get_period_size_min(pHWParms, &minval, &dir); 392 AssertLogRelMsgReturn(err >= 0, ("ALSA: Could not determine minimal period size: %s\n", snd_strerror(err)), err); 393 394 snd_pcm_uframes_t period_size_f = pCfgReq->period_size; 395 if (period_size_f < minval) 396 period_size_f = minval; 397 err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms, &period_size_f, 0); 398 LogRel2(("ALSA: Period size is: %lu frames (min %lu, requested %lu)\n", period_size_f, minval, pCfgReq->period_size)); 399 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set period size %d (%s)\n", period_size_f, snd_strerror(err)), err); 400 401 /* The buffer size: */ 402 minval = pCfgReq->buffer_size; 403 err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval); 404 AssertLogRelMsgReturn(err >= 0, ("ALSA: Could not retrieve minimal buffer size: %s\n", snd_strerror(err)), err); 405 406 snd_pcm_uframes_t buffer_size_f = pCfgReq->buffer_size; 407 if (buffer_size_f < minval) 408 buffer_size_f = minval; 409 err = snd_pcm_hw_params_set_buffer_size_near(phPCM, pHWParms, &buffer_size_f); 410 LogRel2(("ALSA: Buffer size is: %lu frames (min %lu, requested %lu)\n", buffer_size_f, minval, pCfgReq->buffer_size)); 411 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set near buffer size %RU32: %s\n", buffer_size_f, snd_strerror(err)), err); 412 413 /* 414 * Set the hardware parameters. 415 */ 416 err = snd_pcm_hw_params(phPCM, pHWParms); 417 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to apply audio parameters: %s\n", snd_strerror(err)), err); 418 419 /* 420 * Get relevant parameters and put them in the pCfgObt structure. 421 */ 422 snd_pcm_uframes_t obt_buffer_size = buffer_size_f; 423 err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size); 424 AssertLogRelMsgStmt(err >= 0, ("ALSA: Failed to get buffer size: %s\n", snd_strerror(err)), obt_buffer_size = buffer_size_f); 425 pCfgObt->buffer_size = obt_buffer_size; 426 427 snd_pcm_uframes_t obt_period_size = period_size_f; 428 err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir); 429 AssertLogRelMsgStmt(err >= 0, ("ALSA: Failed to get period size: %s\n", snd_strerror(err)), obt_period_size = period_size_f); 430 pCfgObt->period_size = obt_period_size; 431 432 pCfgObt->access = pCfgReq->access; 433 pCfgObt->fmt = pCfgReq->fmt; 434 435 LogRel2(("ALSA: HW params: %u Hz, %ul frames period, %ul frames buffer, %u channel(s), fmt=%d, access=%d\n", 436 pCfgObt->freq, pCfgObt->period_size, pCfgObt->buffer_size, pCfgObt->nchannels, pCfgObt->fmt, pCfgObt->access)); 437 return 0; 361 438 } 362 439 … … 375 452 PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **pphPCM) 376 453 { 454 AssertLogRelMsgReturn(pszDev && *pszDev, 455 ("ALSA: Invalid or no %s device name set\n", fIn ? "input" : "output"), 456 VERR_INVALID_NAME); 457 458 /* 459 * Open the stream. 460 */ 461 int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 377 462 snd_pcm_t *phPCM = NULL; 378 379 int rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE; 380 381 unsigned int cChannels = pCfgReq->nchannels; 382 unsigned int uFreq = pCfgReq->freq; 383 snd_pcm_uframes_t obt_buffer_size; 384 385 do 386 { 387 AssertLogRelMsgReturn(pszDev && *pszDev, 388 ("ALSA: Invalid or no %s device name set\n", fIn ? "input" : "output"), 389 VERR_INVALID_NAME); 390 391 LogRel(("ALSA: Using %s device \"%s\"\n", fIn ? "input" : "output", pszDev)); 392 393 int err = snd_pcm_open(&phPCM, pszDev, 394 fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 395 SND_PCM_NONBLOCK); 396 if (err < 0) 397 { 398 LogRel(("ALSA: Failed to open \"%s\" as %s device: %s\n", pszDev, fIn ? "input" : "output", snd_strerror(err))); 399 break; 400 } 401 463 LogRel(("ALSA: Using %s device \"%s\"\n", fIn ? "input" : "output", pszDev)); 464 int err = snd_pcm_open(&phPCM, pszDev, 465 fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 466 SND_PCM_NONBLOCK); 467 if (err >= 0) 468 { 402 469 err = snd_pcm_nonblock(phPCM, 1); 403 if (err < 0) 404 { 405 LogRel(("ALSA: Error setting output non-blocking mode: %s\n", snd_strerror(err))); 406 break; 407 } 408 409 snd_pcm_hw_params_t *pHWParms; 410 snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */ 411 err = snd_pcm_hw_params_any(phPCM, pHWParms); 412 if (err < 0) 413 { 414 LogRel(("ALSA: Failed to initialize hardware parameters: %s\n", snd_strerror(err))); 415 break; 416 } 417 418 err = snd_pcm_hw_params_set_access(phPCM, pHWParms, SND_PCM_ACCESS_RW_INTERLEAVED); 419 if (err < 0) 420 { 421 LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err))); 422 break; 423 } 424 425 err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt); 426 if (err < 0) 427 { 428 LogRel(("ALSA: Failed to set audio format to %d: %s\n", pCfgReq->fmt, snd_strerror(err))); 429 break; 430 } 431 432 err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0); 433 if (err < 0) 434 { 435 LogRel(("ALSA: Failed to set frequency to %uHz: %s\n", pCfgReq->freq, snd_strerror(err))); 436 break; 437 } 438 439 err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels); 440 if (err < 0) 441 { 442 LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels)); 443 break; 444 } 445 446 if ( cChannels != 1 447 && cChannels != 2) 448 { 449 LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels)); 450 break; 451 } 452 453 snd_pcm_uframes_t period_size_f = pCfgReq->period_size; 454 snd_pcm_uframes_t buffer_size_f = pCfgReq->buffer_size; 455 456 snd_pcm_uframes_t minval = period_size_f; 457 458 int dir = 0; 459 err = snd_pcm_hw_params_get_period_size_min(pHWParms, &minval, &dir); 460 if (err < 0) 461 { 462 LogRel(("ALSA: Could not determine minimal period size\n")); 463 break; 470 if (err >= 0) 471 { 472 /* 473 * Configure hardware stream parameters. 474 */ 475 err = alsaStreamSetHwParams(phPCM, pCfgReq, pCfgObt); 476 if (err >= 0) 477 { 478 /* 479 * Prepare it. 480 */ 481 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 482 err = snd_pcm_prepare(phPCM); 483 if (err >= 0) 484 { 485 /* 486 * Configure software stream parameters and we're done. 487 */ 488 rc = alsaStreamSetSWParams(phPCM, fIn, pCfgReq, pCfgObt); 489 if (RT_SUCCESS(rc)) 490 { 491 *pphPCM = phPCM; 492 return VINF_SUCCESS; 493 } 494 } 495 else 496 LogRel(("ALSA: snd_pcm_prepare failed: %s\n", snd_strerror(err))); 497 } 464 498 } 465 499 else 466 { 467 LogFunc(("Minimal period size is: %ld\n", minval)); 468 if (period_size_f < minval) 469 period_size_f = minval; 470 } 471 472 err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms, &period_size_f, 0); 473 LogFunc(("Period size is: %RU32\n", period_size_f)); 474 if (err < 0) 475 { 476 LogRel(("ALSA: Failed to set period size %d (%s)\n", period_size_f, snd_strerror(err))); 477 break; 478 } 479 480 minval = buffer_size_f; 481 err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval); 482 if (err < 0) 483 { 484 LogRel(("ALSA: Could not retrieve minimal buffer size\n")); 485 break; 486 } 487 else 488 LogFunc(("Minimal buffer size is: %RU32\n", minval)); 489 490 err = snd_pcm_hw_params_set_buffer_size_near(phPCM, pHWParms, &buffer_size_f); 491 if (err < 0) 492 { 493 LogRel(("ALSA: Failed to set near buffer size %RU32: %s\n", buffer_size_f, snd_strerror(err))); 494 break; 495 } 496 497 err = snd_pcm_hw_params(phPCM, pHWParms); 498 if (err < 0) 499 { 500 LogRel(("ALSA: Failed to apply audio parameters\n")); 501 break; 502 } 503 504 err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size); 505 if (err < 0) 506 { 507 LogRel(("ALSA: Failed to get buffer size\n")); 508 break; 509 } 510 511 snd_pcm_uframes_t obt_period_size; 512 err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir); 513 if (err < 0) 514 { 515 LogRel(("ALSA: Failed to get period size\n")); 516 break; 517 } 518 519 LogRel2(("ALSA: Frequency is %dHz, period size is %RU32 frames, buffer size is %RU32 frames\n", 520 pCfgReq->freq, obt_period_size, obt_buffer_size)); 521 522 err = snd_pcm_prepare(phPCM); 523 if (err < 0) 524 { 525 LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM)); 526 rc = VERR_AUDIO_BACKEND_INIT_FAILED; 527 break; 528 } 529 530 rc = alsaStreamSetSWParams(phPCM, fIn, pCfgReq, pCfgObt); 531 if (RT_FAILURE(rc)) 532 break; 533 534 pCfgObt->fmt = pCfgReq->fmt; 535 pCfgObt->nchannels = cChannels; 536 pCfgObt->freq = uFreq; 537 pCfgObt->period_size = obt_period_size; 538 pCfgObt->buffer_size = obt_buffer_size; 539 540 rc = VINF_SUCCESS; 541 } 542 while (0); 543 544 if (RT_SUCCESS(rc)) 545 { 546 *pphPCM = phPCM; 500 LogRel(("ALSA: Error setting output non-blocking mode: %s\n", snd_strerror(err))); 501 alsaStreamClose(&phPCM); 547 502 } 548 503 else 549 alsaStreamClose(&phPCM); 550 551 LogFlowFuncLeaveRC(rc); 504 LogRel(("ALSA: Failed to open \"%s\" as %s device: %s\n", pszDev, fIn ? "input" : "output", snd_strerror(err))); 552 505 return rc; 553 506 } … … 813 766 const void *pvBuf, uint32_t uBufSize, uint32_t *puWritten) 814 767 { 768 PALSAAUDIOSTREAM pStreamALSA = (PALSAAUDIOSTREAM)pStream; 815 769 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 816 770 AssertPtrReturn(pStream, VERR_INVALID_POINTER); … … 818 772 AssertReturn(uBufSize, VERR_INVALID_PARAMETER); 819 773 /* puWritten is optional. */ 820 821 PALSAAUDIOSTREAM pStreamALSA = (PALSAAUDIOSTREAM)pStream;774 Log4Func(("pvBuf=%p uBufSize=%#x (%u) state=%s - %s\n", pvBuf, uBufSize, uBufSize, 775 snd_pcm_state_name(snd_pcm_state(pStreamALSA->phPCM)), pStreamALSA->pCfg->szName)); 822 776 823 777 PPDMAUDIOSTREAMCFG pCfg = pStreamALSA->pCfg; … … 859 813 csWritten = snd_pcm_writei(pStreamALSA->phPCM, pStreamALSA->pvBuf, 860 814 PDMAUDIOSTREAMCFG_B2F(pCfg, cbToWrite)); 815 Log4Func(("snd_pcm_writei w/ cbToWrite=%u -> %ld (frames) [csAvail=%ld]\n", cbToWrite, csWritten, csAvail)); 861 816 if (csWritten <= 0) 862 817 { -
trunk/src/VBox/Devices/Audio/alsa_mangling.h
r82968 r88220 45 45 #define snd_pcm_start ALSA_MANGLER(snd_pcm_start) 46 46 #define snd_pcm_state ALSA_MANGLER(snd_pcm_state) 47 #define snd_pcm_state_name ALSA_MANGLER(snd_pcm_state_name) 47 48 #define snd_pcm_writei ALSA_MANGLER(snd_pcm_writei) 48 49 -
trunk/src/VBox/Devices/Audio/alsa_stubs.c
r82968 r88220 73 73 PROXY_STUB(snd_pcm_resume, int, (snd_pcm_t *pcm), (pcm)) 74 74 PROXY_STUB(snd_pcm_state, snd_pcm_state_t, (snd_pcm_t *pcm), (pcm)) 75 PROXY_STUB(snd_pcm_state_name, const char *, (snd_pcm_state_t state), (state)) 75 76 PROXY_STUB(snd_pcm_writei, snd_pcm_sframes_t, 76 77 (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size), … … 173 174 ELEMENT(snd_pcm_resume), 174 175 ELEMENT(snd_pcm_state), 176 ELEMENT(snd_pcm_state_name), 175 177 176 178 ELEMENT(snd_pcm_readi),
Note:
See TracChangeset
for help on using the changeset viewer.