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 227 : 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 2390 : bool isCaptureMuted() const { return isCaptureMuted_; } 143 : 144 : /** 145 : * Mute capture (microphone) 146 : */ 147 0 : void muteCapture(bool muted) { isCaptureMuted_ = muted; } 148 : 149 2390 : 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 2390 : 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 2390 : 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 165 : 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