Ring Daemon 16.0.0
Loading...
Searching...
No Matches
pulselayer.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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 "noncopyable.h"
20#include "logger.h"
21#include "audio/audiolayer.h"
22
23#include <pulse/pulseaudio.h>
24#include <pulse/stream.h>
25
26#include <list>
27#include <string>
28#include <memory>
29#include <thread>
30
31namespace jami {
32
33class AudioPreference;
34class AudioStream;
35class RingBuffer;
36
41{
43 std::string name {};
44 std::string description {"default"};
48
50
52 : index(source.index)
53 , name(source.name)
54 , description(source.description)
55 , sample_spec(source.sample_spec)
56 , channel_map(source.channel_map)
58 {}
59
61 : index(source.index)
62 , name(source.name)
63 , description(source.description)
64 , sample_spec(source.sample_spec)
65 , channel_map(source.channel_map)
66 {}
67
72 {
73 public:
74 explicit NameComparator(const std::string& ref)
75 : baseline(ref)
76 {}
77 bool operator()(const PaDeviceInfos& arg) { return arg.name == baseline; }
78
79 private:
80 const std::string& baseline;
81 };
82
84 {
85 public:
86 explicit DescriptionComparator(const std::string& ref)
87 : baseline(ref)
88 {}
89 bool operator()(const PaDeviceInfos& arg) { return arg.description == baseline; }
90
91 private:
92 const std::string& baseline;
93 };
94};
95
97{
98public:
101
102private:
105};
106
107class PulseLayer : public AudioLayer
108{
109public:
111 ~PulseLayer();
112
117 void readFromMic();
118 void writeToSpeaker();
119 void ringtoneToSpeaker();
120
121 void updateSinkList();
122 void updateSourceList();
123 void updateServerInfo();
124
125 bool inSinkList(const std::string& deviceName);
126 bool inSourceList(const std::string& deviceName);
127
128 virtual std::vector<std::string> getCaptureDeviceList() const;
129 virtual std::vector<std::string> getPlaybackDeviceList() const;
130 int getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const;
131 int getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const;
132
133 std::string getAudioDeviceName(int index, AudioDeviceType type) const;
134
135 virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL);
136 virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL);
137
138private:
139 static void context_state_callback(pa_context* c, void* user_data);
140 static void context_changed_callback(pa_context* c,
142 uint32_t idx,
143 void* userdata);
144 void contextStateChanged(pa_context* c);
145 void contextChanged(pa_context*, pa_subscription_event_type_t, uint32_t idx);
146
147 static void source_input_info_callback(pa_context* c,
148 const pa_source_info* i,
149 int eol,
150 void* userdata);
151 static void sink_input_info_callback(pa_context* c,
152 const pa_sink_info* i,
153 int eol,
154 void* userdata);
155 static void server_info_callback(pa_context*, const pa_server_info* i, void* userdata);
156
157 virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type);
158
159 virtual int getIndexCapture() const;
160 virtual int getIndexPlayback() const;
161 virtual int getIndexRingtone() const;
162
163 void waitForDevices();
164 void waitForDeviceList();
165
166 std::string getPreferredPlaybackDevice() const;
167 std::string getPreferredRingtoneDevice() const;
168 std::string getPreferredCaptureDevice() const;
169
171
175 void createStream(std::unique_ptr<AudioStream>& stream, AudioDeviceType type, const PaDeviceInfos& dev_infos, bool ec, std::function<void(size_t)>&& onData);
176
177 std::unique_ptr<AudioStream>& getStream(AudioDeviceType type)
178 {
179 if (type == AudioDeviceType::PLAYBACK)
180 return playback_;
181 else if (type == AudioDeviceType::RINGTONE)
182 return ringtone_;
183 else if (type == AudioDeviceType::CAPTURE)
184 return record_;
185 else
186 return playback_;
187 }
188
192 void disconnectAudioStream();
193 void onStreamReady();
194
199 const PaDeviceInfos* getDeviceInfos(const std::vector<PaDeviceInfos>&,
200 const std::string& name) const;
201
202 std::atomic_uint pendingStreams {0};
203
207 std::unique_ptr<AudioStream> playback_;
208
212 std::unique_ptr<AudioStream> record_;
213
217 std::unique_ptr<AudioStream> ringtone_;
218
222 std::vector<PaDeviceInfos> sinkList_ {};
223
227 std::vector<PaDeviceInfos> sourceList_ {};
228
230 AudioFormat defaultAudioFormat_ {AudioFormat::MONO()};
231 std::string defaultSink_ {};
232 std::string defaultSource_ {};
233
235 pa_context* context_ {nullptr};
236 std::unique_ptr<pa_threaded_mainloop, decltype(pa_threaded_mainloop_free)&> mainloop_;
237 bool enumeratingSinks_ {false};
238 bool enumeratingSources_ {false};
239 bool gettingServerInfo_ {false};
240 std::atomic_bool waitingDeviceList_ {false};
241 std::mutex readyMtx_ {};
242 std::condition_variable readyCv_ {};
243 std::thread streamStarter_ {};
244
245 AudioPreference& preference_;
246
247 pa_operation* subscribeOp_ {nullptr};
248 friend class AudioLayerTest;
249};
250
251} // namespace jami
Main sound class.
bool operator()(const PaDeviceInfos &arg)
Definition pulselayer.h:89
DescriptionComparator(const std::string &ref)
Definition pulselayer.h:86
Unary function to search for a device by name in a list using std functions.
Definition pulselayer.h:72
bool operator()(const PaDeviceInfos &arg)
Definition pulselayer.h:77
NameComparator(const std::string &ref)
Definition pulselayer.h:74
virtual void stopStream(AudioDeviceType stream=AudioDeviceType::ALL)
Stop the playback and capture streams.
std::string getAudioDeviceName(int index, AudioDeviceType type) const
friend class AudioLayerTest
Definition pulselayer.h:248
virtual std::vector< std::string > getPlaybackDeviceList() const
virtual std::vector< std::string > getCaptureDeviceList() const
bool inSourceList(const std::string &deviceName)
virtual void startStream(AudioDeviceType stream=AudioDeviceType::ALL)
Start the capture stream and prepare the playback stream.
void readFromMic()
Write data from the ring buffer to the hardware and read data from the hardware.
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 ring_signal.h:64
AudioDeviceType
Definition audiolayer.h:58
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:41
std::string name
Definition pulselayer.h:43
pa_sample_spec sample_spec
Definition pulselayer.h:45
pa_channel_map channel_map
Definition pulselayer.h:46
PaDeviceInfos(const pa_source_info &source)
Definition pulselayer.h:51
std::string description
Definition pulselayer.h:44
PaDeviceInfos(const pa_sink_info &source)
Definition pulselayer.h:60