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