fix(recording): compact short mic discontinuities

This commit is contained in:
wiiiii123
2026-05-06 20:16:32 +07:00
parent ae0378cee4
commit 63a8a5bf43
5 changed files with 30 additions and 8 deletions
@@ -5,10 +5,10 @@
"helpers": {
"wgc-capture": {
"binaryName": "wgc-capture.exe",
"binarySha256": "b016da7435ba68b9c235e85818b5f4e8c1647f2386b4f2205e9a690cd057f908",
"binarySha256": "a0e2f0b98a903f89ab4706a56623f141604c3a311102e8914c2780745e94c635",
"sourceDir": "electron/native/wgc-capture",
"sourceFingerprint": "7ef55b0d4bb9674de2b263e9dad2de2a593d0cb6aa09aea9ab3dc1832010a9d0",
"updatedAt": "2026-05-06T11:48:48.808Z"
"sourceFingerprint": "820d13741c659a0357d4d7944f3dbf4ce778b9716725b47ec088f573db0e7311",
"updatedAt": "2026-05-06T13:15:19.804Z"
},
"cursor-monitor": {
"binaryName": "cursor-monitor.exe",
Binary file not shown.
+10 -2
View File
@@ -229,6 +229,8 @@ static void writeCompanionAudioTimingMetadata(
metadataFile << ",\"channels\":" << capture.channelCount();
metadataFile << ",\"gapFillCount\":" << capture.gapFillCount();
metadataFile << ",\"insertedSilenceFrames\":" << capture.insertedSilenceFrames();
metadataFile << ",\"compactedDiscontinuityCount\":" << capture.compactedDiscontinuityCount();
metadataFile << ",\"compactedDiscontinuityFrames\":" << capture.compactedDiscontinuityFrames();
const uint32_t discontinuityCount = capture.dataDiscontinuityCount();
if (discontinuityCount > 0) {
metadataFile << ",\"dataDiscontinuityCount\":" << discontinuityCount;
@@ -445,13 +447,16 @@ int main(int argc, char* argv[]) {
if (
loopback.dataDiscontinuityCount() > 0 ||
loopback.timestampErrorCount() > 0 ||
loopback.gapFillCount() > 0
loopback.gapFillCount() > 0 ||
loopback.compactedDiscontinuityCount() > 0
) {
std::cerr << "WARNING: System audio timing metadata includes discontinuities="
<< loopback.dataDiscontinuityCount()
<< " timestampErrors=" << loopback.timestampErrorCount()
<< " gapFills=" << loopback.gapFillCount()
<< " insertedSilenceFrames=" << loopback.insertedSilenceFrames()
<< " compactedDiscontinuities=" << loopback.compactedDiscontinuityCount()
<< " compactedDiscontinuityFrames=" << loopback.compactedDiscontinuityFrames()
<< std::endl;
}
std::cout << "Audio path: " << config.audioOutputPath << std::endl;
@@ -460,13 +465,16 @@ int main(int argc, char* argv[]) {
if (
micCapture.dataDiscontinuityCount() > 0 ||
micCapture.timestampErrorCount() > 0 ||
micCapture.gapFillCount() > 0
micCapture.gapFillCount() > 0 ||
micCapture.compactedDiscontinuityCount() > 0
) {
std::cerr << "WARNING: Microphone timing metadata includes discontinuities="
<< micCapture.dataDiscontinuityCount()
<< " timestampErrors=" << micCapture.timestampErrorCount()
<< " gapFills=" << micCapture.gapFillCount()
<< " insertedSilenceFrames=" << micCapture.insertedSilenceFrames()
<< " compactedDiscontinuities=" << micCapture.compactedDiscontinuityCount()
<< " compactedDiscontinuityFrames=" << micCapture.compactedDiscontinuityFrames()
<< std::endl;
}
std::cout << "Mic path: " << config.micOutputPath << std::endl;
@@ -11,7 +11,9 @@ namespace {
constexpr int64_t kHundredNanosecondsPerSecond = 10000000;
constexpr uint64_t kSilenceWriteChunkFrames = 4096;
constexpr uint32_t kMinimumGapFillThresholdMs = 50;
constexpr uint32_t kDiscontinuityGapFillThresholdMs = 10;
// Wireless headsets can flag short WASAPI discontinuities that are less audible
// when compacted and later duration-corrected than when rendered as hard silence.
constexpr uint32_t kDiscontinuityGapFillThresholdMs = 140;
constexpr uint32_t kBoundaryFadeInMs = 5;
int64_t queryPerformanceCounterHns() {
@@ -193,6 +195,8 @@ bool WasapiCapture::start() {
timestampErrorCount_ = 0;
gapFillCount_ = 0;
insertedSilenceFrames_ = 0;
compactedDiscontinuityCount_ = 0;
compactedDiscontinuityFrames_ = 0;
fadeInFramesRemaining_ = 0;
writeWavHeader(outputFile_, 0);
@@ -461,8 +465,14 @@ void WasapiCapture::captureThread() {
const uint64_t gapThresholdFrames =
gapThresholdFrameCount > 0 ? gapThresholdFrameCount : 1;
if (expectedStartFrame > writtenFrames + gapThresholdFrames) {
writeSilenceFrames(expectedStartFrame - writtenFrames, channels);
if (expectedStartFrame > writtenFrames) {
const uint64_t missingFrames = expectedStartFrame - writtenFrames;
if (missingFrames > gapThresholdFrames) {
writeSilenceFrames(missingFrames, channels);
} else if (hasDataDiscontinuity) {
compactedDiscontinuityCount_.fetch_add(1);
compactedDiscontinuityFrames_.fetch_add(missingFrames);
}
}
}
}
@@ -28,6 +28,8 @@ public:
uint32_t timestampErrorCount() const { return timestampErrorCount_.load(); }
uint32_t gapFillCount() const { return gapFillCount_.load(); }
uint64_t insertedSilenceFrames() const { return insertedSilenceFrames_.load(); }
uint32_t compactedDiscontinuityCount() const { return compactedDiscontinuityCount_.load(); }
uint64_t compactedDiscontinuityFrames() const { return compactedDiscontinuityFrames_.load(); }
private:
bool initializeCommon();
@@ -61,5 +63,7 @@ private:
std::atomic<uint32_t> timestampErrorCount_{0};
std::atomic<uint32_t> gapFillCount_{0};
std::atomic<uint64_t> insertedSilenceFrames_{0};
std::atomic<uint32_t> compactedDiscontinuityCount_{0};
std::atomic<uint64_t> compactedDiscontinuityFrames_{0};
std::atomic<uint32_t> fadeInFramesRemaining_{0};
};