Skip to content

Commit 31e2f57

Browse files
committed
Safeguard port creation when PipeWire server not connected
1 parent b389875 commit 31e2f57

2 files changed

Lines changed: 74 additions & 61 deletions

File tree

src/soundio/pipewireenumerator.cpp

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ PipewireEnumerator::~PipewireEnumerator() {
8383
pw_thread_loop_stop(m_pPwThreadLoop);
8484

8585
if (m_pPwFilter) {
86+
spa_hook_remove(&m_pwFilterListener);
8687
pw_filter_destroy(m_pPwFilter);
8788
}
8889

@@ -110,7 +111,6 @@ PipewireEnumerator::~PipewireEnumerator() {
110111

111112
void PipewireEnumerator::initialize() {
112113
if (m_initialized) {
113-
qWarning() << "PipewireEnumerator::initialize already initialized";
114114
return;
115115
}
116116

@@ -158,6 +158,16 @@ void PipewireEnumerator::initialize() {
158158

159159
pw_filter_add_listener(m_pPwFilter, &m_pwFilterListener, &filter_events, this);
160160

161+
const auto registeredOutputs = m_pSoundManager->registeredOutputs();
162+
for (const auto& output : registeredOutputs) {
163+
createOutputPorts(output);
164+
}
165+
166+
const auto registeredInputs = m_pSoundManager->registeredInputs();
167+
for (const auto& input : registeredInputs) {
168+
createInputPorts(input);
169+
}
170+
161171
int res = pw_filter_connect(m_pPwFilter,
162172
PW_FILTER_FLAG_RT_PROCESS,
163173
nullptr,
@@ -491,10 +501,11 @@ void PipewireEnumerator::callback(const spa_io_position* pos) {
491501
const uint64_t framesPerBuffer = pos->clock.duration;
492502

493503
if (sampleRate != m_sampleRate || framesPerBuffer != m_framesPerBuffer) {
494-
qWarning() << "PipewireEnumerator::callback rate requested"
495-
<< m_sampleRate << "provided" << sampleRate
496-
<< "buffer size requested" << m_framesPerBuffer << "provided"
497-
<< framesPerBuffer;
504+
qWarning() << "PipewireEnumerator::callback"
505+
"requested"
506+
<< m_framesPerBuffer << "samples at" << m_sampleRate << "hz,"
507+
"provided"
508+
<< framesPerBuffer << "samples at" << sampleRate << "hz";
498509
setLatency(sampleRate, framesPerBuffer);
499510
}
500511

@@ -504,7 +515,7 @@ void PipewireEnumerator::callback(const spa_io_position* pos) {
504515
for (uint32_t deviceId : m_openedDevices) {
505516
QSharedPointer<SoundDevicePipewire> device = m_soundDevices.at(deviceId);
506517
QList<AudioInputBuffer> deviceInputs = device->inputs();
507-
for (AudioInputBuffer input : deviceInputs) {
518+
for (const AudioInputBuffer& input : deviceInputs) {
508519
ChannelGroup channelGroup = input.getChannelGroup();
509520
const int iChannelCount = channelGroup.getChannelCount();
510521
const int iChannelBase = channelGroup.getChannelBase();
@@ -543,7 +554,7 @@ void PipewireEnumerator::callback(const spa_io_position* pos) {
543554

544555
for (uint32_t deviceId : m_openedDevices) {
545556
QSharedPointer<SoundDevicePipewire> device = m_soundDevices.at(deviceId);
546-
for (AudioOutputBuffer output : device->outputs()) {
557+
for (const AudioOutputBuffer& output : device->outputs()) {
547558
ChannelGroup chanGroup = output.getChannelGroup();
548559
const int iChannelCount = chanGroup.getChannelCount();
549560
const int iChannelBase = chanGroup.getChannelBase();
@@ -637,72 +648,71 @@ void PipewireEnumerator::registerInput(const AudioInput& input, AudioDestination
637648
return;
638649
}
639650

640-
pw_thread_loop_lock(m_pPwThreadLoop);
641-
pw_properties* props = pw_properties_new(
642-
// see pipewire/keys.h header
643-
PW_KEY_FORMAT_DSP,
644-
"32 bit float mono audio",
645-
nullptr);
646-
pw_properties_setf(props, PW_KEY_PORT_NAME, "%s:FL", input.getString().toStdString().c_str());
647-
void* portFL = pw_filter_add_port(m_pPwFilter,
648-
SPA_DIRECTION_INPUT,
649-
PW_FILTER_PORT_FLAG_MAP_BUFFERS,
650-
sizeof(uint32_t),
651-
props,
652-
nullptr,
653-
0);
654-
655-
props = pw_properties_new(
656-
// see pipewire/keys.h header
657-
PW_KEY_FORMAT_DSP,
658-
"32 bit float mono audio",
659-
nullptr);
660-
pw_properties_setf(props, PW_KEY_PORT_NAME, "%s:FR", input.getString().toStdString().c_str());
661-
void* portFR = pw_filter_add_port(m_pPwFilter,
662-
SPA_DIRECTION_INPUT,
663-
PW_FILTER_PORT_FLAG_MAP_BUFFERS,
664-
sizeof(uint32_t),
665-
props,
666-
nullptr,
667-
0);
668-
pw_thread_loop_unlock(m_pPwThreadLoop);
669-
m_inputs.insert(input,
670-
std::pair{static_cast<uint32_t*>(portFL),
671-
static_cast<uint32_t*>(portFR)});
651+
if (m_initialized) {
652+
pw_thread_loop_lock(m_pPwThreadLoop);
653+
createInputPorts(input);
654+
pw_thread_loop_unlock(m_pPwThreadLoop);
655+
}
672656
}
673657

674658
void PipewireEnumerator::registerOutput(const AudioOutput& output, AudioSource*) {
675-
pw_thread_loop_lock(m_pPwThreadLoop);
659+
if (m_initialized) {
660+
pw_thread_loop_lock(m_pPwThreadLoop);
661+
createOutputPorts(output);
662+
pw_thread_loop_unlock(m_pPwThreadLoop);
663+
}
664+
}
665+
666+
// need to pw_thread_loop_lock before calling this
667+
uint32_t* PipewireEnumerator::createPorts(const AudioPath& path, bool channel) {
668+
spa_direction direction;
669+
switch (path.getType()) {
670+
case AudioPathType::Main:
671+
case AudioPathType::Headphones:
672+
case AudioPathType::Booth:
673+
case AudioPathType::Bus:
674+
case AudioPathType::Deck:
675+
direction = SPA_DIRECTION_OUTPUT;
676+
break;
677+
case AudioPathType::VinylControl:
678+
case AudioPathType::Microphone:
679+
case AudioPathType::Auxiliary:
680+
case AudioPathType::RecordBroadcast:
681+
direction = SPA_DIRECTION_INPUT;
682+
break;
683+
default:
684+
qWarning() << "PipewireEnumerator::createPorts path type AudioPathType::Invalid";
685+
return nullptr;
686+
}
687+
676688
pw_properties* props = pw_properties_new(
677689
// see pipewire/keys.h header
678690
PW_KEY_FORMAT_DSP,
679691
"32 bit float mono audio",
680692
nullptr);
681-
pw_properties_setf(props, PW_KEY_PORT_NAME, "%s:FL", output.getString().toStdString().c_str());
682-
void* portFL = pw_filter_add_port(m_pPwFilter,
683-
SPA_DIRECTION_OUTPUT,
693+
pw_properties_setf(props,
694+
PW_KEY_PORT_NAME,
695+
channel ? "%s:FR" : "%s:FL",
696+
path.getString().toStdString().c_str());
697+
return static_cast<uint32_t*>(pw_filter_add_port(m_pPwFilter,
698+
direction,
684699
PW_FILTER_PORT_FLAG_MAP_BUFFERS,
685700
sizeof(uint32_t),
686701
props,
687702
nullptr,
688-
0);
689-
props = pw_properties_new(
690-
// see pipewire/keys.h header
691-
PW_KEY_FORMAT_DSP,
692-
"32 bit float mono audio",
693-
nullptr);
694-
pw_properties_setf(props, PW_KEY_PORT_NAME, "%s:FR", output.getString().toStdString().c_str());
695-
void* portFR = pw_filter_add_port(m_pPwFilter,
696-
SPA_DIRECTION_OUTPUT,
697-
PW_FILTER_PORT_FLAG_MAP_BUFFERS,
698-
sizeof(uint32_t),
699-
props,
700-
nullptr,
701-
0);
702-
pw_thread_loop_unlock(m_pPwThreadLoop);
703-
m_outputs.insert(output,
704-
std::pair{static_cast<uint32_t*>(portFL),
705-
static_cast<uint32_t*>(portFR)});
703+
0));
704+
}
705+
706+
// need to pw_thread_loop_lock before calling this
707+
void PipewireEnumerator::createInputPorts(const AudioInput& input) {
708+
auto ports = std::pair{createPorts(input, false), createPorts(input, true)};
709+
m_inputs.insert(input, ports);
710+
}
711+
712+
// need to pw_thread_loop_lock before calling this
713+
void PipewireEnumerator::createOutputPorts(const AudioOutput& output) {
714+
auto ports = std::pair{createPorts(output, false), createPorts(output, true)};
715+
m_outputs.insert(output, ports);
706716
}
707717

708718
void PipewireEnumerator::setLatency(unsigned int sampleRate, unsigned int framesPerBuffer) {

src/soundio/pipewireenumerator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ class PipewireEnumerator : public SoundDeviceEnumerator {
115115

116116
void updateAudioLatencyUsage(const SINT framesPerBuffer);
117117
void setLatency(unsigned int sampleRate, unsigned int framesPerBuffer);
118+
void createInputPorts(const AudioInput& path);
119+
void createOutputPorts(const AudioOutput& path);
120+
uint32_t* createPorts(const AudioPath& path, bool channel);
118121

119122
struct Link {
120123
uint32_t input;

0 commit comments

Comments
 (0)