Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 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 : * Stop the playback and capture streams. 80 : * Drops the pending frames and put the capture and playback handles to PREPARED state 81 : */ 82 : virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0; 83 : 84 : virtual std::vector<std::string> getCaptureDeviceList() const = 0; 85 : virtual std::vector<std::string> getPlaybackDeviceList() const = 0; 86 : 87 : virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const = 0; 88 : virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const = 0; 89 : virtual int getIndexCapture() const = 0; 90 : virtual int getIndexPlayback() const = 0; 91 : virtual int getIndexRingtone() const = 0; 92 : 93 : /** 94 : * Determine whether or not the audio layer is active (i.e. playback opened) 95 : */ 96 0 : inline bool isStarted() const { return status_ == Status::Started; } 97 : 98 : template<class Rep, class Period> 99 0 : bool waitForStart(const std::chrono::duration<Rep, Period>& rel_time) const 100 : { 101 0 : std::unique_lock lk(mutex_); 102 0 : startedCv_.wait_for(lk, rel_time, [this] { return isStarted(); }); 103 0 : return isStarted(); 104 0 : } 105 : 106 : /** 107 : * Send a chunk of data to the hardware buffer to start the playback 108 : * Copy data in the urgent buffer. 109 : * @param buffer The buffer containing the data to be played ( ringtones ) 110 : */ 111 : void putUrgent(std::shared_ptr<AudioFrame> buffer); 112 : 113 : /** 114 : * Start/Stop playing the incoming call notification sound (beep) 115 : * while playing back audio (typically during an ongoing call). 116 : */ 117 260 : void playIncomingCallNotification(bool play) { playIncomingCallBeep_.exchange(play); } 118 : 119 : /** 120 : * Flush main buffer 121 : */ 122 : void flushMain(); 123 : 124 : /** 125 : * Flush urgent buffer 126 : */ 127 : void flushUrgent(); 128 : 129 1733 : bool isCaptureMuted() const { return isCaptureMuted_; } 130 : 131 : /** 132 : * Mute capture (microphone) 133 : */ 134 0 : void muteCapture(bool muted) { isCaptureMuted_ = muted; } 135 : 136 1733 : bool isPlaybackMuted() const { return isPlaybackMuted_; } 137 : 138 : /** 139 : * Mute playback 140 : */ 141 0 : void mutePlayback(bool muted) { isPlaybackMuted_ = muted; } 142 : 143 0 : bool isRingtoneMuted() const { return isRingtoneMuted_; } 144 0 : void muteRingtone(bool muted) { isRingtoneMuted_ = muted; } 145 : 146 : /** 147 : * Set capture stream gain (microphone) 148 : * Range should be [-1.0, 1.0] 149 : */ 150 0 : void setCaptureGain(double gain) { captureGain_ = gain; } 151 : 152 : /** 153 : * Get capture stream gain (microphone) 154 : */ 155 1733 : double getCaptureGain() const { return captureGain_; } 156 : 157 : /** 158 : * Set playback stream gain (speaker) 159 : * Range should be [-1.0, 1.0] 160 : */ 161 0 : void setPlaybackGain(double gain) { playbackGain_ = gain; } 162 : 163 : /** 164 : * Get playback stream gain (speaker) 165 : */ 166 1733 : double getPlaybackGain() const { return playbackGain_; } 167 : 168 : /** 169 : * Get the sample rate of the audio layer 170 : * @return unsigned int The sample rate 171 : * default: 44100 HZ 172 : */ 173 0 : unsigned int getSampleRate() const { return audioFormat_.sample_rate; } 174 : 175 : /** 176 : * Get the audio format of the layer (sample rate & channel number). 177 : */ 178 205 : AudioFormat getFormat() const { return audioFormat_; } 179 : 180 : /** 181 : * Emit an audio notification (beep) on incoming calls 182 : */ 183 : void notifyIncomingCall(); 184 : 185 : virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) = 0; 186 : 187 : protected: 188 : /** 189 : * Callback to be called by derived classes when the audio output is opened. 190 : */ 191 : void hardwareFormatAvailable(AudioFormat playback, size_t bufSize = 0); 192 : 193 : /** 194 : * Set the input format on necessary objects. 195 : */ 196 : void hardwareInputFormatAvailable(AudioFormat capture); 197 : 198 : void devicesChanged(); 199 : 200 : void playbackChanged(bool started); 201 : void recordChanged(bool started); 202 : void setHasNativeAEC(bool hasEAC); 203 : void setHasNativeNS(bool hasNS); 204 : 205 : std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples); 206 : std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples); 207 : std::shared_ptr<AudioFrame> getPlayback(AudioFormat format, size_t samples) 208 : { 209 : const auto& ringBuff = getToRing(format, samples); 210 : const auto& playBuff = getToPlay(format, samples); 211 : return ringBuff ? ringBuff : playBuff; 212 : } 213 : 214 : void putRecorded(std::shared_ptr<AudioFrame>&& frame); 215 : 216 : void flush(); 217 : 218 : /** 219 : * True if capture is not to be used 220 : */ 221 : bool isCaptureMuted_; 222 : 223 : /** 224 : * True if playback is not to be used 225 : */ 226 : bool isPlaybackMuted_; 227 : 228 : /** 229 : * True if ringtone should be muted 230 : */ 231 : bool isRingtoneMuted_ {false}; 232 : 233 : bool playbackStarted_ {false}; 234 : bool recordStarted_ {false}; 235 : bool hasNativeAEC_ {true}; 236 : bool hasNativeNS_ {false}; 237 : 238 : /** 239 : * Gain applied to mic signal 240 : */ 241 : double captureGain_; 242 : 243 : /** 244 : * Gain applied to playback signal 245 : */ 246 : double playbackGain_; 247 : 248 : // audio processor preferences 249 : const AudioPreference& pref_; 250 : 251 : /** 252 : * Buffers for audio processing 253 : */ 254 : std::shared_ptr<RingBuffer> mainRingBuffer_; 255 : std::unique_ptr<AudioFrameResizer> playbackQueue_; 256 : 257 : /** 258 : * Whether or not the audio layer's playback stream is started 259 : */ 260 : std::atomic<Status> status_ {Status::Idle}; 261 : mutable std::condition_variable startedCv_; 262 : 263 : /** 264 : * Sample Rate that should be sent to the sound card 265 : */ 266 : AudioFormat audioFormat_; 267 : 268 : /** 269 : * Sample Rate for input. 270 : */ 271 : AudioFormat audioInputFormat_; 272 : 273 : size_t nativeFrameSize_ {0}; 274 : 275 : /** 276 : * Urgent ring buffer used for ringtones 277 : */ 278 : RingBuffer urgentRingBuffer_; 279 : 280 : /** 281 : * Lock for the entire audio layer 282 : */ 283 : mutable std::mutex mutex_ {}; 284 : 285 : /** 286 : * Manage sampling rate conversion 287 : */ 288 : std::unique_ptr<Resampler> resampler_; 289 : 290 : private: 291 : std::mutex audioProcessorMutex {}; 292 : std::unique_ptr<AudioProcessor> audioProcessor; 293 : 294 : void createAudioProcessor(); 295 : void destroyAudioProcessor(); 296 : 297 : // Set to "true" to play the incoming call notification (beep) 298 : // when the playback is on (typically when there is already an 299 : // active call). 300 : std::atomic_bool playIncomingCallBeep_ {false}; 301 : /** 302 : * Time of the last incoming call notification 303 : */ 304 : std::chrono::system_clock::time_point lastNotificationTime_ { 305 : std::chrono::system_clock::time_point::min()}; 306 : }; 307 : 308 : } // namespace jami