Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 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 "ringbuffer.h"
20 : #include "noncopyable.h"
21 : #include "audio_frame_resizer.h"
22 : #include "audio-processing/audio_processor.h"
23 :
24 : #include <chrono>
25 : #include <mutex>
26 : #include <vector>
27 : #include <atomic>
28 : #include <condition_variable>
29 :
30 : extern "C" {
31 : struct SpeexEchoState_;
32 : typedef struct SpeexEchoState_ SpeexEchoState;
33 : }
34 :
35 : /**
36 : * @file audiolayer.h
37 : * @brief Main sound class. Manages the data transfers between the application and the hardware.
38 : */
39 :
40 : // Define the audio api
41 : #define AAUDIO_API_STR "aaudio"
42 : #define PULSEAUDIO_API_STR "pulseaudio"
43 : #define ALSA_API_STR "alsa"
44 : #define JACK_API_STR "jack"
45 : #define COREAUDIO_API_STR "coreaudio"
46 : #define PORTAUDIO_API_STR "portaudio"
47 :
48 : #define PCM_DEFAULT "default" // Default ALSA plugin
49 : #define PCM_DSNOOP "plug:dsnoop" // Alsa plugin for microphone sharing
50 : #define PCM_DMIX_DSNOOP "dmix/dsnoop" // Audio profile using Alsa dmix/dsnoop
51 :
52 : namespace jami {
53 :
54 : class AudioPreference;
55 : class Resampler;
56 :
57 : enum class AudioDeviceType : int8_t { ALL = -1, PLAYBACK = 0, CAPTURE, RINGTONE };
58 :
59 : class AudioLayer
60 : {
61 : private:
62 : NON_COPYABLE(AudioLayer);
63 :
64 : protected:
65 : enum class Status : uint8_t { Idle, Starting, Started };
66 :
67 : public:
68 : AudioLayer(const AudioPreference&);
69 : virtual ~AudioLayer();
70 :
71 : /**
72 : * Start the capture stream and prepare the playback stream.
73 : * The playback starts accordingly to its threshold
74 : */
75 : virtual void startStream(AudioDeviceType stream) = 0;
76 :
77 : /**
78 : * Start a capture stream on the given device (eg. a window handle, or a hard-coded string like "desktop-audio").
79 : * Not all audio layers will implement this method, so default implementation does nothing.
80 : * @param id The identifier of the device from which audio should be captured
81 : */
82 0 : virtual void startCaptureStream(const std::string& id) { (void) id; };
83 :
84 : /**
85 : * Stop an ongoing capture stream on the given device.
86 : * Not all audio layers will implement this method, so default implementation does nothing.
87 : * @param id The identifier of the capture device from which audio should stop being captured
88 : */
89 0 : virtual void stopCaptureStream(const std::string& id) { (void) id; };
90 :
91 : /**
92 : * Stop the playback and capture streams.
93 : * Drops the pending frames and put the capture and playback handles to PREPARED state
94 : */
95 : virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0;
96 :
97 : virtual std::vector<std::string> getCaptureDeviceList() const = 0;
98 : virtual std::vector<std::string> getPlaybackDeviceList() const = 0;
99 :
100 : virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const = 0;
101 : virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const = 0;
102 : virtual int getIndexCapture() const = 0;
103 : virtual int getIndexPlayback() const = 0;
104 : virtual int getIndexRingtone() const = 0;
105 :
106 : /**
107 : * Determine whether or not the audio layer is active (i.e. playback opened)
108 : */
109 0 : inline bool isStarted() const { return status_ == Status::Started; }
110 :
111 : template<class Rep, class Period>
112 0 : bool waitForStart(const std::chrono::duration<Rep, Period>& rel_time) const
113 : {
114 0 : std::unique_lock lk(mutex_);
115 0 : startedCv_.wait_for(lk, rel_time, [this] { return isStarted(); });
116 0 : return isStarted();
117 0 : }
118 :
119 : /**
120 : * Send a chunk of data to the hardware buffer to start the playback
121 : * Copy data in the urgent buffer.
122 : * @param buffer The buffer containing the data to be played ( ringtones )
123 : */
124 : void putUrgent(std::shared_ptr<AudioFrame> buffer);
125 :
126 : /**
127 : * Start/Stop playing the incoming call notification sound (beep)
128 : * while playing back audio (typically during an ongoing call).
129 : */
130 239 : void playIncomingCallNotification(bool play) { playIncomingCallBeep_.exchange(play); }
131 :
132 : /**
133 : * Flush main buffer
134 : */
135 : void flushMain();
136 :
137 : /**
138 : * Flush urgent buffer
139 : */
140 : void flushUrgent();
141 :
142 2449 : bool isCaptureMuted() const { return isCaptureMuted_; }
143 :
144 : /**
145 : * Mute capture (microphone)
146 : */
147 0 : void muteCapture(bool muted) { isCaptureMuted_ = muted; }
148 :
149 2449 : bool isPlaybackMuted() const { return isPlaybackMuted_; }
150 :
151 : /**
152 : * Mute playback
153 : */
154 0 : void mutePlayback(bool muted) { isPlaybackMuted_ = muted; }
155 :
156 0 : bool isRingtoneMuted() const { return isRingtoneMuted_; }
157 0 : void muteRingtone(bool muted) { isRingtoneMuted_ = muted; }
158 :
159 : /**
160 : * Set capture stream gain (microphone)
161 : * Range should be [-1.0, 1.0]
162 : */
163 0 : void setCaptureGain(double gain) { captureGain_ = gain; }
164 :
165 : /**
166 : * Get capture stream gain (microphone)
167 : */
168 2449 : double getCaptureGain() const { return captureGain_; }
169 :
170 : /**
171 : * Set playback stream gain (speaker)
172 : * Range should be [-1.0, 1.0]
173 : */
174 0 : void setPlaybackGain(double gain) { playbackGain_ = gain; }
175 :
176 : /**
177 : * Get playback stream gain (speaker)
178 : */
179 2449 : double getPlaybackGain() const { return playbackGain_; }
180 :
181 : /**
182 : * Get the sample rate of the audio layer
183 : * @return unsigned int The sample rate
184 : * default: 44100 HZ
185 : */
186 0 : unsigned int getSampleRate() const { return audioFormat_.sample_rate; }
187 :
188 : /**
189 : * Get the audio format of the layer (sample rate & channel number).
190 : */
191 188 : AudioFormat getFormat() const { return audioFormat_; }
192 :
193 : /**
194 : * Emit an audio notification (beep) on incoming calls
195 : */
196 : void notifyIncomingCall();
197 :
198 : virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) = 0;
199 :
200 : protected:
201 : /**
202 : * Callback to be called by derived classes when the audio output is opened.
203 : */
204 : void hardwareFormatAvailable(AudioFormat playback, size_t bufSize = 0);
205 :
206 : /**
207 : * Set the input format on necessary objects.
208 : */
209 : void hardwareInputFormatAvailable(AudioFormat capture);
210 :
211 : void devicesChanged();
212 :
213 : void playbackChanged(bool started);
214 : void recordChanged(bool started);
215 : void setHasNativeAEC(bool hasEAC);
216 : void setHasNativeNS(bool hasNS);
217 :
218 : std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples);
219 : std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples);
220 : std::shared_ptr<AudioFrame> getPlayback(AudioFormat format, size_t samples)
221 : {
222 : const auto& ringBuff = getToRing(format, samples);
223 : const auto& playBuff = getToPlay(format, samples);
224 : return ringBuff ? ringBuff : playBuff;
225 : }
226 :
227 : void putRecorded(std::shared_ptr<AudioFrame>&& frame);
228 :
229 : void flush();
230 :
231 : /**
232 : * True if capture is not to be used
233 : */
234 : bool isCaptureMuted_;
235 :
236 : /**
237 : * True if playback is not to be used
238 : */
239 : bool isPlaybackMuted_;
240 :
241 : /**
242 : * True if ringtone should be muted
243 : */
244 : bool isRingtoneMuted_ {false};
245 :
246 : bool playbackStarted_ {false};
247 : bool recordStarted_ {false};
248 : bool hasNativeAEC_ {true};
249 : bool hasNativeNS_ {false};
250 :
251 : /**
252 : * Gain applied to mic signal
253 : */
254 : double captureGain_;
255 :
256 : /**
257 : * Gain applied to playback signal
258 : */
259 : double playbackGain_;
260 :
261 : // audio processor preferences
262 : const AudioPreference& pref_;
263 :
264 : /**
265 : * Buffers for audio processing
266 : */
267 : std::shared_ptr<RingBuffer> mainRingBuffer_;
268 : std::unique_ptr<AudioFrameResizer> playbackQueue_;
269 :
270 : /**
271 : * Whether or not the audio layer's playback stream is started
272 : */
273 : std::atomic<Status> status_ {Status::Idle};
274 : mutable std::condition_variable startedCv_;
275 :
276 : /**
277 : * Sample Rate that should be sent to the sound card
278 : */
279 : AudioFormat audioFormat_;
280 :
281 : /**
282 : * Sample Rate for input.
283 : */
284 : AudioFormat audioInputFormat_;
285 :
286 : size_t nativeFrameSize_ {0};
287 :
288 : /**
289 : * Urgent ring buffer used for ringtones
290 : */
291 : RingBuffer urgentRingBuffer_;
292 :
293 : /**
294 : * Lock for the entire audio layer
295 : */
296 : mutable std::mutex mutex_ {};
297 :
298 : /**
299 : * Manage sampling rate conversion
300 : */
301 : std::unique_ptr<Resampler> resampler_;
302 :
303 : private:
304 : std::mutex audioProcessorMutex {};
305 : std::unique_ptr<AudioProcessor> audioProcessor;
306 :
307 : void createAudioProcessor();
308 : void destroyAudioProcessor();
309 :
310 : // Set to "true" to play the incoming call notification (beep)
311 : // when the playback is on (typically when there is already an
312 : // active call).
313 : std::atomic_bool playIncomingCallBeep_ {false};
314 : /**
315 : * Time of the last incoming call notification
316 : */
317 : std::chrono::system_clock::time_point lastNotificationTime_ {std::chrono::system_clock::time_point::min()};
318 : };
319 :
320 : } // namespace jami
|