mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 07:16:02 +00:00
fix(recording): compact short mic discontinuities
This commit is contained in:
@@ -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.
@@ -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};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user