LCOV - code coverage report
Current view: top level - foo/src/media/audio - audiolayer.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 6 21 28.6 %
Date: 2026-02-28 10:41:24 Functions: 6 18 33.3 %

          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

Generated by: LCOV version 1.14