plugin/ac: fix idle state + reduce buffer size
This commit is contained in:
parent
ffed0aefab
commit
6f463a92d1
3 changed files with 55 additions and 27 deletions
|
|
@ -19,6 +19,7 @@ PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector)
|
||||||
: m_loop(nullptr)
|
: m_loop(nullptr)
|
||||||
, m_stream(nullptr)
|
, m_stream(nullptr)
|
||||||
, m_timer(nullptr)
|
, m_timer(nullptr)
|
||||||
|
, m_idle(true)
|
||||||
, m_token(token)
|
, m_token(token)
|
||||||
, m_collector(collector) {
|
, m_collector(collector) {
|
||||||
pw_init(nullptr, nullptr);
|
pw_init(nullptr, nullptr);
|
||||||
|
|
@ -56,6 +57,10 @@ PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector)
|
||||||
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
|
params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
|
||||||
|
|
||||||
pw_stream_events events{};
|
pw_stream_events events{};
|
||||||
|
events.state_changed = [](void* data, pw_stream_state, pw_stream_state state, const char*) {
|
||||||
|
auto* self = static_cast<PipeWireWorker*>(data);
|
||||||
|
self->streamStateChanged(state);
|
||||||
|
};
|
||||||
events.process = [](void* data) {
|
events.process = [](void* data) {
|
||||||
auto* self = static_cast<PipeWireWorker*>(data);
|
auto* self = static_cast<PipeWireWorker*>(data);
|
||||||
self->processStream();
|
self->processStream();
|
||||||
|
|
@ -76,11 +81,40 @@ PipeWireWorker::PipeWireWorker(std::stop_token token, AudioCollector* collector)
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipeWireWorker::handleTimeout(void* data, uint64_t expirations) {
|
void PipeWireWorker::handleTimeout(void* data, uint64_t expirations) {
|
||||||
Q_UNUSED(expirations);
|
|
||||||
auto* self = static_cast<PipeWireWorker*>(data);
|
auto* self = static_cast<PipeWireWorker*>(data);
|
||||||
|
|
||||||
if (self->m_token.stop_requested()) {
|
if (self->m_token.stop_requested()) {
|
||||||
pw_main_loop_quit(self->m_loop);
|
pw_main_loop_quit(self->m_loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self->m_idle) {
|
||||||
|
if (expirations < 10) {
|
||||||
|
self->m_collector->clearBuffer();
|
||||||
|
} else {
|
||||||
|
self->m_idle = true;
|
||||||
|
timespec timeout = { 0, 500 * SPA_NSEC_PER_MSEC };
|
||||||
|
pw_loop_update_timer(pw_main_loop_get_loop(self->m_loop), self->m_timer, &timeout, &timeout, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipeWireWorker::streamStateChanged(pw_stream_state state) {
|
||||||
|
m_idle = false;
|
||||||
|
switch (state) {
|
||||||
|
case PW_STREAM_STATE_PAUSED: {
|
||||||
|
timespec timeout = { 0, 10 * SPA_NSEC_PER_MSEC };
|
||||||
|
pw_loop_update_timer(pw_main_loop_get_loop(m_loop), m_timer, &timeout, &timeout, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PW_STREAM_STATE_STREAMING:
|
||||||
|
pw_loop_update_timer(pw_main_loop_get_loop(m_loop), m_timer, nullptr, nullptr, false);
|
||||||
|
break;
|
||||||
|
case PW_STREAM_STATE_ERROR:
|
||||||
|
pw_main_loop_quit(m_loop);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,9 +159,8 @@ unsigned int PipeWireWorker::nextPowerOf2(unsigned int n) {
|
||||||
|
|
||||||
AudioCollector::AudioCollector(uint32_t sampleRate, uint32_t chunkSize, uint32_t bufferSize, QObject* parent)
|
AudioCollector::AudioCollector(uint32_t sampleRate, uint32_t chunkSize, uint32_t bufferSize, QObject* parent)
|
||||||
: Service(parent)
|
: Service(parent)
|
||||||
, m_buffer(bufferSize)
|
, m_buffer(bufferSize, 0.0f)
|
||||||
, m_bufferIndex(0)
|
, m_bufferIndex(bufferSize)
|
||||||
, m_bufferFull(false)
|
|
||||||
, m_sampleRate(sampleRate)
|
, m_sampleRate(sampleRate)
|
||||||
, m_chunkSize(chunkSize)
|
, m_chunkSize(chunkSize)
|
||||||
, m_bufferSize(bufferSize) {}
|
, m_bufferSize(bufferSize) {}
|
||||||
|
|
@ -156,6 +189,12 @@ uint32_t AudioCollector::bufferSize() const {
|
||||||
return m_bufferSize;
|
return m_bufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioCollector::clearBuffer() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||||
|
std::fill(m_buffer.begin(), m_buffer.end(), 0.0f);
|
||||||
|
m_bufferIndex = m_bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
void AudioCollector::loadChunk(const int16_t* samples, uint32_t count) {
|
void AudioCollector::loadChunk(const int16_t* samples, uint32_t count) {
|
||||||
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||||
|
|
||||||
|
|
@ -168,10 +207,6 @@ void AudioCollector::loadChunk(const int16_t* samples, uint32_t count) {
|
||||||
});
|
});
|
||||||
|
|
||||||
m_bufferIndex = (m_bufferIndex + toCopy) % m_bufferSize;
|
m_bufferIndex = (m_bufferIndex + toCopy) % m_bufferSize;
|
||||||
if (m_bufferIndex == 0) {
|
|
||||||
m_bufferFull = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
samples += toCopy;
|
samples += toCopy;
|
||||||
count -= toCopy;
|
count -= toCopy;
|
||||||
}
|
}
|
||||||
|
|
@ -180,13 +215,11 @@ void AudioCollector::loadChunk(const int16_t* samples, uint32_t count) {
|
||||||
uint32_t AudioCollector::readChunk(float* out, uint32_t count) {
|
uint32_t AudioCollector::readChunk(float* out, uint32_t count) {
|
||||||
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||||
|
|
||||||
const auto available = m_bufferFull ? m_bufferSize : m_bufferIndex;
|
if (count == 0 || count > m_bufferSize) {
|
||||||
if (count == 0 || count > available) {
|
count = m_bufferSize;
|
||||||
count = available;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto start = m_bufferFull ? (m_bufferIndex + m_bufferSize - count) % m_bufferSize
|
const auto start = (m_bufferIndex + m_bufferSize - count) % m_bufferSize;
|
||||||
: (m_bufferIndex >= count ? m_bufferIndex - count : 0);
|
|
||||||
const auto firstChunk = std::min(count, m_bufferSize - start);
|
const auto firstChunk = std::min(count, m_bufferSize - start);
|
||||||
|
|
||||||
std::copy(m_buffer.begin() + start, m_buffer.begin() + start + firstChunk, out);
|
std::copy(m_buffer.begin() + start, m_buffer.begin() + start + firstChunk, out);
|
||||||
|
|
@ -201,13 +234,11 @@ uint32_t AudioCollector::readChunk(float* out, uint32_t count) {
|
||||||
uint32_t AudioCollector::readChunk(double* out, uint32_t count) {
|
uint32_t AudioCollector::readChunk(double* out, uint32_t count) {
|
||||||
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
||||||
|
|
||||||
const auto available = m_bufferFull ? m_bufferSize : m_bufferIndex;
|
if (count == 0 || count > m_bufferSize) {
|
||||||
if (count == 0 || count > available) {
|
count = m_bufferSize;
|
||||||
count = available;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto start = m_bufferFull ? (m_bufferIndex + m_bufferSize - count) % m_bufferSize
|
const auto start = (m_bufferIndex + m_bufferSize - count) % m_bufferSize;
|
||||||
: (m_bufferIndex >= count ? m_bufferIndex - count : 0);
|
|
||||||
const auto firstChunk = std::min(count, m_bufferSize - start);
|
const auto firstChunk = std::min(count, m_bufferSize - start);
|
||||||
|
|
||||||
std::transform(m_buffer.begin() + start, m_buffer.begin() + start + firstChunk, out, [](float sample) {
|
std::transform(m_buffer.begin() + start, m_buffer.begin() + start + firstChunk, out, [](float sample) {
|
||||||
|
|
@ -228,12 +259,7 @@ void AudioCollector::start() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
clearBuffer();
|
||||||
std::lock_guard<std::mutex> lock(m_bufferMutex);
|
|
||||||
m_buffer.clear();
|
|
||||||
m_bufferIndex = 0;
|
|
||||||
m_bufferFull = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_thread = std::jthread([this](std::stop_token token) {
|
m_thread = std::jthread([this](std::stop_token token) {
|
||||||
PipeWireWorker worker(token, this);
|
PipeWireWorker worker(token, this);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ private:
|
||||||
pw_main_loop* m_loop;
|
pw_main_loop* m_loop;
|
||||||
pw_stream* m_stream;
|
pw_stream* m_stream;
|
||||||
spa_source* m_timer;
|
spa_source* m_timer;
|
||||||
|
bool m_idle;
|
||||||
|
|
||||||
std::stop_token m_token;
|
std::stop_token m_token;
|
||||||
AudioCollector* m_collector;
|
AudioCollector* m_collector;
|
||||||
|
|
@ -31,6 +32,7 @@ private:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
static void handleTimeout(void* data, uint64_t expirations);
|
static void handleTimeout(void* data, uint64_t expirations);
|
||||||
|
void streamStateChanged(pw_stream_state state);
|
||||||
void processStream();
|
void processStream();
|
||||||
void processSamples(const int16_t* samples, uint32_t count);
|
void processSamples(const int16_t* samples, uint32_t count);
|
||||||
|
|
||||||
|
|
@ -42,7 +44,7 @@ class AudioCollector : public Service {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AudioCollector(
|
explicit AudioCollector(
|
||||||
uint32_t sampleRate = 44100, uint32_t chunkSize = 512, uint32_t bufferSize = 1024, QObject* parent = nullptr);
|
uint32_t sampleRate = 44100, uint32_t chunkSize = 512, uint32_t bufferSize = 512, QObject* parent = nullptr);
|
||||||
~AudioCollector();
|
~AudioCollector();
|
||||||
|
|
||||||
static AudioCollector* instance();
|
static AudioCollector* instance();
|
||||||
|
|
@ -51,6 +53,7 @@ public:
|
||||||
[[nodiscard]] uint32_t chunkSize() const;
|
[[nodiscard]] uint32_t chunkSize() const;
|
||||||
[[nodiscard]] uint32_t bufferSize() const;
|
[[nodiscard]] uint32_t bufferSize() const;
|
||||||
|
|
||||||
|
void clearBuffer();
|
||||||
void loadChunk(const int16_t* samples, uint32_t count);
|
void loadChunk(const int16_t* samples, uint32_t count);
|
||||||
uint32_t readChunk(float* out, uint32_t count = 0);
|
uint32_t readChunk(float* out, uint32_t count = 0);
|
||||||
uint32_t readChunk(double* out, uint32_t count = 0);
|
uint32_t readChunk(double* out, uint32_t count = 0);
|
||||||
|
|
@ -62,7 +65,6 @@ private:
|
||||||
std::jthread m_thread;
|
std::jthread m_thread;
|
||||||
std::vector<float> m_buffer;
|
std::vector<float> m_buffer;
|
||||||
uint32_t m_bufferIndex;
|
uint32_t m_bufferIndex;
|
||||||
bool m_bufferFull;
|
|
||||||
std::mutex m_bufferMutex;
|
std::mutex m_bufferMutex;
|
||||||
|
|
||||||
const uint32_t m_sampleRate;
|
const uint32_t m_sampleRate;
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ QVector<double> CavaProvider::values() const {
|
||||||
|
|
||||||
void CavaProvider::updateValues(QVector<double> values) {
|
void CavaProvider::updateValues(QVector<double> values) {
|
||||||
if (values != m_values) {
|
if (values != m_values) {
|
||||||
m_values = std::move(values);
|
m_values = values;
|
||||||
emit valuesChanged();
|
emit valuesChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue