MCPcopy Create free account
hub / github.com/aethersdr/AetherSDR / open

Method open

src/core/PipeWireNativeRxSource.cpp:67–175  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

65}
66
67bool PipeWireNativeRxSource::open()
68{
69 if (m_stream) {
70 return true;
71 }
72
73 auto& ctx = PipeWireNativeContext::instance();
74 if (!ctx.acquire()) {
75 qCWarning(lcDax) << "PipeWireNativeRxSource: failed to acquire context for ch" << m_channel;
76 return false;
77 }
78 m_contextAcquired = true;
79
80 const QByteArray nodeName = QString("aethersdr-dax-%1").arg(m_channel).toUtf8();
81 const QByteArray nodeDesc = QString("AetherSDR DAX %1").arg(m_channel).toUtf8();
82
83 // Latency strategy:
84 // node.latency — the *request*: 256-sample quantum (~5.3 ms @ 48 kHz)
85 // node.force-quantum — *forces* the graph cycle to 256 samples while our
86 // node is active. Without this, any other client
87 // (e.g. WSJT-X's Qt PulseAudio backend) requesting
88 // a longer buffer drags the negotiated graph
89 // quantum up, undoing our latency hint.
90 // node.force-rate — pin graph rate to 48 kHz so it can't fall back to
91 // a slower clock during negotiation.
92 // node.always-process— keep draining the ring even when no client is
93 // connected, so we don't accumulate backlog
94 // between "DAX enabled" and "WSJT-X connected".
95 // pulse.min.{req,frag,quantum}
96 // — clamp the PipeWire pulse-compat fragment pool
97 // that PulseAudio-API clients sit behind. This
98 // is the hidden ~200 ms buffer Qt's PulseAudio
99 // backend negotiates by default (4–8 fragments
100 // × 50 ms each). PipeWire's pulse module reads
101 // these source-side properties when sizing each
102 // capturing pulse client's ring, so any client
103 // (WSJT-X, fldigi, …) connecting to us inherits
104 // the small 256-sample fragment cap regardless
105 // of what its own backend requested. Confirmed
106 // via pw-cat (native PipeWire client at 5.3 ms)
107 // vs QtPulseAudio:<pid> (50 ms quantum + 200 ms
108 // pulse fragment buffer).
109 pw_properties* props = pw_properties_new(
110 PW_KEY_MEDIA_TYPE, "Audio",
111 PW_KEY_MEDIA_CATEGORY, "Playback", // we play audio INTO the graph; clients capture from us
112 PW_KEY_MEDIA_CLASS, "Audio/Source",
113 PW_KEY_MEDIA_ROLE, "Production",
114 PW_KEY_NODE_NAME, nodeName.constData(),
115 PW_KEY_NODE_DESCRIPTION, nodeDesc.constData(),
116 PW_KEY_NODE_LATENCY, "256/48000",
117 PW_KEY_NODE_RATE, "1/48000",
118 PW_KEY_NODE_FORCE_QUANTUM, "256",
119 PW_KEY_NODE_FORCE_RATE, "48000",
120 PW_KEY_NODE_ALWAYS_PROCESS, "true",
121 "pulse.min.req", "256/48000",
122 "pulse.default.req", "256/48000",
123 "pulse.min.frag", "256/48000",
124 "pulse.default.frag", "256/48000",

Callers

nothing calls this directly

Calls 5

lockMethod · 0.80
coreMethod · 0.80
unlockMethod · 0.80
acquireMethod · 0.45
releaseMethod · 0.45

Tested by

no test coverage detected