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

Method createPipe

src/models/DaxIqModel.cpp:314–377  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

312}
313
314void DaxIqWorker::createPipe(int channel, int sampleRate)
315{
316#ifndef Q_OS_WIN
317 int idx = channel - 1;
318 if (idx < 0 || idx >= DaxIqModel::NUM_CHANNELS) return;
319 if (m_pipeFds[idx] >= 0) destroyPipe(channel);
320
321 const QString pipePath = iqPipePath(channel);
322 if (pipePath.isEmpty()) {
323 qCWarning(lcAudio) << "DaxIqWorker: cannot resolve IQ FIFO dir for ch" << channel;
324 return;
325 }
326
327 // Create the owner-only FIFO ourselves first, THEN load the pipe-source.
328 // (1) mkfifo-first removes the create-race: the old code fire-and-forgot
329 // `pactl` and raced a 200ms sleep to open a FIFO module-pipe-source had
330 // not created yet -> ENOENT "cannot open IQ pipe", no node ever appeared.
331 // (2) 0600 under $XDG_RUNTIME_DIR/aethersdr (not /tmp/aethersdr-iq-N.pipe,
332 // which was prw-rw-rw-) closes the world-writable-FIFO IQ-injection
333 // vector, mirroring the DAX-audio hardening (GHSA-x8xf-4g5v-ppf9).
334 if (!makeOwnedFifo(pipePath)) {
335 qCWarning(lcAudio) << "DaxIqWorker: mkfifo failed for" << pipePath;
336 return;
337 }
338
339 // Load module-pipe-source SYNCHRONOUSLY so we know it succeeded and capture
340 // the module index for a clean unload. source_properties is single-quoted so
341 // the spaced device.description survives pipewire-pulse's module-arg parser
342 // (mirrors the DAX RX/TX naming fix); node.description drives the label shown
343 // in qpwgraph / JACK / WSJT-X.
344 const quint32 modIdx = runPactlSync({
345 "load-module", "module-pipe-source",
346 QStringLiteral("source_name=aethersdr-iq-%1").arg(channel),
347 QStringLiteral("file=%1").arg(pipePath),
348 QStringLiteral("format=float32le"),
349 QStringLiteral("rate=%1").arg(sampleRate),
350 QStringLiteral("channels=2"),
351 QStringLiteral("source_properties='device.description=\"AetherSDR DAX IQ %1\"'").arg(channel),
352 });
353 if (modIdx == 0) {
354 ::unlink(pipePath.toLocal8Bit().constData());
355 qCWarning(lcAudio) << "DaxIqWorker: pactl load-module failed for IQ ch" << channel;
356 return;
357 }
358 m_pipeModuleIdx[idx] = modIdx;
359
360 // Open the write end. O_RDWR (not O_WRONLY) never ENXIOs even if the module's
361 // read side has not attached yet; we only ever write this fd.
362 int fd = ::open(pipePath.toLocal8Bit().constData(), O_RDWR | O_NONBLOCK);
363 if (fd < 0) {
364 qCWarning(lcAudio) << "DaxIqWorker: cannot open IQ pipe" << pipePath
365 << strerror(errno);
366 runPactlSync({"unload-module", QString::number(modIdx)});
367 ::unlink(pipePath.toLocal8Bit().constData());
368 m_pipeModuleIdx[idx] = 0;
369 return;
370 }
371 m_pipeFds[idx] = fd;

Callers 1

applyStreamStatusMethod · 0.80

Calls 4

iqPipePathFunction · 0.85
runPactlSyncFunction · 0.85
makeOwnedFifoFunction · 0.70
isEmptyMethod · 0.45

Tested by

no test coverage detected