LCOV - code coverage report
Current view: top level - src/media/audio - audiolayer.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 28.6 % 21 6
Test Date: 2026-06-13 09:18:46 Functions: 33.3 % 18 6

            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
        

Generated by: LCOV version 2.0-1