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