LCOV - code coverage report
Current view: top level - foo/src/media/audio/audio-processing - webrtc.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 0 76 0.0 %
Date: 2025-12-18 10:07:43 Functions: 0 43 0.0 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2025 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  This program is free software: you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation, either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "webrtc.h"
      19             : #include "logger.h"
      20             : 
      21             : #include <webrtc/modules/audio_processing/include/audio_processing.h>
      22             : 
      23             : namespace jami {
      24             : 
      25             : inline size_t
      26           0 : webrtcFrameSize(AudioFormat format)
      27             : {
      28           0 :     return (size_t) (webrtc::AudioProcessing::kChunkSizeMs * format.sample_rate / 1000);
      29             : }
      30             : 
      31             : constexpr int webrtcNoError = webrtc::AudioProcessing::kNoError;
      32             : 
      33           0 : WebRTCAudioProcessor::WebRTCAudioProcessor(AudioFormat format, unsigned /* frameSize */)
      34           0 :     : AudioProcessor(format.withSampleFormat(AV_SAMPLE_FMT_FLTP), webrtcFrameSize(format))
      35             : {
      36           0 :     JAMI_LOG("[webrtc-ap] WebRTCAudioProcessor, frame size = {:d} (={:d} ms), channels = {:d}",
      37             :              frameSize_,
      38             :              frameDurationMs_,
      39             :              format_.nb_channels);
      40           0 :     webrtc::Config config;
      41           0 :     config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
      42           0 :     config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(true));
      43             : 
      44           0 :     apm.reset(webrtc::AudioProcessing::Create(config));
      45             : 
      46           0 :     webrtc::StreamConfig streamConfig((int) format_.sample_rate, (int) format_.nb_channels);
      47             :     webrtc::ProcessingConfig pconfig = {
      48             :         streamConfig, /* input stream */
      49             :         streamConfig, /* output stream */
      50             :         streamConfig, /* reverse input stream */
      51             :         streamConfig, /* reverse output stream */
      52           0 :     };
      53             : 
      54           0 :     if (apm->Initialize(pconfig) != webrtcNoError) {
      55           0 :         JAMI_ERROR("[webrtc-ap] Error initialising audio processing module");
      56             :     }
      57           0 : }
      58             : 
      59             : void
      60           0 : WebRTCAudioProcessor::enableNoiseSuppression(bool enabled)
      61             : {
      62           0 :     JAMI_LOG("[webrtc-ap] enableNoiseSuppression {}", enabled);
      63           0 :     if (apm->noise_suppression()->Enable(enabled) != webrtcNoError) {
      64           0 :         JAMI_ERROR("[webrtc-ap] Error enabling noise suppression");
      65             :     }
      66           0 :     if (apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kVeryHigh) != webrtcNoError) {
      67           0 :         JAMI_ERROR("[webrtc-ap] Error setting noise suppression level");
      68             :     }
      69           0 :     if (apm->high_pass_filter()->Enable(enabled) != webrtcNoError) {
      70           0 :         JAMI_ERROR("[webrtc-ap] Error enabling high pass filter");
      71             :     }
      72           0 : }
      73             : 
      74             : void
      75           0 : WebRTCAudioProcessor::enableAutomaticGainControl(bool enabled)
      76             : {
      77           0 :     JAMI_LOG("[webrtc-ap] enableAutomaticGainControl {}", enabled);
      78           0 :     if (apm->gain_control()->Enable(enabled) != webrtcNoError) {
      79           0 :         JAMI_ERROR("[webrtc-ap] Error enabling automatic gain control");
      80             :     }
      81           0 :     if (apm->gain_control()->set_analog_level_limits(0, 255) != webrtcNoError) {
      82           0 :         JAMI_ERROR("[webrtc-ap] Error setting automatic gain control analog level limits");
      83             :     }
      84           0 :     if (apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveAnalog) != webrtcNoError) {
      85           0 :         JAMI_ERROR("[webrtc-ap] Error setting automatic gain control mode");
      86             :     }
      87           0 : }
      88             : 
      89             : void
      90           0 : WebRTCAudioProcessor::enableEchoCancel(bool enabled)
      91             : {
      92           0 :     JAMI_LOG("[webrtc-ap] enableEchoCancel {}", enabled);
      93             : 
      94           0 :     if (apm->echo_cancellation()->Enable(enabled) != webrtcNoError) {
      95           0 :         JAMI_ERROR("[webrtc-ap] Error enabling echo cancellation");
      96             :     }
      97           0 :     if (apm->echo_cancellation()->set_suppression_level(webrtc::EchoCancellation::SuppressionLevel::kHighSuppression)
      98           0 :         != webrtcNoError) {
      99           0 :         JAMI_ERROR("[webrtc-ap] Error setting echo cancellation level");
     100             :     }
     101           0 :     if (apm->echo_cancellation()->enable_drift_compensation(true) != webrtcNoError) {
     102           0 :         JAMI_ERROR("[webrtc-ap] Error enabling echo cancellation drift compensation");
     103             :     }
     104           0 : }
     105             : 
     106             : void
     107           0 : WebRTCAudioProcessor::enableVoiceActivityDetection(bool enabled)
     108             : {
     109           0 :     JAMI_LOG("[webrtc-ap] enableVoiceActivityDetection {}", enabled);
     110           0 :     if (apm->voice_detection()->Enable(enabled) != webrtcNoError) {
     111           0 :         JAMI_ERROR("[webrtc-ap] Error enabling voice activation detection");
     112             :     }
     113           0 :     if (apm->voice_detection()->set_likelihood(webrtc::VoiceDetection::kVeryLowLikelihood) != webrtcNoError) {
     114           0 :         JAMI_ERROR("[webrtc-ap] Error setting voice detection likelihood");
     115             :     }
     116             :     // asserted to be 10 in voice_detection_impl.cc
     117           0 :     if (apm->voice_detection()->set_frame_size_ms(10) != webrtcNoError) {
     118           0 :         JAMI_ERROR("[webrtc-ap] Error setting voice detection frame size");
     119             :     }
     120           0 : }
     121             : 
     122             : std::shared_ptr<AudioFrame>
     123           0 : WebRTCAudioProcessor::getProcessed()
     124             : {
     125           0 :     if (tidyQueues()) {
     126           0 :         return {};
     127             :     }
     128             : 
     129           0 :     int driftSamples = playbackQueue_.samples() - recordQueue_.samples();
     130             : 
     131           0 :     auto playback = playbackQueue_.dequeue();
     132           0 :     auto record = recordQueue_.dequeue();
     133           0 :     if (!playback || !record) {
     134           0 :         return {};
     135             :     }
     136           0 :     webrtc::StreamConfig sc((int) format_.sample_rate, (int) format_.nb_channels);
     137             : 
     138             :     // process reverse in place
     139           0 :     float** playData = (float**) playback->pointer()->extended_data;
     140           0 :     if (apm->ProcessReverseStream(playData, sc, sc, playData) != webrtcNoError) {
     141           0 :         JAMI_ERR("[webrtc-ap] ProcessReverseStream failed");
     142             :     }
     143             : 
     144             :     // process deinterleaved float recorded data
     145             :     // TODO: maybe implement this to see if it's better than automatic drift compensation
     146             :     // (it MUST be called prior to ProcessStream)
     147             :     // delay = (t_render - t_analyze) + (t_process - t_capture)
     148           0 :     if (apm->set_stream_delay_ms(0) != webrtcNoError) {
     149           0 :         JAMI_ERR("[webrtc-ap] set_stream_delay_ms failed");
     150             :     }
     151             : 
     152           0 :     if (apm->gain_control()->set_stream_analog_level(analogLevel_) != webrtcNoError) {
     153           0 :         JAMI_ERR("[webrtc-ap] set_stream_analog_level failed");
     154             :     }
     155           0 :     apm->echo_cancellation()->set_stream_drift_samples(driftSamples);
     156             : 
     157             :     // process in place
     158           0 :     float** recData = (float**) record->pointer()->extended_data;
     159           0 :     if (apm->ProcessStream(recData, sc, sc, recData) != webrtcNoError) {
     160           0 :         JAMI_ERR("[webrtc-ap] ProcessStream failed");
     161             :     }
     162             : 
     163           0 :     analogLevel_ = apm->gain_control()->stream_analog_level();
     164           0 :     record->has_voice = apm->voice_detection()->is_enabled()
     165           0 :                         && getStabilizedVoiceActivity(apm->voice_detection()->stream_has_voice());
     166           0 :     return record;
     167           0 : }
     168             : 
     169             : } // namespace jami

Generated by: LCOV version 1.14