Ring Daemon 16.0.0
Loading...
Searching...
No Matches
audio_processor.h
Go to the documentation of this file.
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#pragma once
18
19#include "noncopyable.h"
23#include "media/libav_deps.h"
24#include "logger.h"
25
26#include <atomic>
27#include <memory>
28
29namespace jami {
30
32{
33private:
35
36public:
37 AudioProcessor(AudioFormat format, unsigned frameSize)
38 : playbackQueue_(format, (int) frameSize)
39 , recordQueue_(format, (int) frameSize)
41 , format_(format)
42 , frameSize_(frameSize)
43 , frameDurationMs_((unsigned int) (frameSize_ * (1.0 / format_.sample_rate) * 1000))
44 {}
45 virtual ~AudioProcessor() = default;
46
47 virtual void putRecorded(std::shared_ptr<AudioFrame>&& buf)
48 {
49 recordStarted_ = true;
51 return;
52 enqueue(recordQueue_, std::move(buf));
53 };
54 virtual void putPlayback(const std::shared_ptr<AudioFrame>& buf)
55 {
56 playbackStarted_ = true;
57 if (!recordStarted_)
58 return;
59 auto copy = buf;
60 enqueue(playbackQueue_, std::move(copy));
61 };
62
66 virtual std::shared_ptr<AudioFrame> getProcessed() = 0;
67
71 virtual void enableEchoCancel(bool enabled) = 0;
72
77 virtual void enableNoiseSuppression(bool enabled) = 0;
78
82 virtual void enableAutomaticGainControl(bool enabled) = 0;
83
87 virtual void enableVoiceActivityDetection(bool enabled) = 0;
88
89protected:
92 std::unique_ptr<Resampler> resampler_;
93 std::atomic_bool playbackStarted_;
94 std::atomic_bool recordStarted_;
96 unsigned int frameSize_;
97 unsigned int frameDurationMs_;
98
99 // artificially extend voice activity by this long
100 unsigned int forceMinimumVoiceActivityMs {1000};
101
102 // current number of frames to force the voice activity to be true
104
105 // voice activity must be active for this long _before_ it is considered legitimate
107
108 // current number of frames that the voice activity has been true
109 unsigned int consecutiveActiveFrames {0};
110
118 {
121 while (recordQueue_.samples() > recordFrameSize * 10
123 JAMI_LOG("record overflow {:d} / {:d} - playback: {:d}", recordQueue_.samples(), frameSize_, playbackQueue_.samples());
125 }
128 JAMI_LOG("playback overflow {:d} / {:d} - record: {:d}", playbackQueue_.samples(), frameSize_, recordQueue_.samples());
130 }
133 // If there are not enough samples in either queue, we are unable to
134 // process anything.
135 return true;
136 }
137 return false;
138 }
139
147 {
148 bool newVoice = false;
149
150 if (voiceStatus) {
151 // we detected activity
153
154 // make sure that we have been active for necessary time
156 newVoice = true;
157
158 // set number of frames that will be forced positive
160 }
161 } else if (forceVoiceActiveFramesLeft > 0) {
162 // if we didn't detect voice, but we haven't elapsed the minimum duration,
163 // force voice to be true
164 newVoice = true;
166
168 } else {
169 // else no voice and no need to force
170 newVoice = false;
172 }
173
174 return newVoice;
175 }
176
177private:
178 void enqueue(AudioFrameResizer& frameResizer, std::shared_ptr<AudioFrame>&& buf)
179 {
180 if (buf->getFormat() != format_) {
181 frameResizer.enqueue(resampler_->resample(std::move(buf), format_));
182 } else
183 frameResizer.enqueue(std::move(buf));
184 };
185};
186
187} // namespace jami
Buffers extra samples.
int frameSize() const
Gets the number of samples per output frame.
int samples() const
Gets the numbers of samples available for reading.
std::shared_ptr< AudioFrame > dequeue()
Notifies owner of a new frame.
AudioProcessor(AudioFormat format, unsigned frameSize)
virtual void enableVoiceActivityDetection(bool enabled)=0
Set the status of voice activity detection.
unsigned int frameDurationMs_
AudioFrameResizer playbackQueue_
bool tidyQueues()
Helper method for audio processors, should be called at start of getProcessed() Pops frames from audi...
virtual void enableNoiseSuppression(bool enabled)=0
Set the status of noise suppression includes de-reverb, de-noise, high pass filter,...
std::unique_ptr< Resampler > resampler_
virtual void enableEchoCancel(bool enabled)=0
Set the status of echo cancellation.
unsigned int consecutiveActiveFrames
unsigned int minimumConsequtiveDurationMs
bool getStabilizedVoiceActivity(bool voiceStatus)
Stablilizes voice activity.
virtual void enableAutomaticGainControl(bool enabled)=0
Set the status of automatic gain control.
AudioFrameResizer recordQueue_
virtual std::shared_ptr< AudioFrame > getProcessed()=0
Process and return a single AudioFrame.
unsigned int forceVoiceActiveFramesLeft
virtual void putPlayback(const std::shared_ptr< AudioFrame > &buf)
virtual void putRecorded(std::shared_ptr< AudioFrame > &&buf)
std::atomic_bool playbackStarted_
unsigned int forceMinimumVoiceActivityMs
std::atomic_bool recordStarted_
virtual ~AudioProcessor()=default
Wrapper class for libswresample.
Definition resampler.h:36
#define JAMI_LOG(formatstr,...)
Definition logger.h:225
void emitSignal(Args... args)
Definition ring_signal.h:64
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30
Structure to hold sample rate and channel number associated with audio data.