Ring Daemon
Loading...
Searching...
No Matches
pulselayer.h
Go to the documentation of this file.
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
18#pragma once
19
20#include "noncopyable.h"
21#include "logger.h"
22#include "audio/audiolayer.h"
24
25#include <pulse/pulseaudio.h>
26#include <pulse/stream.h>
27
28#include <list>
29#include <string>
30#include <memory>
31#include <thread>
32
33namespace jami {
34
35class AudioPreference;
36class AudioStream;
37class RingBuffer;
38
43{
45 std::string name {};
46 std::string description {"default"};
50
52
54 : index(source.index)
55 , name(source.name)
56 , description(source.description)
57 , sample_spec(source.sample_spec)
58 , channel_map(source.channel_map)
60 {}
61
63 : index(source.index)
64 , name(source.name)
65 , description(source.description)
66 , sample_spec(source.sample_spec)
67 , channel_map(source.channel_map)
68 {}
69
74 {
75 public:
76 explicit NameComparator(const std::string& ref)
77 : baseline(ref)
78 {}
79 bool operator()(const PaDeviceInfos& arg) { return arg.name == baseline; }
80
81 private:
82 const std::string& baseline;
83 };
84
86 {
87 public:
88 explicit DescriptionComparator(const std::string& ref)
89 : baseline(ref)
90 {}
91 bool operator()(const PaDeviceInfos& arg) { return arg.description == baseline; }
92
93 private:
94 const std::string& baseline;
95 };
96};
97
99{
100public:
103
104private:
107};
108
109class PulseLayer : public AudioLayer
110{
111public:
113 ~PulseLayer();
114
119 void readFromMic();
120 void writeToSpeaker();
121 void ringtoneToSpeaker();
122
123 void updateSinkList();
124 void updateSourceList();
125 void updateServerInfo();
126
127 bool inSinkList(const std::string& deviceName);
128 bool inSourceList(const std::string& deviceName);
129
130 virtual std::vector<std::string> getCaptureDeviceList() const;
131 virtual std::vector<std::string> getPlaybackDeviceList() const;
132 int getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const;
133 int getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const;
134
135 std::string getAudioDeviceName(int index, AudioDeviceType type) const;
136
137 virtual void startStream(AudioDeviceType stream);
138 virtual void startCaptureStream(const std::string& id) override;
139 virtual void stopCaptureStream(const std::string& id) override;
140 virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
141
142private:
143 static void context_state_callback(pa_context* c, void* user_data);
144 static void context_changed_callback(pa_context* c, pa_subscription_event_type_t t, uint32_t idx, void* userdata);
145 void contextStateChanged(pa_context* c);
146 void contextChanged(pa_context*, pa_subscription_event_type_t, uint32_t idx);
147
148 static void source_input_info_callback(pa_context* c, const pa_source_info* i, int eol, void* userdata);
149 static void sink_input_info_callback(pa_context* c, const pa_sink_info* i, int eol, void* userdata);
150 static void server_info_callback(pa_context*, const pa_server_info* i, void* userdata);
151
152 virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
153
154 virtual int getIndexCapture() const;
155 virtual int getIndexPlayback() const;
156 virtual int getIndexRingtone() const;
157
158 void waitForDevices();
159 void waitForDeviceList();
160
161 std::string getPreferredPlaybackDevice() const;
162 std::string getPreferredRingtoneDevice() const;
163 std::string getPreferredCaptureDevice() const;
164
166
170 void createStream(std::unique_ptr<AudioStream>& stream,
171 AudioDeviceType type,
173 bool ec,
174 std::function<void(size_t)>&& onData);
175
176 std::unique_ptr<AudioStream>& getStream(AudioDeviceType type)
177 {
178 if (type == AudioDeviceType::PLAYBACK)
179 return playback_;
180 else if (type == AudioDeviceType::RINGTONE)
181 return ringtone_;
182 else if (type == AudioDeviceType::CAPTURE)
183 return record_;
184 else
185 return playback_;
186 }
187
191 void disconnectAudioStream();
192 void onStreamReady();
193
198 const PaDeviceInfos* getDeviceInfos(const std::vector<PaDeviceInfos>&, const std::string& name) const;
199
200 std::atomic_uint pendingStreams {0};
201
205 std::unique_ptr<AudioStream> playback_;
206
210 std::unique_ptr<AudioStream> record_;
211
215 std::unique_ptr<AudioStream> ringtone_;
216
220 PulseLoopbackCapture loopbackCapture_;
221
225 std::vector<PaDeviceInfos> sinkList_ {};
226
230 std::vector<PaDeviceInfos> sourceList_ {};
231
233 AudioFormat defaultAudioFormat_ {AudioFormat::MONO()};
234 std::string defaultSink_ {};
235 std::string defaultSource_ {};
236
238 pa_context* context_ {nullptr};
239 std::unique_ptr<pa_threaded_mainloop, decltype(pa_threaded_mainloop_free)&> mainloop_;
240 bool enumeratingSinks_ {false};
241 bool enumeratingSources_ {false};
242 bool gettingServerInfo_ {false};
243 std::atomic_bool waitingDeviceList_ {false};
244 std::mutex readyMtx_ {};
245 std::condition_variable readyCv_ {};
246 std::thread streamStarter_ {};
247
248 AudioPreference& preference_;
249
250 pa_operation* subscribeOp_ {nullptr};
251 friend class AudioLayerTest;
252};
253
254} // namespace jami
Main sound class.
bool operator()(const PaDeviceInfos &arg)
Definition pulselayer.h:91
DescriptionComparator(const std::string &ref)
Definition pulselayer.h:88
Unary function to search for a device by name in a list using std functions.
Definition pulselayer.h:74
bool operator()(const PaDeviceInfos &arg)
Definition pulselayer.h:79
NameComparator(const std::string &ref)
Definition pulselayer.h:76
virtual void stopStream(AudioDeviceType stream=AudioDeviceType::ALL)
Stop the playback and capture streams.
std::string getAudioDeviceName(int index, AudioDeviceType type) const
virtual void startStream(AudioDeviceType stream)
Start the capture stream and prepare the playback stream.
friend class AudioLayerTest
Definition pulselayer.h:251
virtual std::vector< std::string > getPlaybackDeviceList() const
virtual std::vector< std::string > getCaptureDeviceList() const
bool inSourceList(const std::string &deviceName)
virtual void stopCaptureStream(const std::string &id) override
Stop an ongoing capture stream on the given device.
void readFromMic()
Write data from the ring buffer to the hardware and read data from the hardware.
virtual void startCaptureStream(const std::string &id) override
Start a capture stream on the given device (eg.
int getAudioDeviceIndex(const std::string &descr, AudioDeviceType type) const
int getAudioDeviceIndexByName(const std::string &name, AudioDeviceType type) const
bool inSinkList(const std::string &deviceName)
void emitSignal(Args... args)
Definition jami_signal.h:64
AudioDeviceType
Definition audiolayer.h:57
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30
Structure to hold sample rate and channel number associated with audio data.
static const constexpr AudioFormat MONO()
Convenience structure to hold PulseAudio device propreties such as supported channel number etc.
Definition pulselayer.h:43
std::string name
Definition pulselayer.h:45
pa_sample_spec sample_spec
Definition pulselayer.h:47
pa_channel_map channel_map
Definition pulselayer.h:48
PaDeviceInfos(const pa_source_info &source)
Definition pulselayer.h:53
std::string description
Definition pulselayer.h:46
PaDeviceInfos(const pa_sink_info &source)
Definition pulselayer.h:62