fix(recording): compact silent mic discontinuities

This commit is contained in:
wiiiii123
2026-05-06 23:11:16 +07:00
parent 978e913045
commit e660b49241
5 changed files with 41 additions and 6 deletions
@@ -5,10 +5,10 @@
"helpers": {
"wgc-capture": {
"binaryName": "wgc-capture.exe",
"binarySha256": "a0e2f0b98a903f89ab4706a56623f141604c3a311102e8914c2780745e94c635",
"binarySha256": "88226bd499c820081a27264b40f37875d0949d9f921920738e05b7eaeb1a9e7d",
"sourceDir": "electron/native/wgc-capture",
"sourceFingerprint": "820d13741c659a0357d4d7944f3dbf4ce778b9716725b47ec088f573db0e7311",
"updatedAt": "2026-05-06T13:15:19.804Z"
"sourceFingerprint": "7190e148ede1fb1c573cc1866405d6345b0c35378a7e32499580bffacf1cc6d2",
"updatedAt": "2026-05-06T16:09:49.253Z"
},
"cursor-monitor": {
"binaryName": "cursor-monitor.exe",
Binary file not shown.
+10 -2
View File
@@ -231,6 +231,8 @@ static void writeCompanionAudioTimingMetadata(
metadataFile << ",\"insertedSilenceFrames\":" << capture.insertedSilenceFrames();
metadataFile << ",\"compactedDiscontinuityCount\":" << capture.compactedDiscontinuityCount();
metadataFile << ",\"compactedDiscontinuityFrames\":" << capture.compactedDiscontinuityFrames();
metadataFile << ",\"compactedSilentDiscontinuityCount\":" << capture.compactedSilentDiscontinuityCount();
metadataFile << ",\"compactedSilentDiscontinuityFrames\":" << capture.compactedSilentDiscontinuityFrames();
const uint32_t discontinuityCount = capture.dataDiscontinuityCount();
if (discontinuityCount > 0) {
metadataFile << ",\"dataDiscontinuityCount\":" << discontinuityCount;
@@ -448,7 +450,8 @@ int main(int argc, char* argv[]) {
loopback.dataDiscontinuityCount() > 0 ||
loopback.timestampErrorCount() > 0 ||
loopback.gapFillCount() > 0 ||
loopback.compactedDiscontinuityCount() > 0
loopback.compactedDiscontinuityCount() > 0 ||
loopback.compactedSilentDiscontinuityCount() > 0
) {
std::cerr << "WARNING: System audio timing metadata includes discontinuities="
<< loopback.dataDiscontinuityCount()
@@ -457,6 +460,8 @@ int main(int argc, char* argv[]) {
<< " insertedSilenceFrames=" << loopback.insertedSilenceFrames()
<< " compactedDiscontinuities=" << loopback.compactedDiscontinuityCount()
<< " compactedDiscontinuityFrames=" << loopback.compactedDiscontinuityFrames()
<< " compactedSilentDiscontinuities=" << loopback.compactedSilentDiscontinuityCount()
<< " compactedSilentDiscontinuityFrames=" << loopback.compactedSilentDiscontinuityFrames()
<< std::endl;
}
std::cout << "Audio path: " << config.audioOutputPath << std::endl;
@@ -466,7 +471,8 @@ int main(int argc, char* argv[]) {
micCapture.dataDiscontinuityCount() > 0 ||
micCapture.timestampErrorCount() > 0 ||
micCapture.gapFillCount() > 0 ||
micCapture.compactedDiscontinuityCount() > 0
micCapture.compactedDiscontinuityCount() > 0 ||
micCapture.compactedSilentDiscontinuityCount() > 0
) {
std::cerr << "WARNING: Microphone timing metadata includes discontinuities="
<< micCapture.dataDiscontinuityCount()
@@ -475,6 +481,8 @@ int main(int argc, char* argv[]) {
<< " insertedSilenceFrames=" << micCapture.insertedSilenceFrames()
<< " compactedDiscontinuities=" << micCapture.compactedDiscontinuityCount()
<< " compactedDiscontinuityFrames=" << micCapture.compactedDiscontinuityFrames()
<< " compactedSilentDiscontinuities=" << micCapture.compactedSilentDiscontinuityCount()
<< " compactedSilentDiscontinuityFrames=" << micCapture.compactedSilentDiscontinuityFrames()
<< std::endl;
}
std::cout << "Mic path: " << config.micOutputPath << std::endl;
@@ -14,6 +14,7 @@ constexpr uint32_t kMinimumGapFillThresholdMs = 50;
// 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 kSilentDiscontinuityCompactThresholdMs = 40;
constexpr uint32_t kBoundaryFadeInMs = 5;
int64_t queryPerformanceCounterHns() {
@@ -197,6 +198,8 @@ bool WasapiCapture::start() {
insertedSilenceFrames_ = 0;
compactedDiscontinuityCount_ = 0;
compactedDiscontinuityFrames_ = 0;
compactedSilentDiscontinuityCount_ = 0;
compactedSilentDiscontinuityFrames_ = 0;
fadeInFramesRemaining_ = 0;
writeWavHeader(outputFile_, 0);
@@ -478,8 +481,28 @@ void WasapiCapture::captureThread() {
}
UINT32 totalSamples = numFrames * channels;
const bool isSilentPacket = (flags & AUDCLNT_BUFFERFLAGS_SILENT) != 0;
const uint32_t silentCompactThresholdFrames =
(mixFormat_->nSamplesPerSec * kSilentDiscontinuityCompactThresholdMs) / 1000;
if (
hasDataDiscontinuity &&
isSilentPacket &&
framesWritten_.load() > 0 &&
numFrames > 0 &&
numFrames <= (silentCompactThresholdFrames > 0 ? silentCompactThresholdFrames : 1)
) {
compactedSilentDiscontinuityCount_.fetch_add(1);
compactedSilentDiscontinuityFrames_.fetch_add(numFrames);
captureClient_->ReleaseBuffer(numFrames);
hr = captureClient_->GetNextPacketSize(&packetLength);
if (FAILED(hr)) {
std::cerr << "WASAPI: GetNextPacketSize failed hr=0x" << std::hex << hr << std::dec << std::endl;
break;
}
continue;
}
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
if (isSilentPacket) {
pcmBuffer.assign(totalSamples, 0);
} else if (isFloat && bitsPerSample == 32 && sourceBytesPerSample >= 4) {
pcmBuffer.resize(totalSamples);
@@ -30,6 +30,8 @@ public:
uint64_t insertedSilenceFrames() const { return insertedSilenceFrames_.load(); }
uint32_t compactedDiscontinuityCount() const { return compactedDiscontinuityCount_.load(); }
uint64_t compactedDiscontinuityFrames() const { return compactedDiscontinuityFrames_.load(); }
uint32_t compactedSilentDiscontinuityCount() const { return compactedSilentDiscontinuityCount_.load(); }
uint64_t compactedSilentDiscontinuityFrames() const { return compactedSilentDiscontinuityFrames_.load(); }
private:
bool initializeCommon();
@@ -65,5 +67,7 @@ private:
std::atomic<uint64_t> insertedSilenceFrames_{0};
std::atomic<uint32_t> compactedDiscontinuityCount_{0};
std::atomic<uint64_t> compactedDiscontinuityFrames_{0};
std::atomic<uint32_t> compactedSilentDiscontinuityCount_{0};
std::atomic<uint64_t> compactedSilentDiscontinuityFrames_{0};
std::atomic<uint32_t> fadeInFramesRemaining_{0};
};