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-01-22 10:39:23 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             : #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

Generated by: LCOV version 1.14