Changeset 103567 in vbox for trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp
- Timestamp:
- Feb 26, 2024 12:53:47 PM (9 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp
r103530 r103567 66 66 #endif 67 67 68 #include <iprt/circbuf.h> 68 69 #include <iprt/ctype.h> 69 70 #include <iprt/dir.h> … … 794 795 795 796 if (cbWrittenTotal != cbToWriteTotal) 796 RTTestFailed(g_hTest, "Test #%RU32: Playback ended unexpectedly (%RU32/%RU32 played)\n", 797 { 798 RTTestFailed(g_hTest, "Test #%RU32: Playback ended unexpectedly (%RU32 played, expected %RU32)\n", 797 799 idxTest, cbWrittenTotal, cbToWriteTotal); 800 rc = cbWrittenTotal > cbToWriteTotal ? VERR_BUFFER_OVERFLOW : VERR_BUFFER_UNDERFLOW; 801 } 798 802 799 803 if (RT_SUCCESS(rc)) … … 850 854 if (RT_SUCCESS(rc)) 851 855 { 852 uint32_t cb RecTotal = 0; /* Counts everything, including silence / whatever. */853 uint32_t cbTestToRec = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, pParms->msDuration);854 uint32_t cb TestRec = 0;856 uint32_t cbToReadTotal = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, pParms->msDuration); 857 AssertStmt(cbToReadTotal, rc = VERR_INVALID_PARAMETER); 858 uint32_t cbReadTotal = 0; /* Counts the read test tone data (w/o any beacons). */ 855 859 856 860 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Recording %RU32 bytes total (%RU32ms timeout)\n", 857 idxTest, cbT estToRec, pTstEnv->msTimeout);861 idxTest, cbToReadTotal, pTstEnv->msTimeout); 858 862 859 863 /* Failsafe if invalid timeout is set. */ … … 885 889 AudioTestObjAddMetadataStr(Obj, "beacon_pre_bytes=%RU32\n", cbBeacon); 886 890 AudioTestObjAddMetadataStr(Obj, "beacon_post_bytes=%RU32\n", cbBeacon); 887 AudioTestObjAddMetadataStr(Obj, "stream_to_record_bytes=%RU32\n", cbT estToRec);891 AudioTestObjAddMetadataStr(Obj, "stream_to_record_bytes=%RU32\n", cbToReadTotal); 888 892 AudioTestObjAddMetadataStr(Obj, "stream_buffer_size_ms=%RU32\n", pIoOpts->cMsBufferSize); 889 893 AudioTestObjAddMetadataStr(Obj, "stream_prebuf_size_ms=%RU32\n", pIoOpts->cMsPreBuffer); … … 892 896 AudioTestObjAddMetadataStr(Obj, "device_scheduling_hint_ms=%RU32\n", pIoOpts->cMsSchedulingHint); 893 897 894 uint8_t abSamples[16384]; 895 uint32_t const cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples)); 898 PRTCIRCBUF pCircBuf; 899 rc = RTCircBufCreate(&pCircBuf, _64K); 900 AssertRCReturn(rc, rc); 896 901 897 902 uint64_t const nsStarted = RTTimeNanoTS(); … … 904 909 while (!g_fTerminate) 905 910 { 906 uint64_t const nsNow = RTTimeNanoTS(); 911 uint64_t const nsNow = RTTimeNanoTS(); 912 913 void *pvBlock; 914 size_t cbBlock; 907 915 908 916 /* 909 * Anything we can read?917 * Anything we can capture from the stream? 910 918 */ 911 919 uint32_t const cbCanRead = AudioTestMixStreamGetReadable(pMix); 912 920 if (cbCanRead) 913 921 { 914 if (g_uVerbosity >= 3) 915 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Stream is readable with %RU64ms (%RU32 bytes)\n", 916 idxTest, PDMAudioPropsBytesToMilli(pMix->pProps, cbCanRead), cbCanRead); 917 918 uint32_t const cbToRead = RT_MIN(cbCanRead, cbSamplesAligned); 919 uint32_t cbRecorded = 0; 920 rc = AudioTestMixStreamCapture(pMix, abSamples, cbToRead, &cbRecorded); 921 if (RT_SUCCESS(rc)) 922 RTCircBufAcquireWriteBlock(pCircBuf, cbCanRead, &pvBlock, &cbBlock); 923 924 uint32_t cbCaptured = 0; 925 if (cbBlock) 922 926 { 923 /* Flag indicating whether the whole block we're going to play is silence or not. */ 924 bool const fIsAllSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, abSamples, cbRecorded); 925 926 cbRecTotal += cbRecorded; /* Do a bit of accounting. */ 927 928 switch (enmState) 929 { 930 case AUDIOTESTSTATE_PRE: 931 RT_FALL_THROUGH(); 932 case AUDIOTESTSTATE_POST: 933 { 934 bool fGoToNextStage = false; 935 936 if ( AudioTestBeaconGetSize(&Beacon) 937 && !AudioTestBeaconIsComplete(&Beacon)) 938 { 939 bool const fStarted = AudioTestBeaconGetRemaining(&Beacon) == AudioTestBeaconGetSize(&Beacon); 940 941 size_t uOff; 942 rc = AudioTestBeaconAddConsecutive(&Beacon, abSamples, cbRecorded, &uOff); 943 if (RT_SUCCESS(rc)) 944 { 945 /* 946 * When being in the AUDIOTESTSTATE_PRE state, we might get more audio data 947 * than we need for the pre-beacon to complete. In other words, that "more data" 948 * needs to be counted to the actual recorded test tone data then. 949 */ 950 if (enmState == AUDIOTESTSTATE_PRE) 951 cbTestRec += cbRecorded - (uint32_t)uOff; 952 } 953 954 if ( fStarted 955 && g_uVerbosity >= 3) 956 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 957 "Test #%RU32: Detection of %s beacon started (%RU32ms recorded so far)\n", 958 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType), 959 PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbRecTotal)); 960 961 if (AudioTestBeaconIsComplete(&Beacon)) 962 { 963 if (g_uVerbosity >= 2) 964 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Detected %s beacon\n", 965 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType)); 966 fGoToNextStage = true; 967 } 968 } 969 else 970 fGoToNextStage = true; 971 972 if (fGoToNextStage) 973 { 974 if (enmState == AUDIOTESTSTATE_PRE) 975 enmState = AUDIOTESTSTATE_RUN; 976 else if (enmState == AUDIOTESTSTATE_POST) 977 enmState = AUDIOTESTSTATE_DONE; 978 } 979 break; 980 } 981 982 case AUDIOTESTSTATE_RUN: 983 { 984 /* Whether we count all silence as recorded data or not. 985 * Currently we don't, as otherwise consequtively played tones will be cut off in the end. */ 986 if (!fIsAllSilence) 987 { 988 uint32_t const cbToAddMax = cbTestToRec - cbTestRec; 989 990 /* Don't read more than we're told to. 991 * After the actual test tone data there might come a post beacon which also 992 * needs to be handled in the AUDIOTESTSTATE_POST state then. */ 993 if (cbRecorded > cbToAddMax) 994 cbRecorded = cbToAddMax; 995 996 cbTestRec += cbRecorded; 997 } 998 999 if (cbTestToRec - cbTestRec == 0) /* Done recording the test tone? */ 1000 { 1001 enmState = AUDIOTESTSTATE_POST; 1002 1003 if (g_uVerbosity >= 2) 1004 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Recording tone data done\n", idxTest); 1005 1006 if (AudioTestBeaconGetSize(&Beacon)) 1007 { 1008 /* Re-use the beacon object, but this time it's the post beacon. */ 1009 AudioTestBeaconInit(&Beacon, (uint8_t)pParms->Hdr.idxTest, AUDIOTESTTONEBEACONTYPE_PLAY_POST, 1010 &pStream->Cfg.Props); 1011 if (g_uVerbosity >= 2) 1012 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 1013 "Test #%RU32: Waiting for %s beacon ...\n", 1014 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType)); 1015 } 1016 } 1017 break; 1018 } 1019 1020 case AUDIOTESTSTATE_DONE: 1021 { 1022 /* Nothing to do here. */ 1023 break; 1024 } 1025 1026 default: 1027 AssertFailed(); 1028 break; 1029 } 927 rc = AudioTestMixStreamCapture(pMix, pvBlock, cbBlock, &cbCaptured); 928 if (RT_FAILURE(rc)) 929 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Reading from stream failed with %Rrc\n", idxTest, rc); 930 931 if (g_uVerbosity >= 2) 932 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Stream is readable with %RU64ms (%RU32 bytes), captured %RU64ms (%RU32 bytes)\n", 933 idxTest, 934 PDMAudioPropsBytesToMilli(pMix->pProps, cbCanRead), cbCanRead, 935 PDMAudioPropsBytesToMilli(pMix->pProps, cbCaptured), cbCaptured); 936 937 if (RT_FAILURE(rc)) 938 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Capturing failed with %Rrc\n", 939 idxTest, rc); 1030 940 } 1031 941 1032 if (cbRecorded) 1033 { 1034 /* Always write (record) everything, no matter if the current audio contains complete silence or not. 1035 * Might be also become handy later if we want to have a look at start/stop timings and so on. */ 1036 rc = AudioTestObjWrite(Obj, abSamples, cbRecorded); 1037 AssertRCBreak(rc); 1038 } 1039 1040 if (enmState == AUDIOTESTSTATE_DONE) /* Bail out when in state "done". */ 1041 break; 942 RTCircBufReleaseWriteBlock(pCircBuf, cbCaptured); 1042 943 } 1043 944 else if (AudioTestMixStreamIsOkay(pMix)) … … 1057 958 } 1058 959 960 /* 961 * Process our buffer. 962 */ 963 size_t cbBlockToAcq; 964 if (pTstEnv->fSelftest) /* For self-test mode we want to have a bit more randomness. */ 965 { 966 size_t const u = RTCircBufUsed(pCircBuf); 967 size_t const r = RTRandU32Ex(1, RTCircBufSize(pCircBuf)); 968 cbBlockToAcq = PDMAudioPropsFloorBytesToFrame(pMix->pProps, RT_MIN(u, r)); 969 } 970 else 971 cbBlockToAcq = PDMAudioPropsFloorBytesToFrame(pMix->pProps, RTCircBufUsed(pCircBuf)); 972 973 RTCircBufAcquireReadBlock(pCircBuf, cbBlockToAcq, &pvBlock, &cbBlock); 974 if (!cbBlock) 975 continue; 976 977 /* Flag indicating whether the whole block we've captured is silence or not. */ 978 bool const fIsAllSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBlock, cbBlock); 979 uint32_t cbRead = 0; 980 981 switch (enmState) 982 { 983 case AUDIOTESTSTATE_PRE: 984 RT_FALL_THROUGH(); 985 case AUDIOTESTSTATE_POST: 986 { 987 bool fGoToNextStage = false; 988 989 if ( AudioTestBeaconGetSize(&Beacon) 990 && !AudioTestBeaconIsComplete(&Beacon)) 991 { 992 bool const fStarted = AudioTestBeaconGetRemaining(&Beacon) == AudioTestBeaconGetSize(&Beacon); 993 994 size_t uOff; 995 int rc2 = AudioTestBeaconAddConsecutive(&Beacon, (uint8_t *)pvBlock, cbBlock, &uOff); 996 if ( RT_SUCCESS(rc2) 997 && uOff) 998 cbRead = uOff; 999 1000 if ( fStarted 1001 && g_uVerbosity >= 2) 1002 { 1003 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 1004 "Test #%RU32: Detection of %s beacon started (%RU32ms recorded so far)\n", 1005 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType), 1006 PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbReadTotal)); 1007 } 1008 1009 if (AudioTestBeaconIsComplete(&Beacon)) 1010 { 1011 if (g_uVerbosity >= 2) 1012 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Detection of %s beacon complete\n", 1013 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType)); 1014 fGoToNextStage = true; 1015 } 1016 } 1017 else 1018 fGoToNextStage = true; 1019 1020 if (fGoToNextStage) 1021 { 1022 if (enmState == AUDIOTESTSTATE_PRE) 1023 enmState = AUDIOTESTSTATE_RUN; 1024 else if (enmState == AUDIOTESTSTATE_POST) 1025 enmState = AUDIOTESTSTATE_DONE; 1026 } 1027 break; 1028 } 1029 1030 case AUDIOTESTSTATE_RUN: 1031 { 1032 /* Whether we count all silence as recorded data or not. 1033 * Currently we don't, as otherwise consequtively played tones will be cut off in the end. */ 1034 bool const fRecord = !fIsAllSilence; 1035 if (fRecord) 1036 { 1037 /* Don't read more than we're told to. 1038 * After the actual test tone data there might come a post beacon which also 1039 * needs to be handled in the AUDIOTESTSTATE_POST state then. */ 1040 if (cbReadTotal + cbBlock > cbToReadTotal) 1041 { 1042 AssertBreakStmt(cbToReadTotal >= cbReadTotal, rc = VERR_INTERNAL_ERROR); 1043 cbRead = cbToReadTotal - cbReadTotal; 1044 } 1045 else 1046 cbRead = cbBlock; 1047 1048 cbReadTotal += cbRead; 1049 AssertBreakStmt(cbReadTotal <= cbToReadTotal, rc = VERR_INTERNAL_ERROR); 1050 } 1051 1052 /* Done recording the test tone? */ 1053 if (cbReadTotal + cbRead == cbToReadTotal) 1054 { 1055 enmState = AUDIOTESTSTATE_POST; 1056 1057 if (g_uVerbosity >= 2) 1058 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Recording tone data done\n", idxTest); 1059 1060 if (AudioTestBeaconGetSize(&Beacon)) 1061 { 1062 /* Re-use the beacon object, but this time it's the post beacon. */ 1063 AudioTestBeaconInit(&Beacon, (uint8_t)pParms->Hdr.idxTest, AUDIOTESTTONEBEACONTYPE_PLAY_POST, 1064 &pStream->Cfg.Props); 1065 if (g_uVerbosity >= 2) 1066 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, 1067 "Test #%RU32: Waiting for %s beacon ...\n", 1068 idxTest, AudioTestBeaconTypeGetName(Beacon.enmType)); 1069 } 1070 } 1071 break; 1072 } 1073 1074 case AUDIOTESTSTATE_DONE: 1075 { 1076 /* Nothing to do here. */ 1077 break; 1078 } 1079 1080 default: 1081 AssertFailed(); 1082 break; 1083 } 1084 1085 if (cbRead) 1086 { 1087 if (g_uVerbosity >= 3) 1088 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Read data (%RU32 bytes):\n" 1089 "%.*Rhxd\n", 1090 idxTest, cbRead, cbRead, pvBlock); 1091 1092 /* Always write (record) everything, no matter if the current audio contains complete silence or not. 1093 * Might be also become handy later if we want to have a look at start/stop timings and so on. */ 1094 rc = AudioTestObjWrite(Obj, pvBlock, cbRead); 1095 AssertRCBreak(rc); 1096 } 1097 1098 if (g_uVerbosity >= 2) 1099 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Processed %RU64ms (%RU32 bytes)\n", 1100 idxTest, PDMAudioPropsBytesToMilli(pMix->pProps, cbRead), cbRead); 1101 1102 RTCircBufReleaseReadBlock(pCircBuf, cbRead); 1103 1104 if (enmState == AUDIOTESTSTATE_DONE) /* Bail out when in state "done". */ 1105 break; 1106 1059 1107 /* Fail-safe in case something screwed up while playing back. */ 1060 1108 uint64_t const cNsElapsed = nsNow - nsStarted; … … 1068 1116 if (RT_FAILURE(rc)) 1069 1117 break; 1070 } 1118 } /* while */ 1071 1119 1072 1120 if (g_uVerbosity >= 2) 1073 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Recorded %RU32 bytes total\n", idxTest, cbRecTotal); 1074 if (cbTestRec != cbTestToRec) 1075 { 1076 RTTestFailed(g_hTest, "Test #%RU32: Recording ended unexpectedly (%RU32/%RU32 recorded)\n", 1077 idxTest, cbTestRec, cbTestToRec); 1078 rc = VERR_WRONG_ORDER; /** @todo Find a better rc. */ 1121 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%RU32: Recorded %RU32 bytes total\n", idxTest, cbReadTotal); 1122 if (cbReadTotal != cbToReadTotal) 1123 { 1124 RTTestFailed(g_hTest, "Test #%RU32: Recording ended unexpectedly (%RU32 read, expected %RU32)\n", 1125 idxTest, cbReadTotal, cbToReadTotal); 1126 int rc2 = cbReadTotal > cbToReadTotal ? VERR_BUFFER_OVERFLOW : VERR_BUFFER_UNDERFLOW; 1127 if (RT_SUCCESS(rc)) 1128 rc = rc2; 1079 1129 } 1080 1130 … … 1085 1135 if (RT_SUCCESS(rc)) 1086 1136 rc = rc2; 1137 1138 RTCircBufDestroy(pCircBuf); 1087 1139 } 1088 1140
Note:
See TracChangeset
for help on using the changeset viewer.