Changeset 89450 in vbox for trunk/src/VBox
- Timestamp:
- Jun 1, 2021 11:55:53 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144804
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioAlsa.cpp
r89449 r89450 93 93 unsigned long period_size; 94 94 /** For playback: Starting to play threshold (in audio frames). 95 * For Capturing: Starting to capture threshold (in audio frames).*/95 * For Capturing: ~~Starting to capture threshold (in audio frames)~~ !nothing! */ 96 96 unsigned long threshold; 97 97 … … 404 404 { 405 405 AssertReturn(cChannels > 0, VERR_INVALID_PARAMETER); 406 AssertReturn(cChannels < 16, VERR_INVALID_PARAMETER);406 AssertReturn(cChannels < PDMAUDIO_MAX_CHANNELS, VERR_INVALID_PARAMETER); 407 407 switch (fmt) 408 408 { … … 458 458 * 459 459 * @returns 0 on success, negative errno on failure. 460 * @param hPCM ALSA stream to set software parameters for. 461 * @param fIn Whether this is an input stream or not. 462 * @param pCfgReq Requested configuration to set. 463 * @param pCfgObt Obtained configuration on success. Might differ from requested configuration. 464 */ 465 static int alsaStreamSetSWParams(snd_pcm_t *hPCM, bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt) 460 * @param hPCM ALSA stream to set software parameters for. 461 * @param fIn Whether this is an input stream or not. 462 * @param pAlsaCfgReq Requested configuration to set (ALSA). 463 * @param pAlsaCfgObt Obtained configuration on success (ALSA). 464 * Might differ from requested configuration. 465 */ 466 static int alsaStreamSetSWParams(snd_pcm_t *hPCM, bool fIn, PALSAAUDIOSTREAMCFG pAlsaCfgReq, PALSAAUDIOSTREAMCFG pAlsaCfgObt) 466 467 { 467 468 if (fIn) /* For input streams there's nothing to do in here right now. */ … … 479 480 one continuous chunk when we should start playing. But since it is 480 481 configurable, we'll set a reasonable minimum of two DMA periods or 481 max 64 milliseconds (the p CfgReq->threshold value).482 max 64 milliseconds (the pAlsaCfgReq->threshold value). 482 483 483 484 Of course we also have to make sure the threshold is below the buffer 484 485 size, or ALSA will never start playing. */ 485 unsigned long cFramesThreshold = RT_MIN(p CfgObt->period_size * 2, pCfgReq->threshold);486 if (cFramesThreshold >= p CfgObt->buffer_size - pCfgObt->buffer_size / 16)487 cFramesThreshold = p CfgObt->buffer_size - pCfgObt->buffer_size / 16;486 unsigned long cFramesThreshold = RT_MIN(pAlsaCfgObt->period_size * 2, pAlsaCfgReq->threshold); 487 if (cFramesThreshold >= pAlsaCfgObt->buffer_size - pAlsaCfgObt->buffer_size / 16) 488 cFramesThreshold = pAlsaCfgObt->buffer_size - pAlsaCfgObt->buffer_size / 16; 488 489 489 490 err = snd_pcm_sw_params_set_start_threshold(hPCM, pSWParms, cFramesThreshold); 490 491 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set software threshold to %lu: %s\n", cFramesThreshold, snd_strerror(err)), err); 491 492 492 err = snd_pcm_sw_params_set_avail_min(hPCM, pSWParms, pCfgReq->period_size); 493 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set available minimum to %lu: %s\n", pCfgReq->period_size, snd_strerror(err)), err); 493 err = snd_pcm_sw_params_set_avail_min(hPCM, pSWParms, pAlsaCfgReq->period_size); 494 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set available minimum to %lu: %s\n", 495 pAlsaCfgReq->period_size, snd_strerror(err)), err); 494 496 495 497 /* Commit the software parameters: */ … … 498 500 499 501 /* Get the actual parameters: */ 500 err = snd_pcm_sw_params_get_start_threshold(pSWParms, &p CfgObt->threshold);502 err = snd_pcm_sw_params_get_start_threshold(pSWParms, &pAlsaCfgObt->threshold); 501 503 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to get start threshold: %s\n", snd_strerror(err)), err); 502 504 503 505 LogRel2(("ALSA: SW params: %lu frames threshold, %lu frame avail minimum\n", 504 p CfgObt->threshold, pCfgReq->period_size));506 pAlsaCfgObt->threshold, pAlsaCfgReq->period_size)); 505 507 return 0; 506 508 } … … 511 513 * 512 514 * @returns 0 on success, negative errno on failure. 513 * @param hPCM ALSA stream to set software parameters for.514 * @param p CfgReq Requested configuration to set.515 * @param p CfgObt Obtained configuration on success. Might differ from516 * requested configuration.517 */ 518 static int alsaStreamSetHwParams(snd_pcm_t *hPCM, PALSAAUDIOSTREAMCFG p CfgReq, PALSAAUDIOSTREAMCFG pCfgObt)515 * @param hPCM ALSA stream to set software parameters for. 516 * @param pAlsaCfgReq Requested configuration to set (ALSA). 517 * @param pAlsaCfgObt Obtained configuration on success (ALSA). Might differ 518 * from requested configuration. 519 */ 520 static int alsaStreamSetHwParams(snd_pcm_t *hPCM, PALSAAUDIOSTREAMCFG pAlsaCfgReq, PALSAAUDIOSTREAMCFG pAlsaCfgObt) 519 521 { 520 522 /* … … 529 531 530 532 /* 531 * Modify them according to p CfgReq.532 * We update p CfgObt as we go for parameters set by "near" methods.533 * Modify them according to pAlsaCfgReq. 534 * We update pAlsaCfgObt as we go for parameters set by "near" methods. 533 535 */ 534 536 /* We'll use snd_pcm_writei/snd_pcm_readi: */ … … 537 539 538 540 /* Set the format, frequency and channel count. */ 539 err = snd_pcm_hw_params_set_format(hPCM, pHWParms, p CfgReq->fmt);540 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set audio format to %d: %s\n", p CfgReq->fmt, snd_strerror(err)), err);541 542 unsigned int uFreq = p CfgReq->freq;541 err = snd_pcm_hw_params_set_format(hPCM, pHWParms, pAlsaCfgReq->fmt); 542 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set audio format to %d: %s\n", pAlsaCfgReq->fmt, snd_strerror(err)), err); 543 544 unsigned int uFreq = pAlsaCfgReq->freq; 543 545 err = snd_pcm_hw_params_set_rate_near(hPCM, pHWParms, &uFreq, NULL /*dir*/); 544 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set frequency to %uHz: %s\n", p CfgReq->freq, snd_strerror(err)), err);545 p CfgObt->freq= uFreq;546 547 unsigned int cChannels = p CfgReq->cChannels;546 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set frequency to %uHz: %s\n", pAlsaCfgReq->freq, snd_strerror(err)), err); 547 pAlsaCfgObt->freq = uFreq; 548 549 unsigned int cChannels = pAlsaCfgReq->cChannels; 548 550 err = snd_pcm_hw_params_set_channels_near(hPCM, pHWParms, &cChannels); 549 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set number of channels to %d\n", p CfgReq->cChannels), err);550 p CfgObt->cChannels = cChannels;551 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set number of channels to %d\n", pAlsaCfgReq->cChannels), err); 552 pAlsaCfgObt->cChannels = cChannels; 551 553 552 554 /* The period size (reportedly frame count per hw interrupt): */ 553 555 int dir = 0; 554 snd_pcm_uframes_t minval = p CfgReq->period_size;556 snd_pcm_uframes_t minval = pAlsaCfgReq->period_size; 555 557 err = snd_pcm_hw_params_get_period_size_min(pHWParms, &minval, &dir); 556 558 AssertLogRelMsgReturn(err >= 0, ("ALSA: Could not determine minimal period size: %s\n", snd_strerror(err)), err); 557 559 558 snd_pcm_uframes_t period_size_f = p CfgReq->period_size;560 snd_pcm_uframes_t period_size_f = pAlsaCfgReq->period_size; 559 561 if (period_size_f < minval) 560 562 period_size_f = minval; 561 563 err = snd_pcm_hw_params_set_period_size_near(hPCM, pHWParms, &period_size_f, 0); 562 LogRel2(("ALSA: Period size is: %lu frames (min %lu, requested %lu)\n", period_size_f, minval, p CfgReq->period_size));564 LogRel2(("ALSA: Period size is: %lu frames (min %lu, requested %lu)\n", period_size_f, minval, pAlsaCfgReq->period_size)); 563 565 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set period size %d (%s)\n", period_size_f, snd_strerror(err)), err); 564 566 565 567 /* The buffer size: */ 566 minval = p CfgReq->buffer_size;568 minval = pAlsaCfgReq->buffer_size; 567 569 err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval); 568 570 AssertLogRelMsgReturn(err >= 0, ("ALSA: Could not retrieve minimal buffer size: %s\n", snd_strerror(err)), err); 569 571 570 snd_pcm_uframes_t buffer_size_f = p CfgReq->buffer_size;572 snd_pcm_uframes_t buffer_size_f = pAlsaCfgReq->buffer_size; 571 573 if (buffer_size_f < minval) 572 574 buffer_size_f = minval; 573 575 err = snd_pcm_hw_params_set_buffer_size_near(hPCM, pHWParms, &buffer_size_f); 574 LogRel2(("ALSA: Buffer size is: %lu frames (min %lu, requested %lu)\n", buffer_size_f, minval, p CfgReq->buffer_size));576 LogRel2(("ALSA: Buffer size is: %lu frames (min %lu, requested %lu)\n", buffer_size_f, minval, pAlsaCfgReq->buffer_size)); 575 577 AssertLogRelMsgReturn(err >= 0, ("ALSA: Failed to set near buffer size %RU32: %s\n", buffer_size_f, snd_strerror(err)), err); 576 578 … … 582 584 583 585 /* 584 * Get relevant parameters and put them in the p CfgObt structure.586 * Get relevant parameters and put them in the pAlsaCfgObt structure. 585 587 */ 586 588 snd_pcm_uframes_t obt_buffer_size = buffer_size_f; 587 589 err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size); 588 590 AssertLogRelMsgStmt(err >= 0, ("ALSA: Failed to get buffer size: %s\n", snd_strerror(err)), obt_buffer_size = buffer_size_f); 589 p CfgObt->buffer_size = obt_buffer_size;591 pAlsaCfgObt->buffer_size = obt_buffer_size; 590 592 591 593 snd_pcm_uframes_t obt_period_size = period_size_f; 592 594 err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir); 593 595 AssertLogRelMsgStmt(err >= 0, ("ALSA: Failed to get period size: %s\n", snd_strerror(err)), obt_period_size = period_size_f); 594 p CfgObt->period_size = obt_period_size;595 596 // p CfgObt->access = pCfgReq->access; - unused and uninitialized.597 p CfgObt->fmt = pCfgReq->fmt;596 pAlsaCfgObt->period_size = obt_period_size; 597 598 // pAlsaCfgObt->access = pAlsaCfgReq->access; - unused and uninitialized. 599 pAlsaCfgObt->fmt = pAlsaCfgReq->fmt; 598 600 599 601 LogRel2(("ALSA: HW params: %u Hz, %lu frames period, %lu frames buffer, %u channel(s), fmt=%d, access=%d\n", 600 pCfgObt->freq, pCfgObt->period_size, pCfgObt->buffer_size, pCfgObt->cChannels, pCfgObt->fmt, -1 /*pCfgObt->access*/)); 602 pAlsaCfgObt->freq, pAlsaCfgObt->period_size, pAlsaCfgObt->buffer_size, pAlsaCfgObt->cChannels, 603 pAlsaCfgObt->fmt, -1 /*pAlsaCfgObt->access*/)); 601 604 return 0; 602 605 } … … 607 610 * 608 611 * @returns VBox status code. 609 * @param pszDev The name of the device to open. 610 * @param fIn Whether this is an input stream to create or not. 611 * @param pCfgReq Requested configuration to create stream with. 612 * @param pCfgObt Obtained configuration the stream got created on success. 613 * @param phPCM Where to store the ALSA stream handle on success. 614 */ 615 static int alsaStreamOpen(const char *pszDev, bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, 616 PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **phPCM) 612 * @param pszDev The name of the device to open. 613 * @param fIn Whether this is an input stream to create or not. 614 * @param pAlsaCfgReq Requested configuration to create stream with (ALSA). 615 * @param pCfgReq Requested configuration to create stream with (PDM). 616 * @param pAlsaCfgObt Obtained configuration the stream got created on 617 * success. 618 * @param phPCM Where to store the ALSA stream handle on success. 619 */ 620 static int alsaStreamOpen(const char *pszDev, bool fIn, PALSAAUDIOSTREAMCFG pAlsaCfgReq, PPDMAUDIOSTREAMCFG pCfgReq, 621 PALSAAUDIOSTREAMCFG pAlsaCfgObt, snd_pcm_t **phPCM) 617 622 { 618 623 AssertLogRelMsgReturn(pszDev && *pszDev, 619 624 ("ALSA: Invalid or no %s device name set\n", fIn ? "input" : "output"), 620 625 VERR_INVALID_NAME); 626 RT_NOREF(pCfgReq); 621 627 622 628 /* … … 637 643 * Configure hardware stream parameters. 638 644 */ 639 err = alsaStreamSetHwParams(hPCM, p CfgReq, pCfgObt);645 err = alsaStreamSetHwParams(hPCM, pAlsaCfgReq, pAlsaCfgObt); 640 646 if (err >= 0) 641 647 { … … 650 656 * Configure software stream parameters and we're done. 651 657 */ 652 rc = alsaStreamSetSWParams(hPCM, fIn, p CfgReq, pCfgObt);658 rc = alsaStreamSetSWParams(hPCM, fIn, pAlsaCfgReq, pAlsaCfgObt); 653 659 if (RT_SUCCESS(rc)) 654 660 { … … 673 679 674 680 /** 675 * Creates an ALSA output stream. 676 * 677 * @returns VBox status code. 678 * @param pThis The ALSA driver instance data. 679 * @param pStreamALSA ALSA output stream to create. 680 * @param pCfgReq Requested configuration to create stream with. 681 * @param pCfgAcq Obtained configuration the stream got created 682 * with on success. 683 */ 684 static int alsaCreateStreamOut(PDRVHOSTALSAAUDIO pThis, PALSAAUDIOSTREAM pStreamALSA, 685 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 686 { 681 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 682 */ 683 static DECLCALLBACK(int) drvHostAlsaAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 684 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 685 { 686 PDRVHOSTALSAAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTALSAAUDIO, IHostAudio); 687 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 688 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 689 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 690 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 691 692 PALSAAUDIOSTREAM pStreamALSA = (PALSAAUDIOSTREAM)pStream; 693 PDMAudioStrmCfgCopy(&pStreamALSA->Cfg, pCfgReq); 694 687 695 ALSAAUDIOSTREAMCFG Req; 688 696 Req.fmt = alsaAudioPropsToALSA(&pCfgReq->Props); … … 692 700 Req.buffer_size = pCfgReq->Backend.cFramesBufferSize; 693 701 Req.threshold = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 50); 694 int rc = alsaStreamOpen(pThis->szDefaultOut, false /*fIn*/, &Req, &pStreamALSA->AlsaCfg, &pStreamALSA->hPCM); 702 int rc = alsaStreamOpen(pCfgReq->enmDir == PDMAUDIODIR_IN ? pThis->szDefaultIn : pThis->szDefaultOut, 703 pCfgReq->enmDir == PDMAUDIODIR_IN, 704 &Req, pCfgReq, &pStreamALSA->AlsaCfg, &pStreamALSA->hPCM); 695 705 if (RT_SUCCESS(rc)) 696 706 { … … 704 714 /* We have no objections to the pre-buffering that DrvAudio applies, 705 715 only we need to adjust it relative to the actual buffer size. */ 706 /** @todo DrvAudio should do this. */707 716 pCfgAcq->Backend.cFramesPreBuffering = (uint64_t)pCfgReq->Backend.cFramesPreBuffering 708 717 * pCfgAcq->Backend.cFramesBufferSize 709 718 / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1); 710 719 720 PDMAudioStrmCfgCopy(&pStreamALSA->Cfg, pCfgAcq); 711 721 LogFlowFunc(("returns success - hPCM=%p\n", pStreamALSA->hPCM)); 712 return VINF_SUCCESS;722 return rc; 713 723 } 714 724 alsaStreamClose(&pStreamALSA->hPCM); 715 725 } 716 LogFlowFuncLeaveRC(rc); 717 return rc; 718 } 719 720 721 /** 722 * Creates an ALSA input stream. 723 * 724 * @returns VBox status code. 725 * @param pThis The ALSA driver instance data. 726 * @param pStreamALSA ALSA input stream to create. 727 * @param pCfgReq Requested configuration to create stream with. 728 * @param pCfgAcq Obtained configuration the stream got created 729 * with on success. 730 */ 731 static int alsaCreateStreamIn(PDRVHOSTALSAAUDIO pThis, PALSAAUDIOSTREAM pStreamALSA, 732 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 733 { 734 ALSAAUDIOSTREAMCFG Req; 735 Req.fmt = alsaAudioPropsToALSA(&pCfgReq->Props); 736 Req.freq = PDMAudioPropsHz(&pCfgReq->Props); 737 Req.cChannels = PDMAudioPropsChannels(&pCfgReq->Props); 738 /** @todo r=bird: Isn't all this configurable already?!? */ 739 Req.period_size = PDMAudioPropsMilliToFrames(&pCfgReq->Props, 50 /*ms*/); /** @todo Make this configurable. */ 740 Req.buffer_size = Req.period_size * 2; /** @todo Make this configurable. */ 741 Req.threshold = Req.period_size; 742 int rc = alsaStreamOpen(pThis->szDefaultIn, true /* fIn */, &Req, &pStreamALSA->AlsaCfg, &pStreamALSA->hPCM); 743 if (RT_SUCCESS(rc)) 744 { 745 rc = alsaALSAToAudioProps(&pCfgAcq->Props, pStreamALSA->AlsaCfg.fmt, pStreamALSA->AlsaCfg.cChannels, pStreamALSA->AlsaCfg.freq); 746 if (RT_SUCCESS(rc)) 747 { 748 pCfgAcq->Backend.cFramesPeriod = pStreamALSA->AlsaCfg.period_size; 749 pCfgAcq->Backend.cFramesBufferSize = pStreamALSA->AlsaCfg.buffer_size; 750 pCfgAcq->Backend.cFramesPreBuffering = 0; /* No pre-buffering. */ 751 return VINF_SUCCESS; 752 } 753 754 alsaStreamClose(&pStreamALSA->hPCM); 755 } 756 LogFlowFuncLeaveRC(rc); 757 return rc; 758 } 759 760 761 /** 762 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 763 */ 764 static DECLCALLBACK(int) drvHostAlsaAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 765 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 766 { 767 PDRVHOSTALSAAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTALSAAUDIO, IHostAudio); 768 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 769 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 770 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 771 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 772 773 PALSAAUDIOSTREAM pStreamALSA = (PALSAAUDIOSTREAM)pStream; 774 PDMAudioStrmCfgCopy(&pStreamALSA->Cfg, pCfgReq); 775 776 int rc; 777 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 778 rc = alsaCreateStreamIn( pThis, pStreamALSA, pCfgReq, pCfgAcq); 779 else 780 rc = alsaCreateStreamOut(pThis, pStreamALSA, pCfgReq, pCfgAcq); 781 if (RT_SUCCESS(rc)) 782 PDMAudioStrmCfgCopy(&pStreamALSA->Cfg, pCfgAcq); 726 LogFunc(("returns %Rrc\n", rc)); 783 727 return rc; 784 728 }
Note:
See TracChangeset
for help on using the changeset viewer.