Changeset 89371 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 28, 2021 8:52:58 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144722
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
r89354 r89371 922 922 923 923 /** 924 * Destroys (uninitializes) a mixing buffer.924 * Terminates (uninitializes) a mixing buffer. 925 925 * 926 926 * @param pMixBuf The mixing buffer. Uninitialized mixer buffers will be 927 927 * quietly ignored. As will NULL. 928 928 */ 929 void AudioMixBuf Destroy(PAUDIOMIXBUF pMixBuf)929 void AudioMixBufTerm(PAUDIOMIXBUF pMixBuf) 930 930 { 931 931 if (!pMixBuf) -
trunk/src/VBox/Devices/Audio/AudioMixBuffer.h
r89352 r89371 182 182 183 183 int AudioMixBufInit(PAUDIOMIXBUF pMixBuf, const char *pszName, PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames); 184 void AudioMixBuf Destroy(PAUDIOMIXBUF pMixBuf);184 void AudioMixBufTerm(PAUDIOMIXBUF pMixBuf); 185 185 void AudioMixBufDrop(PAUDIOMIXBUF pMixBuf); 186 186 void AudioMixBufSetVolume(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOVOLUME pVol); -
trunk/src/VBox/Devices/Audio/AudioMixer.cpp
r89357 r89371 104 104 static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink, PPDMDEVINS pDevIns); 105 105 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster); 106 static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink);107 106 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 108 static void audioMixerSinkReset (PAUDMIXSINK pSink);107 static void audioMixerSinkResetInternal(PAUDMIXSINK pSink); 109 108 110 109 static int audioMixerStreamCtlInternal(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd); … … 234 233 RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node) 235 234 { 235 audioMixerRemoveSinkInternal(pMixer, pSink); 236 236 audioMixerSinkDestroyInternal(pSink, pDevIns); 237 audioMixerRemoveSinkInternal(pMixer, pSink);238 RTMemFree(pSink);239 237 } 240 238 Assert(pMixer->cSinks == 0); … … 454 452 455 453 /** 456 * Adds an audio stream to a specific audio sink.457 *458 * @returns VBox status code.459 * @param pSink Sink to add audio stream to.460 * @param pStream Stream to add.461 */462 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)463 {464 LogFlowFuncEnter();465 AssertPtrReturn(pSink, VERR_INVALID_POINTER);466 Assert(pSink->uMagic == AUDMIXSINK_MAGIC);467 AssertPtrReturn(pStream, VERR_INVALID_POINTER);468 Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC);469 AssertPtrReturn(pStream->pConn, VERR_AUDIO_STREAM_NOT_READY);470 AssertReturn(pStream->pSink == NULL, VERR_ALREADY_EXISTS);471 472 int rc = RTCritSectEnter(&pSink->CritSect);473 AssertRCReturn(rc, rc);474 475 AssertLogRelMsgReturnStmt(pSink->cStreams < UINT8_MAX, ("too many streams!\n"), RTCritSectLeave(&pSink->CritSect),476 VERR_TOO_MANY_OPEN_FILES);477 478 /*479 * If the sink is running and not in pending disable mode, make sure that480 * the added stream also is enabled. Ignore any failure to enable it.481 */482 if ( (pSink->fStatus & AUDMIXSINK_STS_RUNNING)483 && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING))484 {485 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE);486 }487 488 /* Save pointer to sink the stream is attached to. */489 pStream->pSink = pSink;490 491 /* Append stream to sink's list. */492 RTListAppend(&pSink->lstStreams, &pStream->Node);493 pSink->cStreams++;494 495 LogFlowFunc(("[%s] cStreams=%RU8, rc=%Rrc\n", pSink->pszName, pSink->cStreams, rc));496 RTCritSectLeave(&pSink->CritSect);497 return rc;498 }499 500 /**501 * Creates an audio mixer stream.502 *503 * @returns VBox status code.504 * @param pSink Sink to use for creating the stream.505 * @param pConn Audio connector interface to use.506 * @param pCfg Audio stream configuration to use. This may be modified507 * in some unspecified way (see508 * PDMIAUDIOCONNECTOR::pfnStreamCreate).509 * @param pDevIns The device instance to register statistics with.510 * @param ppStream Pointer which receives the newly created audio stream.511 */512 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg,513 PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream)514 {515 AssertPtrReturn(pSink, VERR_INVALID_POINTER);516 Assert(pSink->uMagic == AUDMIXSINK_MAGIC);517 AssertPtrReturn(pConn, VERR_INVALID_POINTER);518 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);519 AssertPtrNullReturn(ppStream, VERR_INVALID_POINTER);520 Assert(pSink->AIO.pDevIns == pDevIns); RT_NOREF(pDevIns); /* we'll probably be adding more statistics */521 AssertReturn(pCfg->enmDir == pSink->enmDir, VERR_MISMATCH);522 523 /*524 * Check status and get the host driver config.525 */526 if (pConn->pfnGetStatus(pConn, PDMAUDIODIR_DUPLEX) == PDMAUDIOBACKENDSTS_NOT_ATTACHED)527 return VERR_AUDIO_BACKEND_NOT_ATTACHED;528 529 PDMAUDIOBACKENDCFG BackendCfg;530 int rc = pConn->pfnGetConfig(pConn, &BackendCfg);531 AssertRCReturn(rc, rc);532 533 /*534 * Allocate the instance.535 */536 PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));537 AssertReturn(pMixStream, VERR_NO_MEMORY);538 539 /* Assign the backend's name to the mixer stream's name for easier identification in the (release) log. */540 pMixStream->pszName = RTStrAPrintf2("[%s] %s", pCfg->szName, BackendCfg.szName);541 pMixStream->pszStatPrefix = RTStrAPrintf2("MixerSink-%s/%s/", pSink->pszName, BackendCfg.szName);542 if (pMixStream->pszName && pMixStream->pszStatPrefix)543 {544 rc = RTCritSectInit(&pMixStream->CritSect);545 if (RT_SUCCESS(rc))546 {547 /*548 * Lock the sink so we can safely get it's properties and call549 * down into the audio driver to create that end of the stream.550 */551 rc = RTCritSectEnter(&pSink->CritSect);552 AssertRC(rc);553 if (RT_SUCCESS(rc))554 {555 LogFlowFunc(("[%s] (enmDir=%ld, %u bits, %RU8 channels, %RU32Hz)\n", pSink->pszName, pCfg->enmDir,556 PDMAudioPropsSampleBits(&pCfg->Props), PDMAudioPropsChannels(&pCfg->Props), pCfg->Props.uHz));557 558 /*559 * Initialize the host-side configuration for the stream to be created,560 * this is the sink format & direction with the src/dir, layout, name561 * and device specific config copied from the guest side config (pCfg).562 */563 AssertMsg(AudioHlpPcmPropsAreValid(&pSink->PCMProps),564 ("%s: Does not (yet) have a format set when it must\n", pSink->pszName));565 566 PDMAUDIOSTREAMCFG CfgHost;567 rc = PDMAudioStrmCfgInitWithProps(&CfgHost, &pSink->PCMProps);568 AssertRC(rc); /* cannot fail */569 CfgHost.enmDir = pSink->enmDir;570 CfgHost.enmPath = pCfg->enmPath;571 CfgHost.enmLayout = pCfg->enmLayout;572 CfgHost.Device = pCfg->Device;573 RTStrCopy(CfgHost.szName, sizeof(CfgHost.szName), pCfg->szName);574 575 /*576 * Create the stream.577 *578 * Output streams are not using any mixing buffers in DrvAudio. This will579 * become the norm after we move the input mixing here and convert DevSB16580 * to use this mixer code too.581 */582 PPDMAUDIOSTREAM pStream;583 rc = pConn->pfnStreamCreate(pConn, 0 /*fFlags*/, &CfgHost, pCfg, &pStream);584 if (RT_SUCCESS(rc))585 {586 pMixStream->cFramesBackendBuffer = CfgHost.Backend.cFramesBufferSize;587 588 /* Set up the mixing buffer conversion state. */589 if (pSink->enmDir == PDMAUDIODIR_IN)590 rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props);591 else592 rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props);593 if (RT_SUCCESS(rc))594 {595 /* Save the audio stream pointer to this mixing stream. */596 pMixStream->pStream = pStream;597 598 /* Increase the stream's reference count to let others know599 * we're relying on it to be around now. */600 pConn->pfnStreamRetain(pConn, pStream);601 pMixStream->pConn = pConn;602 pMixStream->uMagic = AUDMIXSTREAM_MAGIC;603 604 RTCritSectLeave(&pSink->CritSect);605 606 if (ppStream)607 *ppStream = pMixStream;608 return VINF_SUCCESS;609 }610 611 rc = pConn->pfnStreamDestroy(pConn, pStream, true /*fImmediate*/);612 }613 614 /*615 * Failed. Tear down the stream.616 */617 int rc2 = RTCritSectLeave(&pSink->CritSect);618 AssertRC(rc2);619 }620 RTCritSectDelete(&pMixStream->CritSect);621 }622 }623 else624 rc = VERR_NO_STR_MEMORY;625 626 RTStrFree(pMixStream->pszStatPrefix);627 pMixStream->pszStatPrefix = NULL;628 RTStrFree(pMixStream->pszName);629 pMixStream->pszName = NULL;630 RTMemFree(pMixStream);631 return rc;632 }633 634 635 /**636 454 * Starts playback/capturing on the mixer sink. 637 455 * … … 667 485 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE); 668 486 } 669 audioMixerSinkReset (pSink);487 audioMixerSinkResetInternal(pSink); 670 488 } 671 489 … … 803 621 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE); 804 622 } 805 audioMixerSinkReset (pSink);623 audioMixerSinkResetInternal(pSink); 806 624 } 807 625 } … … 823 641 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE); 824 642 } 825 audioMixerSinkReset (pSink);643 audioMixerSinkResetInternal(pSink); 826 644 } 827 645 } … … 836 654 837 655 /** 838 * Destroys a mixer sink.656 * Destroys and frees a mixer sink. 839 657 * 840 658 * Worker for AudioMixerSinkDestroy(), AudioMixerCreateSink() and … … 850 668 LogFunc(("%s\n", pSink->pszName)); 851 669 670 /* 671 * Invalidate the sink instance. 672 */ 852 673 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 853 674 pSink->uMagic = AUDMIXSINK_MAGIC_DEAD; 854 675 676 /* 677 * Destroy all streams. 678 */ 855 679 PAUDMIXSTREAM pStream, pStreamNext; 856 680 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 857 681 { 858 682 audioMixerSinkRemoveStreamInternal(pSink, pStream); 859 audioMixerStreamDestroyInternal(pStream, pDevIns, true /*fImmediate*/); /* (Unlike the other two, this frees the stream structure.) */ 860 } 861 862 /** @todo r=bird: this looks wrong for the AudioMixerSinkDestroy case ... */ 863 if ( pSink->pParent 864 && pSink->pParent->fFlags & AUDMIXER_FLAGS_DEBUG) 683 audioMixerStreamDestroyInternal(pStream, pDevIns, true /*fImmediate*/); 684 } 685 686 /* 687 * Destroy debug file and statistics. 688 */ 689 if (!pSink->Dbg.pFile) 690 { /* likely */ } 691 else 865 692 { 866 693 AudioHlpFileDestroy(pSink->Dbg.pFile); … … 872 699 PDMDevHlpSTAMDeregisterByPrefix(pDevIns, szPrefix); 873 700 874 /* Shutdown the AIO thread if started: */ 701 /* 702 * Shutdown the AIO thread if started: 703 */ 875 704 ASMAtomicWriteBool(&pSink->AIO.fShutdown, true); 876 705 if (pSink->AIO.hEvent != NIL_RTSEMEVENT) … … 893 722 } 894 723 895 AudioMixBufDestroy(&pSink->MixBuf); 724 /* 725 * Mixing buffer, critsect and the structure itself. 726 */ 727 AudioMixBufTerm(&pSink->MixBuf); 896 728 RTCritSectDelete(&pSink->CritSect); 729 RTMemFree(pSink); 897 730 } 898 731 … … 901 734 * Destroys a mixer sink and removes it from the attached mixer (if any). 902 735 * 903 * @param pSink Mixer sink to destroy. 736 * @param pSink Mixer sink to destroy. NULL is ignored. 904 737 * @param pDevIns The device instance that statistics are registered with. 905 738 */ … … 908 741 if (!pSink) 909 742 return; 743 AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC); 910 744 911 745 /* … … 930 764 AssertFailed(); 931 765 766 /* 767 * Actually destroy it. 768 */ 932 769 audioMixerSinkDestroyInternal(pSink, pDevIns); 933 934 RTMemFree(pSink); 935 pSink = NULL; 936 } 937 938 /**939 * Returns the amount of bytes ready to be read from a sink since the last call940 * to AudioMixerSinkUpdate().941 * 942 * @ returns Amount of bytes ready to be read from the sink.943 * @param pSink Sink to return number of available bytes for.770 } 771 772 773 /** 774 * Get the number of bytes that can be read from the sink. 775 * 776 * @returns Number of bytes. 777 * @param pSink The mixer sink. 778 * 779 * @note Only applicable to input sinks, will assert and return zero for 780 * other sink directions. 944 781 */ 945 782 uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink) 946 783 { 947 784 AssertPtrReturn(pSink, 0); 948 Assert (pSink->uMagic == AUDMIXSINK_MAGIC);949 AssertMsg (pSink->enmDir == PDMAUDIODIR_IN, ("%s: Can't read from a non-input sink\n", pSink->pszName));785 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, 0); 786 AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_IN, ("%s: Can't read from a non-input sink\n", pSink->pszName), 0); 950 787 951 788 int rc = RTCritSectEnter(&pSink->CritSect); … … 953 790 954 791 uint32_t cbReadable = 0; 955 956 792 if (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 957 { 958 uint32_t const cFrames = AudioMixBufUsed(&pSink->MixBuf); 959 cbReadable = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames); 960 } 961 962 Log3Func(("[%s] cbReadable=%RU32\n", pSink->pszName, cbReadable)); 963 964 int rc2 = RTCritSectLeave(&pSink->CritSect); 965 AssertRC(rc2); 966 793 cbReadable = AudioMixBufUsedBytes(&pSink->MixBuf); 794 795 RTCritSectLeave(&pSink->CritSect); 796 Log3Func(("[%s] cbReadable=%#x\n", pSink->pszName, cbReadable)); 967 797 return cbReadable; 968 798 } 969 799 970 /** 971 * Returns the amount of bytes ready to be written to a sink since the last call 972 * to AudioMixerSinkUpdate(). 973 * 974 * @returns Amount of bytes ready to be written to the sink. 975 * @param pSink Sink to return number of available bytes for. 800 801 /** 802 * Get the number of bytes that can be written to be sink. 803 * 804 * @returns Number of bytes. 805 * @param pSink The mixer sink. 806 * 807 * @note Only applicable to output sinks, will assert and return zero for 808 * other sink directions. 976 809 */ 977 810 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink) 978 811 { 979 812 AssertPtrReturn(pSink, 0); 980 Assert (pSink->uMagic == AUDMIXSINK_MAGIC);981 AssertMsg (pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a non-output sink\n", pSink->pszName));813 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, 0); 814 AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a non-output sink\n", pSink->pszName), 0); 982 815 983 816 int rc = RTCritSectEnter(&pSink->CritSect); … … 985 818 986 819 uint32_t cbWritable = 0; 987 988 if ( (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 989 && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING)) 990 { 820 if ((pSink->fStatus & (AUDMIXSINK_STS_RUNNING | AUDMIXSINK_STS_DRAINING)) == AUDMIXSINK_STS_RUNNING) 991 821 cbWritable = AudioMixBufFreeBytes(&pSink->MixBuf); 992 } 993 994 Log3Func(("[%s] cbWritable=%RU32 (%RU64ms)\n", 995 pSink->pszName, cbWritable, PDMAudioPropsBytesToMilli(&pSink->PCMProps, cbWritable))); 996 997 int rc2 = RTCritSectLeave(&pSink->CritSect); 998 AssertRC(rc2); 999 822 823 RTCritSectLeave(&pSink->CritSect); 824 Log3Func(("[%s] cbWritable=%#x (%RU64ms)\n", pSink->pszName, cbWritable, 825 PDMAudioPropsBytesToMilli(&pSink->PCMProps, cbWritable) )); 1000 826 return cbWritable; 1001 827 } 1002 828 1003 /** 1004 * Returns the sink's mixing direction. 829 830 /** 831 * Get the sink's mixing direction. 1005 832 * 1006 833 * @returns Mixing direction. 1007 * @param pSink Sink to return direction for.1008 */ 1009 PDMAUDIODIR AudioMixerSinkGetDir(P AUDMIXSINK pSink)834 * @param pSink The mixer sink. 835 */ 836 PDMAUDIODIR AudioMixerSinkGetDir(PCAUDMIXSINK pSink) 1010 837 { 1011 838 AssertPtrReturn(pSink, PDMAUDIODIR_INVALID); 1012 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 1013 1014 /** @todo the sink direction should be static... */ 839 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, PDMAUDIODIR_INVALID); 840 841 /* The sink direction cannot be changed after creation, so no need for locking here. */ 842 return pSink->enmDir; 843 } 844 845 846 /** 847 * Get the sink status. 848 * 849 * @returns AUDMIXSINK_STS_XXX 850 * @param pSink The mixer sink. 851 */ 852 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink) 853 { 854 AssertPtrReturn(pSink, AUDMIXSINK_STS_NONE); 855 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, AUDMIXSINK_STS_NONE); 856 1015 857 int rc = RTCritSectEnter(&pSink->CritSect); 1016 AssertRCReturn(rc, PDMAUDIODIR_INVALID); 1017 1018 PDMAUDIODIR const enmDir = pSink->enmDir; 1019 1020 int rc2 = RTCritSectLeave(&pSink->CritSect); 1021 AssertRC(rc2); 1022 1023 return enmDir; 1024 } 1025 1026 /** 1027 * Returns the current status of a mixer sink. 1028 * 1029 * @returns The sink's current status (AUDMIXSINK_STS_XXX). 1030 * @param pSink Mixer sink to return status for. 1031 */ 1032 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink) 1033 { 1034 if (!pSink) 1035 return AUDMIXSINK_STS_NONE; 1036 AssertPtr(pSink); 1037 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 1038 1039 int rc2 = RTCritSectEnter(&pSink->CritSect); 1040 AssertRCReturn(rc2, AUDMIXSINK_STS_NONE); 1041 1042 /* If the dirty flag is set, there is unprocessed data in the sink. */ 858 AssertRCReturn(rc, AUDMIXSINK_STS_NONE); 859 1043 860 uint32_t const fStsSink = pSink->fStatus; 1044 861 1045 rc2 = RTCritSectLeave(&pSink->CritSect); 1046 AssertRC(rc2); 1047 862 RTCritSectLeave(&pSink->CritSect); 1048 863 return fStsSink; 1049 864 } 1050 865 1051 /** 1052 * Returns whether the sink is in an active state or not. 1053 * 1054 * @note The pending disable state also counts as active. 1055 * 1056 * @returns True if active, false if not. 1057 * @param pSink Sink to return active state for. 866 867 /** 868 * Checks if the sink is active not. 869 * 870 * @note The pending disable state also counts as active. 871 * 872 * @retval true if active. 873 * @retval false if not active. 874 * @param pSink The mixer sink. NULL is okay (returns false). 1058 875 */ 1059 876 bool AudioMixerSinkIsActive(PAUDMIXSINK pSink) … … 1062 879 return false; 1063 880 AssertPtr(pSink); 1064 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 1065 1066 int rc2 = RTCritSectEnter(&pSink->CritSect); 1067 AssertRCReturn(rc2, false); 1068 1069 const bool fIsActive = pSink->fStatus & AUDMIXSINK_STS_RUNNING; 1070 /* Note: AUDMIXSINK_STS_PENDING_DISABLE implies AUDMIXSINK_STS_RUNNING. */ 1071 1072 Log3Func(("[%s] fActive=%RTbool\n", pSink->pszName, fIsActive)); 1073 1074 rc2 = RTCritSectLeave(&pSink->CritSect); 1075 AssertRC(rc2); 1076 881 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, false); 882 883 int rc = RTCritSectEnter(&pSink->CritSect); 884 AssertRCReturn(rc, false); 885 886 bool const fIsActive = RT_BOOL(pSink->fStatus & AUDMIXSINK_STS_RUNNING); 887 888 RTCritSectLeave(&pSink->CritSect); 889 Log3Func(("[%s] returns %RTbool\n", pSink->pszName, fIsActive)); 1077 890 return fIsActive; 1078 891 } 1079 892 1080 /** 1081 * Removes a mixer stream from a mixer sink, internal version. 1082 * 1083 * @returns VBox status code. 1084 * @param pSink Sink to remove mixer stream from. 1085 * @param pStream Stream to remove. 1086 */ 1087 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 1088 { 1089 AssertPtrReturn(pSink, VERR_INVALID_PARAMETER); 1090 if (pStream) 1091 { /* likely */ } 1092 else 1093 return VERR_NOT_FOUND; 1094 AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n", 1095 pStream->pszName, pSink->pszName), VERR_NOT_FOUND); 1096 1097 LogFlowFunc(("[%s] (Stream = %s), cStreams=%RU8\n", 1098 pSink->pszName, pStream->pStream->szName, pSink->cStreams)); 1099 1100 /* Remove stream from sink. */ 1101 RTListNodeRemove(&pStream->Node); 1102 1103 /* Set sink to NULL so that we know we're not part of any sink anymore. */ 1104 pStream->pSink = NULL; 1105 1106 return VINF_SUCCESS; 1107 } 1108 1109 /** 1110 * Removes a mixer stream from a mixer sink. 1111 * 1112 * @param pSink Sink to remove mixer stream from. 1113 * @param pStream Stream to remove. 1114 */ 1115 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 1116 { 1117 AssertPtr(pSink); 1118 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 1119 if (pStream) 1120 Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC); 1121 1122 int rc2 = RTCritSectEnter(&pSink->CritSect); 1123 AssertRC(rc2); 1124 1125 rc2 = audioMixerSinkRemoveStreamInternal(pSink, pStream); 1126 if (RT_SUCCESS(rc2)) 1127 { 1128 Assert(pSink->cStreams); 1129 pSink->cStreams--; 1130 } 1131 1132 rc2 = RTCritSectLeave(&pSink->CritSect); 1133 AssertRC(rc2); 1134 } 1135 1136 /** 1137 * Removes all attached streams from a given sink. 1138 * 1139 * @param pSink Sink to remove attached streams from. 1140 */ 1141 static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink) 893 894 /** 895 * Resets the sink's state. 896 * 897 * @param pSink The sink to reset. 898 * @note Must own sink lock. 899 */ 900 static void audioMixerSinkResetInternal(PAUDMIXSINK pSink) 901 { 902 Assert(RTCritSectIsOwner(&pSink->CritSect)); 903 LogFunc(("[%s]\n", pSink->pszName)); 904 905 /* Drop mixing buffer content. */ 906 AudioMixBufDrop(&pSink->MixBuf); 907 908 /* Reset status. */ 909 pSink->fStatus = AUDMIXSINK_STS_NONE; 910 pSink->tsLastUpdatedMs = 0; 911 } 912 913 914 /** 915 * Resets a sink. This will immediately stop all processing. 916 * 917 * @param pSink Sink to reset. 918 */ 919 void AudioMixerSinkReset(PAUDMIXSINK pSink) 1142 920 { 1143 921 if (!pSink) 1144 922 return; 1145 1146 LogFunc(("%s\n", pSink->pszName)); 1147 1148 PAUDMIXSTREAM pStream, pStreamNext; 1149 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 1150 audioMixerSinkRemoveStreamInternal(pSink, pStream); 1151 } 1152 1153 /** 1154 * Removes all attached streams from a given sink. 1155 * 1156 * @param pSink Sink to remove attached streams from. 1157 */ 1158 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink) 1159 { 1160 if (!pSink) 1161 return; 1162 1163 int rc2 = RTCritSectEnter(&pSink->CritSect); 1164 AssertRC(rc2); 1165 1166 audioMixerSinkRemoveAllStreamsInternal(pSink); 1167 1168 pSink->cStreams = 0; 1169 1170 rc2 = RTCritSectLeave(&pSink->CritSect); 1171 AssertRC(rc2); 1172 } 1173 1174 /** 1175 * Resets the sink's state. 1176 * 1177 * @param pSink Sink to reset. 1178 */ 1179 static void audioMixerSinkReset(PAUDMIXSINK pSink) 1180 { 1181 if (!pSink) 1182 return; 1183 1184 LogFunc(("[%s]\n", pSink->pszName)); 1185 1186 AudioMixBufDrop(&pSink->MixBuf); 1187 1188 /* Update last updated timestamp. */ 1189 pSink->tsLastUpdatedMs = 0; 1190 1191 /* Reset status. */ 1192 pSink->fStatus = AUDMIXSINK_STS_NONE; 1193 } 1194 1195 /** 1196 * Resets a sink. This will immediately stop all processing. 1197 * 1198 * @param pSink Sink to reset. 1199 */ 1200 void AudioMixerSinkReset(PAUDMIXSINK pSink) 1201 { 1202 if (!pSink) 1203 return; 1204 1205 int rc2 = RTCritSectEnter(&pSink->CritSect); 1206 AssertRC(rc2); 923 AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC); 924 925 int rc = RTCritSectEnter(&pSink->CritSect); 926 AssertRCReturnVoid(rc); 1207 927 1208 928 LogFlowFunc(("[%s]\n", pSink->pszName)); 1209 929 1210 audioMixerSinkReset(pSink); 1211 1212 rc2 = RTCritSectLeave(&pSink->CritSect); 1213 AssertRC(rc2); 1214 } 930 /* 931 * Stop any stream that's enabled before resetting the state. 932 */ 933 PAUDMIXSTREAM pStream; 934 RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node) 935 { 936 if (pStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED) 937 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_DISABLE); 938 } 939 940 /* 941 * Reset the state. 942 */ 943 audioMixerSinkResetInternal(pSink); 944 945 RTCritSectLeave(&pSink->CritSect); 946 } 947 1215 948 1216 949 /** … … 1219 952 * @returns VBox status code. 1220 953 * @param pSink The sink to set audio format for. 1221 * @param pProps The properties of the new audio format .954 * @param pProps The properties of the new audio format (guest side). 1222 955 */ 1223 956 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pProps) … … 1232 965 1233 966 /* 1234 * Nothing to do here unless the formatchanged.967 * Do nothing unless the format actually changed. 1235 968 */ 1236 969 if (!PDMAudioPropsAreEqual(&pSink->PCMProps, pProps)) … … 1241 974 if (PDMAudioPropsHz(&pSink->PCMProps) != 0) 1242 975 LogFlowFunc(("[%s] Old format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) )); 1243 1244 976 pSink->PCMProps = *pProps; 1245 977 LogFlowFunc(("[%s] New format: %s\n", pSink->pszName, PDMAudioPropsToString(&pSink->PCMProps, szTmp, sizeof(szTmp)) )); … … 1248 980 * Also update the sink's mixing buffer format. 1249 981 */ 1250 AudioMixBuf Destroy(&pSink->MixBuf);982 AudioMixBufTerm(&pSink->MixBuf); 1251 983 1252 984 /** @todo r=bird: Make sure we've got more room here than what's expected to … … 1317 1049 } 1318 1050 1319 /** 1320 * Sets the volume of an individual sink. 1051 1052 /** 1053 * Updates the combined volume (sink + mixer) of a mixer sink. 1321 1054 * 1322 1055 * @returns VBox status code. 1323 * @param pSink Sink to set volume for. 1324 * @param pVol Volume to set. 1325 */ 1326 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol) 1056 * @param pSink The mixer sink to update volume for (valid). 1057 * @param pVolMaster The master (mixer) volume (valid). 1058 */ 1059 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster) 1060 { 1061 AssertPtr(pSink); 1062 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 1063 AssertPtr(pVolMaster); 1064 LogFlowFunc(("[%s] Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 1065 pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight)); 1066 1067 pSink->VolumeCombined.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted; 1068 /** @todo Very crude implementation for now -- needs more work! */ 1069 pSink->VolumeCombined.uLeft = (uint32_t)RT_MAX(pSink->Volume.uLeft, 1) * RT_MAX(pVolMaster->uLeft, 1) / PDMAUDIO_VOLUME_MAX; 1070 pSink->VolumeCombined.uRight = (uint32_t)RT_MAX(pSink->Volume.uRight, 1) * RT_MAX(pVolMaster->uRight, 1) / PDMAUDIO_VOLUME_MAX; 1071 1072 LogFlowFunc(("[%s] fMuted=%RTbool, lVol=%RU32, rVol=%RU32 -> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 1073 pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight, 1074 pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight)); 1075 1076 AudioMixBufSetVolume(&pSink->MixBuf, &pSink->VolumeCombined); 1077 return VINF_SUCCESS; 1078 } 1079 1080 1081 /** 1082 * Sets the volume a mixer sink. 1083 * 1084 * @returns VBox status code. 1085 * @param pSink The sink to set volume for. 1086 * @param pVol New volume settings. 1087 */ 1088 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVol) 1327 1089 { 1328 1090 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 1329 Assert (pSink->uMagic == AUDMIXSINK_MAGIC);1330 AssertPtrReturn(pVol, 1091 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, VERR_INVALID_MAGIC); 1092 AssertPtrReturn(pVol, VERR_INVALID_POINTER); 1331 1093 1332 1094 int rc = RTCritSectEnter(&pSink->CritSect); … … 1338 1100 pSink->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted ? "Muted" : "Unmuted")); 1339 1101 1340 Assert Ptr(pSink->pParent);1341 rc = audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);1342 1343 int rc2 = RTCritSectLeave(&pSink->CritSect); 1344 AssertRC(rc2);1102 Assert(pSink->pParent); 1103 if (pSink->pParent) 1104 rc = audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster); 1105 1106 RTCritSectLeave(&pSink->CritSect); 1345 1107 1346 1108 return rc; … … 1903 1665 LogFunc(("Sink '%s': All %u streams disabled. Drain done after %RU64 ns.\n", 1904 1666 pSink->pszName, cStreamsDisabled, nsNow - pSink->nsDrainStarted)); 1905 audioMixerSinkReset (pSink); /* clears the status */1667 audioMixerSinkResetInternal(pSink); /* clears the status */ 1906 1668 } 1907 1669 } … … 1914 1676 pMixStream->pConn->pfnStreamControl(pMixStream->pConn, pMixStream->pStream, PDMAUDIOSTREAMCMD_DISABLE); 1915 1677 } 1916 audioMixerSinkReset (pSink); /* clears the status */1678 audioMixerSinkResetInternal(pSink); /* clears the status */ 1917 1679 } 1918 1680 … … 2163 1925 2164 1926 /** 1927 * Writes data to a mixer output sink. 1928 * 1929 * @param pSink The sink to write data to. 1930 * @param pvBuf Buffer containing the audio data to write. 1931 * @param cbBuf How many bytes to write. 1932 * @param pcbWritten Number of bytes written. 1933 * 1934 * @todo merge with caller. 1935 */ 1936 static void audioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 1937 { 1938 uint32_t cFrames = AudioMixBufFree(&pSink->MixBuf); 1939 uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames); 1940 cbToWrite = RT_MIN(cbToWrite, cbBuf); 1941 AudioMixBufWrite(&pSink->MixBuf, &pSink->Out.State, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFrames); 1942 Assert(cbToWrite == PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames)); 1943 AudioMixBufCommit(&pSink->MixBuf, cFrames); 1944 *pcbWritten = cbToWrite; 1945 1946 /* Update the sink's last written time stamp. */ 1947 pSink->tsLastReadWrittenNs = RTTimeNanoTS(); 1948 1949 Log3Func(("[%s] cbBuf=%#x -> cbWritten=%#x\n", pSink->pszName, cbBuf, cbToWrite)); 1950 } 1951 1952 1953 /** 2165 1954 * Transfer data from the device's DMA buffer and into the sink. 2166 1955 * … … 2185 1974 AssertReturn(pCircBuf, offStream); 2186 1975 Assert(RTCritSectIsOwner(&pSink->CritSect)); 1976 Assert(pSink->enmDir == PDMAUDIODIR_OUT); 2187 1977 RT_NOREF(idStream); 2188 1978 … … 2211 2001 2212 2002 uint32_t cbWritten = 0; 2213 int rc = AudioMixerSinkWrite(pSink, pvSrcBuf, (uint32_t)cbSrcBuf, &cbWritten); 2214 AssertRC(rc); 2003 audioMixerSinkWrite(pSink, pvSrcBuf, (uint32_t)cbSrcBuf, &cbWritten); 2215 2004 Assert(cbWritten <= cbSrcBuf); 2216 2005 … … 2412 2201 2413 2202 /** 2414 * Updates the (master) volume of a mixer sink.2203 * Creates an audio mixer stream. 2415 2204 * 2416 2205 * @returns VBox status code. 2417 * @param pSink Mixer sink to update volume for. 2418 * @param pVolMaster Master volume to set. 2419 */ 2420 static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVolMaster) 2421 { 2422 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 2206 * @param pSink Sink to use for creating the stream. 2207 * @param pConn Audio connector interface to use. 2208 * @param pCfg Audio stream configuration to use. This may be modified 2209 * in some unspecified way (see 2210 * PDMIAUDIOCONNECTOR::pfnStreamCreate). 2211 * @param pDevIns The device instance to register statistics with. 2212 * @param ppStream Pointer which receives the newly created audio stream. 2213 */ 2214 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, 2215 PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream) 2216 { 2217 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 2423 2218 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 2424 AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER); 2425 2426 LogFlowFunc(("[%s] Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 2427 pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight)); 2428 LogFlowFunc(("[%s] fMuted=%RTbool, lVol=%RU32, rVol=%RU32 ", 2429 pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight)); 2430 2431 /** @todo Very crude implementation for now -- needs more work! */ 2432 2433 pSink->VolumeCombined.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted; 2434 2435 pSink->VolumeCombined.uLeft = ( (pSink->Volume.uLeft ? pSink->Volume.uLeft : 1) 2436 * (pVolMaster->uLeft ? pVolMaster->uLeft : 1)) / PDMAUDIO_VOLUME_MAX; 2437 2438 pSink->VolumeCombined.uRight = ( (pSink->Volume.uRight ? pSink->Volume.uRight : 1) 2439 * (pVolMaster->uRight ? pVolMaster->uRight : 1)) / PDMAUDIO_VOLUME_MAX; 2440 2441 LogFlow(("-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", 2442 pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight)); 2443 2444 AudioMixBufSetVolume(&pSink->MixBuf, &pSink->VolumeCombined); 2445 return VINF_SUCCESS; 2446 } 2447 2448 /** 2449 * Writes data to a mixer output sink. 2219 AssertPtrReturn(pConn, VERR_INVALID_POINTER); 2220 AssertPtrReturn(pCfg, VERR_INVALID_POINTER); 2221 AssertPtrNullReturn(ppStream, VERR_INVALID_POINTER); 2222 Assert(pSink->AIO.pDevIns == pDevIns); RT_NOREF(pDevIns); /* we'll probably be adding more statistics */ 2223 AssertReturn(pCfg->enmDir == pSink->enmDir, VERR_MISMATCH); 2224 2225 /* 2226 * Check status and get the host driver config. 2227 */ 2228 if (pConn->pfnGetStatus(pConn, PDMAUDIODIR_DUPLEX) == PDMAUDIOBACKENDSTS_NOT_ATTACHED) 2229 return VERR_AUDIO_BACKEND_NOT_ATTACHED; 2230 2231 PDMAUDIOBACKENDCFG BackendCfg; 2232 int rc = pConn->pfnGetConfig(pConn, &BackendCfg); 2233 AssertRCReturn(rc, rc); 2234 2235 /* 2236 * Allocate the instance. 2237 */ 2238 PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM)); 2239 AssertReturn(pMixStream, VERR_NO_MEMORY); 2240 2241 /* Assign the backend's name to the mixer stream's name for easier identification in the (release) log. */ 2242 pMixStream->pszName = RTStrAPrintf2("[%s] %s", pCfg->szName, BackendCfg.szName); 2243 pMixStream->pszStatPrefix = RTStrAPrintf2("MixerSink-%s/%s/", pSink->pszName, BackendCfg.szName); 2244 if (pMixStream->pszName && pMixStream->pszStatPrefix) 2245 { 2246 rc = RTCritSectInit(&pMixStream->CritSect); 2247 if (RT_SUCCESS(rc)) 2248 { 2249 /* 2250 * Lock the sink so we can safely get it's properties and call 2251 * down into the audio driver to create that end of the stream. 2252 */ 2253 rc = RTCritSectEnter(&pSink->CritSect); 2254 AssertRC(rc); 2255 if (RT_SUCCESS(rc)) 2256 { 2257 LogFlowFunc(("[%s] (enmDir=%ld, %u bits, %RU8 channels, %RU32Hz)\n", pSink->pszName, pCfg->enmDir, 2258 PDMAudioPropsSampleBits(&pCfg->Props), PDMAudioPropsChannels(&pCfg->Props), pCfg->Props.uHz)); 2259 2260 /* 2261 * Initialize the host-side configuration for the stream to be created, 2262 * this is the sink format & direction with the src/dir, layout, name 2263 * and device specific config copied from the guest side config (pCfg). 2264 */ 2265 AssertMsg(AudioHlpPcmPropsAreValid(&pSink->PCMProps), 2266 ("%s: Does not (yet) have a format set when it must\n", pSink->pszName)); 2267 2268 PDMAUDIOSTREAMCFG CfgHost; 2269 rc = PDMAudioStrmCfgInitWithProps(&CfgHost, &pSink->PCMProps); 2270 AssertRC(rc); /* cannot fail */ 2271 CfgHost.enmDir = pSink->enmDir; 2272 CfgHost.enmPath = pCfg->enmPath; 2273 CfgHost.enmLayout = pCfg->enmLayout; 2274 CfgHost.Device = pCfg->Device; 2275 RTStrCopy(CfgHost.szName, sizeof(CfgHost.szName), pCfg->szName); 2276 2277 /* 2278 * Create the stream. 2279 * 2280 * Output streams are not using any mixing buffers in DrvAudio. This will 2281 * become the norm after we move the input mixing here and convert DevSB16 2282 * to use this mixer code too. 2283 */ 2284 PPDMAUDIOSTREAM pStream; 2285 rc = pConn->pfnStreamCreate(pConn, 0 /*fFlags*/, &CfgHost, pCfg, &pStream); 2286 if (RT_SUCCESS(rc)) 2287 { 2288 pMixStream->cFramesBackendBuffer = CfgHost.Backend.cFramesBufferSize; 2289 2290 /* Set up the mixing buffer conversion state. */ 2291 if (pSink->enmDir == PDMAUDIODIR_IN) 2292 rc = AudioMixBufInitWriteState(&pSink->MixBuf, &pMixStream->WriteState, &pStream->Props); 2293 else 2294 rc = AudioMixBufInitPeekState(&pSink->MixBuf, &pMixStream->PeekState, &pStream->Props); 2295 if (RT_SUCCESS(rc)) 2296 { 2297 /* Save the audio stream pointer to this mixing stream. */ 2298 pMixStream->pStream = pStream; 2299 2300 /* Increase the stream's reference count to let others know 2301 * we're relying on it to be around now. */ 2302 pConn->pfnStreamRetain(pConn, pStream); 2303 pMixStream->pConn = pConn; 2304 pMixStream->uMagic = AUDMIXSTREAM_MAGIC; 2305 2306 RTCritSectLeave(&pSink->CritSect); 2307 2308 if (ppStream) 2309 *ppStream = pMixStream; 2310 return VINF_SUCCESS; 2311 } 2312 2313 rc = pConn->pfnStreamDestroy(pConn, pStream, true /*fImmediate*/); 2314 } 2315 2316 /* 2317 * Failed. Tear down the stream. 2318 */ 2319 int rc2 = RTCritSectLeave(&pSink->CritSect); 2320 AssertRC(rc2); 2321 } 2322 RTCritSectDelete(&pMixStream->CritSect); 2323 } 2324 } 2325 else 2326 rc = VERR_NO_STR_MEMORY; 2327 2328 RTStrFree(pMixStream->pszStatPrefix); 2329 pMixStream->pszStatPrefix = NULL; 2330 RTStrFree(pMixStream->pszName); 2331 pMixStream->pszName = NULL; 2332 RTMemFree(pMixStream); 2333 return rc; 2334 } 2335 2336 2337 /** 2338 * Adds an audio stream to a specific audio sink. 2450 2339 * 2451 2340 * @returns VBox status code. 2452 * @param pSink Sink to write data to. 2453 * @param pvBuf Buffer containing the audio data to write. 2454 * @param cbBuf Size (in bytes) of the buffer containing the audio data. 2455 * @param pcbWritten Number of bytes written. Optional. 2456 */ 2457 int AudioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 2458 { 2459 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 2460 AssertReturn(pSink->uMagic == AUDMIXSINK_MAGIC, VERR_INVALID_MAGIC); 2461 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 2462 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 2463 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER); 2464 AssertMsgReturn(pSink->enmDir == PDMAUDIODIR_OUT, ("%s: Can't write to a sink which is not an output sink\n", pSink->pszName), 2465 VERR_ACCESS_DENIED); 2341 * @param pSink Sink to add audio stream to. 2342 * @param pStream Stream to add. 2343 */ 2344 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 2345 { 2346 LogFlowFuncEnter(); 2347 AssertPtrReturn(pSink, VERR_INVALID_POINTER); 2348 Assert(pSink->uMagic == AUDMIXSINK_MAGIC); 2349 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2350 Assert(pStream->uMagic == AUDMIXSTREAM_MAGIC); 2351 AssertPtrReturn(pStream->pConn, VERR_AUDIO_STREAM_NOT_READY); 2352 AssertReturn(pStream->pSink == NULL, VERR_ALREADY_EXISTS); 2466 2353 2467 2354 int rc = RTCritSectEnter(&pSink->CritSect); 2468 2355 AssertRCReturn(rc, rc); 2469 2356 2470 AssertMsgReturnStmt(pSink->fStatus & AUDMIXSINK_STS_RUNNING, 2471 ("%s: Can't write to a sink which is not running (anymore) (status 0x%x)\n", pSink->pszName, pSink->fStatus), 2472 RTCritSectLeave(&pSink->CritSect), VERR_INVALID_STATE); 2473 2474 uint32_t cFrames = AudioMixBufFree(&pSink->MixBuf); 2475 uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames); 2476 cbToWrite = RT_MIN(cbToWrite, cbBuf); 2477 AudioMixBufWrite(&pSink->MixBuf, &pSink->Out.State, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFrames); 2478 Assert(cbToWrite == PDMAudioPropsFramesToBytes(&pSink->PCMProps, cFrames)); 2479 AudioMixBufCommit(&pSink->MixBuf, cFrames); 2480 if (pcbWritten) 2481 *pcbWritten = cbToWrite; 2482 2483 /* Update the sink's last written time stamp. */ 2484 pSink->tsLastReadWrittenNs = RTTimeNanoTS(); 2485 2486 Log3Func(("[%s] cbBuf=%#x -> cbWritten=%#x\n", pSink->pszName, cbBuf, cbToWrite)); 2487 2357 AssertLogRelMsgReturnStmt(pSink->cStreams < UINT8_MAX, ("too many streams!\n"), RTCritSectLeave(&pSink->CritSect), 2358 VERR_TOO_MANY_OPEN_FILES); 2359 2360 /* 2361 * If the sink is running and not in pending disable mode, make sure that 2362 * the added stream also is enabled. Ignore any failure to enable it. 2363 */ 2364 if ( (pSink->fStatus & AUDMIXSINK_STS_RUNNING) 2365 && !(pSink->fStatus & AUDMIXSINK_STS_DRAINING)) 2366 { 2367 audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE); 2368 } 2369 2370 /* Save pointer to sink the stream is attached to. */ 2371 pStream->pSink = pSink; 2372 2373 /* Append stream to sink's list. */ 2374 RTListAppend(&pSink->lstStreams, &pStream->Node); 2375 pSink->cStreams++; 2376 2377 LogFlowFunc(("[%s] cStreams=%RU8, rc=%Rrc\n", pSink->pszName, pSink->cStreams, rc)); 2488 2378 RTCritSectLeave(&pSink->CritSect); 2379 return rc; 2380 } 2381 2382 2383 /** 2384 * Removes a mixer stream from a mixer sink, internal version. 2385 * 2386 * @returns VBox status code. 2387 * @param pSink The mixer sink (valid). 2388 * @param pStream The stream to remove (valid). 2389 * 2390 * @note Caller must own the sink lock. 2391 */ 2392 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 2393 { 2394 AssertPtr(pSink); 2395 AssertPtr(pStream); 2396 AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n", 2397 pStream->pszName, pSink->pszName), VERR_NOT_FOUND); 2398 Assert(RTCritSectIsOwner(&pSink->CritSect)); 2399 LogFlowFunc(("[%s] (Stream = %s), cStreams=%RU8\n", pSink->pszName, pStream->pStream->szName, pSink->cStreams)); 2400 2401 /* 2402 * Remove stream from sink, update the count and set the pSink member to NULL. 2403 */ 2404 RTListNodeRemove(&pStream->Node); 2405 2406 Assert(pSink->cStreams > 0); 2407 pSink->cStreams--; 2408 2409 pStream->pSink = NULL; 2410 2489 2411 return VINF_SUCCESS; 2490 2412 } 2413 2414 2415 /** 2416 * Removes a mixer stream from a mixer sink. 2417 * 2418 * @param pSink The mixer sink. 2419 * @param pStream The stream to remove. 2420 */ 2421 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream) 2422 { 2423 AssertPtrReturnVoid(pSink); 2424 AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC); 2425 AssertPtrReturnVoid(pStream); 2426 AssertReturnVoid(pStream->uMagic == AUDMIXSTREAM_MAGIC); 2427 2428 int rc = RTCritSectEnter(&pSink->CritSect); 2429 AssertRCReturnVoid(rc); 2430 2431 audioMixerSinkRemoveStreamInternal(pSink, pStream); 2432 2433 RTCritSectLeave(&pSink->CritSect); 2434 } 2435 2436 2437 /** 2438 * Removes all streams from a given sink. 2439 * 2440 * @param pSink The mixer sink. NULL is ignored. 2441 */ 2442 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink) 2443 { 2444 if (!pSink) 2445 return; 2446 AssertReturnVoid(pSink->uMagic == AUDMIXSINK_MAGIC); 2447 2448 int rc = RTCritSectEnter(&pSink->CritSect); 2449 AssertRCReturnVoid(rc); 2450 2451 LogFunc(("%s\n", pSink->pszName)); 2452 2453 PAUDMIXSTREAM pStream, pStreamNext; 2454 RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node) 2455 { 2456 audioMixerSinkRemoveStreamInternal(pSink, pStream); 2457 } 2458 AssertStmt(pSink->cStreams == 0, pSink->cStreams = 0); 2459 2460 RTCritSectLeave(&pSink->CritSect); 2461 } 2462 2491 2463 2492 2464 … … 2602 2574 } 2603 2575 2576 2604 2577 /** 2605 2578 * Destroys & frees a mixer stream, internal version. … … 2615 2588 static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pMixStream, PPDMDEVINS pDevIns, bool fImmediate) 2616 2589 { 2617 AssertPtrReturnVoid(pMixStream); 2618 2590 AssertPtr(pMixStream); 2619 2591 LogFunc(("%s\n", pMixStream->pszName)); 2620 2592 Assert(pMixStream->uMagic == AUDMIXSTREAM_MAGIC); 2621 2593 2594 /* 2595 * Invalidate it. 2596 */ 2597 pMixStream->uMagic = AUDMIXSTREAM_MAGIC_DEAD; 2598 2599 /* 2600 * Destroy the driver stream (if any). 2601 */ 2622 2602 if (pMixStream->pConn) /* Stream has a connector interface present? */ 2623 2603 { … … 2633 2613 } 2634 2614 2615 /* 2616 * Stats. Doing it by prefix is soo much faster than individually, btw. 2617 */ 2635 2618 if (pMixStream->pszStatPrefix) 2636 2619 { … … 2640 2623 } 2641 2624 2625 /* 2626 * Delete the critsect and free the memory. 2627 */ 2628 int rc2 = RTCritSectDelete(&pMixStream->CritSect); 2629 AssertRC(rc2); 2630 2642 2631 RTStrFree(pMixStream->pszName); 2643 2632 pMixStream->pszName = NULL; 2644 2633 2645 int rc2 = RTCritSectDelete(&pMixStream->CritSect);2646 AssertRC(rc2);2647 2648 2634 RTMemFree(pMixStream); 2649 pMixStream = NULL; 2650 } 2635 } 2636 2651 2637 2652 2638 /** … … 2663 2649 if (!pMixStream) 2664 2650 return; 2665 2666 /** @todo r=bird: Wrng critsect for audioMixerSinkRemoveStreamInternal */ 2667 int rc2 = RTCritSectEnter(&pMixStream->CritSect); 2668 AssertRC(rc2); 2669 2651 AssertReturnVoid(pMixStream->uMagic == AUDMIXSTREAM_MAGIC); 2670 2652 LogFunc(("%s\n", pMixStream->pszName)); 2671 2653 2672 if (pMixStream->pSink) /* Is the stream part of a sink? */2673 {2674 /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the2675 * pointer will be gone from the stream. */2676 PAUDMIXSINK pSink = pMixStream->pSink;2677 2678 rc2 = audioMixerSinkRemoveStreamInternal(pSink, pMixStream); 2679 if (RT_SUCCESS(rc2))2680 {2681 Assert(pSink->cStreams);2682 pSink->cStreams--;2683 }2684 }2685 else2686 rc2 = VINF_SUCCESS;2687 2688 int rc3 = RTCritSectLeave(&pMixStream->CritSect);2689 AssertRC(rc3);2690 2691 if (RT_SUCCESS(rc2))2692 { 2693 audioMixerStreamDestroyInternal(pMixStream, pDevIns, fImmediate);2694 pMixStream = NULL;2695 }2696 2697 LogFlowFunc((" Returning %Rrc\n", rc2));2698 } 2699 2654 /* 2655 * Serializing paranoia. 2656 */ 2657 int rc = RTCritSectEnter(&pMixStream->CritSect); 2658 AssertRCReturnVoid(rc); 2659 RTCritSectLeave(&pMixStream->CritSect); 2660 2661 /* 2662 * Unlink from sink if associated with one. 2663 */ 2664 PAUDMIXSINK pSink = pMixStream->pSink; 2665 if ( RT_VALID_PTR(pSink) 2666 && pSink->uMagic == AUDMIXSINK_MAGIC) 2667 { 2668 RTCritSectEnter(&pSink->CritSect); 2669 audioMixerSinkRemoveStreamInternal(pMixStream->pSink, pMixStream); 2670 RTCritSectLeave(&pSink->CritSect); 2671 } 2672 else if (pSink) 2673 AssertFailed(); 2674 2675 /* 2676 * Do the actual stream destruction. 2677 */ 2678 audioMixerStreamDestroyInternal(pMixStream, pDevIns, fImmediate); 2679 LogFlowFunc(("returns\n")); 2680 } 2681 -
trunk/src/VBox/Devices/Audio/AudioMixer.h
r89357 r89371 35 35 /** Pointer to an audio mixer sink. */ 36 36 typedef struct AUDMIXSINK *PAUDMIXSINK; 37 /** Pointer to a const audio mixer sink. */ 38 typedef struct AUDMIXSINK const *PCAUDMIXSINK; 37 39 38 40 … … 287 289 /** @name Audio mixer sink methods 288 290 * @{ */ 289 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 290 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg, 291 PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream); 292 int AudioMixerSinkStart(PAUDMIXSINK pSink); 293 int AudioMixerSinkDrainAndStop(PAUDMIXSINK pSink, uint32_t cbComming); 294 void AudioMixerSinkDestroy(PAUDMIXSINK pSink, PPDMDEVINS pDevIns); 295 uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink); 296 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink); 297 PDMAUDIODIR AudioMixerSinkGetDir(PAUDMIXSINK pSink); 298 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink); 299 bool AudioMixerSinkIsActive(PAUDMIXSINK pSink); 300 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 301 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink); 302 void AudioMixerSinkReset(PAUDMIXSINK pSink); 303 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps); 304 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol); 305 int AudioMixerSinkWrite(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 306 int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod); 291 int AudioMixerSinkStart(PAUDMIXSINK pSink); 292 int AudioMixerSinkDrainAndStop(PAUDMIXSINK pSink, uint32_t cbComming); 293 void AudioMixerSinkDestroy(PAUDMIXSINK pSink, PPDMDEVINS pDevIns); 294 uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink); 295 uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink); 296 PDMAUDIODIR AudioMixerSinkGetDir(PCAUDMIXSINK pSink); 297 uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink); 298 bool AudioMixerSinkIsActive(PAUDMIXSINK pSink); 299 void AudioMixerSinkReset(PAUDMIXSINK pSink); 300 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps); 301 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVol); 302 int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod); 307 303 308 304 int AudioMixerSinkAddUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser, uint32_t cMsTypicalInterval); … … 316 312 int AudioMixerSinkTryLock(PAUDMIXSINK pSink); 317 313 int AudioMixerSinkUnlock(PAUDMIXSINK pSink); 314 315 int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg, 316 PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream); 317 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 318 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream); 319 void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink); 318 320 /** @} */ 319 321 320 322 /** @name Audio mixer stream methods 321 323 * @{ */ 322 void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream, PPDMDEVINS pDevIns, bool fImmediate);324 void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream, PPDMDEVINS pDevIns, bool fImmediate); 323 325 /** @} */ 324 326 -
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r89341 r89371 911 911 { 912 912 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 913 bool fIsEnabled = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);913 bool fIsEnabled = pSink && (AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING); 914 914 915 915 LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8SD, fIsEnabled)); -
trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
r89351 r89371 318 318 RTTESTI_CHECK(AudioMixBufReadPos(&mb) == 0); 319 319 320 AudioMixBuf Destroy(&mb);320 AudioMixBufTerm(&mb); 321 321 } 322 322 … … 674 674 iSrcFrame, cDstMinExpect, cDstMaxExpect, iDstFrame, (cDstMinExpect + cDstMaxExpect) / 2 - iDstFrame)); 675 675 676 AudioMixBuf Destroy(&MixBuf);676 AudioMixBufTerm(&MixBuf); 677 677 } 678 678
Note:
See TracChangeset
for help on using the changeset viewer.