-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Andy
committed
Jan 20, 2025
1 parent
abb8c09
commit 4af24c8
Showing
7 changed files
with
239 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
include_directories(${ZeroMQ_INCLUDE_DIRS} ${COMMON_INCLUDE_DIR}) | ||
|
||
add_executable( | ||
aero-audio-src | ||
main.cpp | ||
sink.cpp | ||
${COMMON_NOTIFIER_SOURCE_FILE} | ||
${COMMON_LOGGER_SOURCE_FILE} | ||
) | ||
target_link_libraries(aero-audio-src PRIVATE ${ZeroMQ_LIBRARIES} Qt6::Concurrent Qt6::Core Qt6::Multimedia) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#include <QAudioDevice> | ||
#include <QCommandLineOption> | ||
#include <QCommandLineParser> | ||
#include <QCoreApplication> | ||
#include <QMediaDevices> | ||
#include <QTimer> | ||
|
||
#include "logger.h" | ||
#include "notifier.h" | ||
#include "sink.h" | ||
|
||
int main(int argc, char *argv[]) { | ||
QCoreApplication core(argc, argv); | ||
QCoreApplication::setApplicationName("aero-audio-src"); | ||
|
||
QCommandLineParser parser; | ||
parser.setApplicationDescription("Publish audio samples from audio input/output devices over ZMQ"); | ||
parser.addHelpOption(); | ||
parser.addOption(QCommandLineOption(QStringList() << "t" << "topic", "ZMQ topic name to publish", "topic")); | ||
parser.addOption(QCommandLineOption(QStringList() << "v" << "verbose", | ||
"Show verbose output")); | ||
parser.addOption(QCommandLineOption("list-devices", "List all available audio input and output device IDs")); | ||
parser.addPositionalArgument("device", "Audio device ID to sample and publish ZMQ"); | ||
parser.process(core); | ||
|
||
if (parser.isSet("list-devices")) { | ||
INF("Available audio input devices:"); | ||
|
||
quint32 devicesCount = 0; | ||
for (const QAudioDevice &device : QMediaDevices::audioInputs()) { | ||
INF(" %-16s", device.id().toStdString().c_str()); | ||
devicesCount++; | ||
} | ||
|
||
if (devicesCount == 0) { | ||
WARN("None"); | ||
} | ||
|
||
INF("\nAvailable audio output devices:"); | ||
|
||
devicesCount = 0; | ||
for (const QAudioDevice &device : QMediaDevices::audioOutputs()) { | ||
INF(" %-16s", device.id().toStdString().c_str()); | ||
devicesCount++; | ||
} | ||
|
||
if (devicesCount == 0) { | ||
WARN("None"); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
if (parser.isSet("verbose")) { | ||
gMaxLogVerbosity = true; | ||
} | ||
|
||
const QStringList args = parser.positionalArguments(); | ||
if (args.isEmpty()) { | ||
CRIT("Required audio device is not provided. Please provide an audio device ID (use --list-devices to see valid audio input/output devices)"); | ||
return 1; | ||
} | ||
|
||
const QString topic = parser.value("topic"); | ||
if (topic.isEmpty()) { | ||
CRIT("Missing ZMQ topic; please specify a ZMQ topic name to broadcast with"); | ||
return 1; | ||
} | ||
|
||
if (topic.size() != 5) { | ||
CRIT("ZMQ topic should be 5 characters long, %s is not valid", topic.toStdString().c_str()); | ||
return 1; | ||
} | ||
|
||
const QString targetDeviceId = args.at(0); | ||
QAudioDevice targetDevice; | ||
|
||
for (const QAudioDevice &device : QMediaDevices::audioInputs()) { | ||
if (device.id().toStdString() == targetDeviceId.toStdString()) { | ||
targetDevice = device; | ||
} | ||
} | ||
|
||
for (const QAudioDevice &device : QMediaDevices::audioOutputs()) { | ||
if (device.id().toStdString() == targetDeviceId.toStdString()) { | ||
targetDevice = device; | ||
} | ||
} | ||
|
||
if (targetDevice.isNull()) { | ||
CRIT("Audio device is not valid: %s", targetDeviceId.toStdString().c_str()); | ||
CRIT("For a list of valid audio device IDs, please use option --list-devices"); | ||
return 1; | ||
} | ||
|
||
EventNotifier notifier; | ||
AudioSink sink(topic, targetDevice, nullptr); | ||
|
||
QObject::connect(¬ifier, SIGNAL(hangup()), &sink, SLOT(handleHup())); | ||
QObject::connect(¬ifier, SIGNAL(interrupt()), &sink, | ||
SLOT(handleInterrupt())); | ||
QObject::connect(¬ifier, SIGNAL(terminate()), &sink, | ||
SLOT(handleTerminate())); | ||
QObject::connect(&sink, SIGNAL(completed()), &core, SLOT(quit())); | ||
QTimer::singleShot(0, &sink, SLOT(begin())); | ||
|
||
EventNotifier::setup(); | ||
|
||
return core.exec(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#include "sink.h" | ||
#include "logger.h" | ||
|
||
AudioSink::AudioSink(const QString &topic, const QAudioDevice device, | ||
QObject *parent) | ||
: QIODevice(parent) { | ||
topicName = topic; | ||
targetDevice = device; | ||
|
||
targetFormat.setChannelCount(1); | ||
targetFormat.setSampleFormat(QAudioFormat::Int16); | ||
targetFormat.setSampleRate(48000); | ||
|
||
targetSource = new QAudioSource(targetDevice, targetFormat, this); | ||
targetSource->setBufferSize(48000 * 1.0); | ||
|
||
// TODO: init ZMQ settings | ||
} | ||
|
||
AudioSink::~AudioSink() {} | ||
|
||
void AudioSink::begin() { | ||
DBG("Starting audio device read from %s", | ||
targetDevice.id().toStdString().c_str()); | ||
|
||
// TODO: setup ZMQ | ||
|
||
open(QIODevice::WriteOnly); | ||
targetSource->start(this); | ||
} | ||
|
||
qint64 AudioSink::readData(char *data, qint64 maxlen) { | ||
Q_UNUSED(data); | ||
Q_UNUSED(maxlen); | ||
return 0; | ||
} | ||
|
||
qint64 AudioSink::writeData(const char *data, qint64 len) { | ||
DBG("Got %lld bytes", len); | ||
return len; | ||
} | ||
|
||
void AudioSink::end() { | ||
DBG("Ending audio device read"); | ||
|
||
targetSource->stop(); | ||
close(); | ||
|
||
// TODO: end ZMQ | ||
|
||
emit completed(); | ||
} | ||
|
||
void AudioSink::handleHup() { | ||
DBG("Got SIGHUP signal from EventNotifier"); | ||
|
||
// TODO: | ||
} | ||
|
||
void AudioSink::handleInterrupt() { | ||
DBG("Got SIGINT signal from EventNotifier"); | ||
|
||
end(); | ||
} | ||
|
||
void AudioSink::handleTerminate() { | ||
DBG("Got SIGTERM signal from EventNotifier"); | ||
|
||
end(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef SINK_H | ||
#define SINK_H | ||
|
||
#include <QAudioDevice> | ||
#include <QAudioFormat> | ||
#include <QAudioSource> | ||
#include <QIODevice> | ||
|
||
class AudioSink : public QIODevice { | ||
Q_OBJECT | ||
|
||
public: | ||
AudioSink(const QString &topic, const QAudioDevice device, QObject *parent = nullptr); | ||
AudioSink(const AudioSink &) = delete; | ||
AudioSink(AudioSink &&) noexcept = delete; | ||
~AudioSink(); | ||
|
||
AudioSink &operator=(const AudioSink &) = delete; | ||
AudioSink &operator=(AudioSink &&) noexcept = delete; | ||
|
||
qint64 readData(char *data, qint64 maxlen); | ||
qint64 writeData(const char *data, qint64 len); | ||
|
||
private: | ||
QString topicName; | ||
QAudioDevice targetDevice; | ||
|
||
QAudioFormat targetFormat; | ||
QAudioSource *targetSource; | ||
|
||
public slots: | ||
void begin(); | ||
void end(); | ||
|
||
void handleHup(); | ||
void handleInterrupt(); | ||
void handleTerminate(); | ||
|
||
signals: | ||
void completed(); | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters