diff options
| author | Anton <anton@picapica.im> | 2026-09-03 21:01:17 +0400 |
|---|---|---|
| committer | Anton <anton@picapica.im> | 2026-09-03 21:01:17 +0400 |
| commit | e62dd7d30bec7a679013dcce8ec4bc2b2f842109 (patch) | |
| tree | 0be99751303e3c0b3306b9d79ca344897996a05d /pica-client/audiovideocallcontroller.h | |
| parent | c6649895d58bcfab864bcc33b131db222e45bfef (diff) | |
| download | pica-pica-e62dd7d30bec7a679013dcce8ec4bc2b2f842109.tar.gz pica-pica-e62dd7d30bec7a679013dcce8ec4bc2b2f842109.zip | |
pica-client: more improvements of echo cancellation
Diffstat (limited to 'pica-client/audiovideocallcontroller.h')
| -rw-r--r-- | pica-client/audiovideocallcontroller.h | 65 |
1 files changed, 56 insertions, 9 deletions
diff --git a/pica-client/audiovideocallcontroller.h b/pica-client/audiovideocallcontroller.h index e30f4c1..f7c9e37 100644 --- a/pica-client/audiovideocallcontroller.h +++ b/pica-client/audiovideocallcontroller.h @@ -85,20 +85,64 @@ private: // // m_savedCaptureGain is where the control was found at the start of the // call, put back in stopAudioPipeline(): this is the user's own setting - // and we are only borrowing it. m_captureGainSteps bounds how far we will - // go, so a microphone that clips for some reason turning it down cannot - // fix - a broken preamp, someone shouting into it - ends up quiet rather - // than muted. + // and we are only borrowing it. CaptureGainControl *m_captureGain; double m_savedCaptureGain; bool m_haveSavedCaptureGain; - int m_captureGainSteps; - static const int kMaxCaptureGainSteps = 12; + // This is a calibration that runs at the start of a call and then stops - + // NOT a gain control that rides the level for the call's duration. The + // difference matters: an adaptive echo canceller can only track a + // stationary echo path, and moving the microphone gain moves that path. + // See the AGC comment in EchoCanceller's constructor, which says the same + // thing about the reason speexdsp's own AGC is left switched off. + // + // So every adjustment resets the canceller, and once m_gainCalibrating is + // false nothing touches the control again until the call ends. + bool m_gainCalibrating; + int m_captureGainSteps; - // Never go below this fraction of the control's travel; past it we are - // making the user inaudible to fix a problem they can hear about instead. - static constexpr double kMinCaptureGain = 0.05; + // dB reading when calibration opened, and whether the platform would give + // us one. Bounding the total cut in decibels rather than as a fraction of + // the control's travel is the whole point: a fraction means different + // things on a hardware mixer (linear in dB) and on a sound server or + // WASAPI endpoint (roughly cubic), which is how an earlier version of this + // managed to wind a microphone down to silence. + double m_gainStartDb; + bool m_haveGainDb; + + // Consecutive adjustments that moved the control but did not reduce the + // clipping. Means the stage actually overloading is one we cannot reach - + // an analog mic boost ahead of the converter, or Windows' separate + // "Microphone Boost" - and that turning our control down further will + // silence the user without ever fixing it. + int m_gainIneffectiveSteps; + double m_lastPinnedPercent; + + // Reports to ignore after an adjustment, while audio captured at the old + // setting drains out of the pipeline. + int m_gainSettleReports; + + static const int kMaxCaptureGainSteps = 6; + + // Bound used when the control will not report decibels at all, where we + // are working blind and a wrong guess is what silences a microphone. + static const int kMaxBlindGainSteps = 2; + static const int kMaxGainIneffectiveSteps = 2; + static const int kGainSettleReports = 1; + + // How long the calibration window stays open, in milliseconds of call + // time. Long enough that someone who says nothing for the first few + // seconds still gets calibrated, short enough to be over before the + // conversation proper. + static const int kGainCalibrationMs = 20000; + + // Hard ceiling on the total cut, in dB below where the user had it. Past + // this the problem is not one we are going to fix by turning a knob. + static constexpr double kMaxGainReductionDb = 24.0; + + // An adjustment that achieves less than this much is not doing anything. + static constexpr double kMinEffectiveStepDb = 0.5; // Sequence number / capture-clock timestamp stamped onto outgoing // 0x76 audio packets (see PICA_PROTO_CALL_PACKET_HDRSIZE). @@ -123,6 +167,9 @@ private: void startCaptureGainControl(const QString &captureDevice); void stopCaptureGainControl(); + // Ends the calibration window, logging why. Idempotent. + void closeGainCalibration(const QString &why); + void playEarpieceTone(void (TonePlayer::*tone)()); void playRingTone(); void stopTones(); |
