Implemented volume control for jukebox

This commit is contained in:
emeric
2026-02-18 00:12:32 +01:00
parent 5f6d3e796a
commit 7a30bb98f6
9 changed files with 137 additions and 51 deletions
@@ -238,6 +238,15 @@ namespace lms::audio::alsa
return ::snd_pcm_state(_pcm.get()) == SND_PCM_STATE_PAUSED;
}
void AudioOutputStream::setVolume(float)
{
}
float AudioOutputStream::getVolume() const
{
return 1.F;
}
std::chrono::microseconds AudioOutputStream::getPlaybackTime() const
{
::snd_pcm_sframes_t delayFrames{};
@@ -52,15 +52,18 @@ namespace lms::audio::alsa
void asyncWrite(std::span<const std::byte> buffer, WriteCompletionCallback cb) override;
void asyncDrain(DrainCompletionCallback cb) override;
void pause() override;
void resume() override;
bool isPaused() const override;
std::chrono::microseconds getPlaybackTime() const override;
std::chrono::microseconds getLatency() const override;
void flush() override;
void pause() override;
void resume() override;
bool isPaused() const override;
void setVolume(float volume) override;
float getVolume() const override;
void stop();
void setupAllDescriptors();
void releaseAllDescriptors();
@@ -19,10 +19,13 @@
#include "AudioOutputStream.hpp"
#include <algorithm>
#include <boost/asio/post.hpp>
#include <pulse/context.h>
#include <pulse/def.h>
#include <pulse/error.h>
#include <pulse/introspect.h>
#include <pulse/operation.h>
#include <pulse/proplist.h>
#include <pulse/stream.h>
@@ -195,47 +198,6 @@ namespace lms::audio::pulseaudio
}
}
void AudioOutputStream::pause()
{
LMS_LOG(AUDIO_OUTPUT_STREAM, DEBUG, "Pausing stream");
MainLoopScopedLock lock{ _mainLoop };
pa_operation* op{ ::pa_stream_cork(_stream.get(), 1, nullptr, nullptr) };
if (!op)
throw PaException("pa_stream_cork (pause) failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
void AudioOutputStream::resume()
{
LMS_LOG(AUDIO_OUTPUT_STREAM, DEBUG, "Resuming stream");
MainLoopScopedLock lock{ _mainLoop };
{
pa_operation* op{ ::pa_stream_cork(_stream.get(), 0, nullptr, nullptr) };
if (!op)
throw PaException("pa_stream_cork (resume) failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
{
pa_operation* op{ ::pa_stream_trigger(_stream.get(), NULL, NULL) };
if (!op)
throw PaException("pa_stream_trigger failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
}
bool AudioOutputStream::isPaused() const
{
MainLoopScopedLock lock{ _mainLoop };
return pa_stream_is_corked(_stream.get());
}
std::chrono::microseconds AudioOutputStream::getPlaybackTime() const
{
pa_usec_t duration{};
@@ -279,6 +241,78 @@ namespace lms::audio::pulseaudio
}
}
void AudioOutputStream::pause()
{
LMS_LOG(AUDIO_OUTPUT_STREAM, DEBUG, "Pausing stream");
MainLoopScopedLock lock{ _mainLoop };
pa_operation* op{ ::pa_stream_cork(_stream.get(), 1, nullptr, nullptr) };
if (!op)
throw PaException("pa_stream_cork (pause) failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
void AudioOutputStream::resume()
{
LMS_LOG(AUDIO_OUTPUT_STREAM, DEBUG, "Resuming stream");
MainLoopScopedLock lock{ _mainLoop };
{
pa_operation* op{ ::pa_stream_cork(_stream.get(), 0, nullptr, nullptr) };
if (!op)
throw PaException("pa_stream_cork (resume) failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
{
pa_operation* op{ ::pa_stream_trigger(_stream.get(), NULL, NULL) };
if (!op)
throw PaException("pa_stream_trigger failed", pa_context_errno(_context));
::pa_operation_unref(op);
}
}
bool AudioOutputStream::isPaused() const
{
MainLoopScopedLock lock{ _mainLoop };
return pa_stream_is_corked(_stream.get());
}
void AudioOutputStream::setVolume(float volume)
{
MainLoopScopedLock lock{ _mainLoop };
if (volume < 0.F || volume > 1.F)
throw Exception{ "Volume must be in range 0-1" };
const pa_volume_t paVol{ pa_sw_volume_from_linear(volume) };
pa_cvolume paChanVol;
pa_cvolume_set(&paChanVol, _outputParameters.channelCount, paVol);
pa_operation* op{ ::pa_context_set_sink_input_volume(
_context,
pa_stream_get_index(_stream.get()),
&paChanVol,
nullptr,
nullptr) };
if (!op)
throw PaException("pa_context_set_sink_input_volume failed", pa_context_errno(_context));
::pa_operation_unref(op);
_currentVolume = volume;
}
float AudioOutputStream::getVolume() const
{
return _currentVolume;
}
void AudioOutputStream::connect()
{
constexpr pa_stream_flags_t flags{ static_cast<pa_stream_flags_t>(
@@ -62,15 +62,18 @@ namespace lms::audio::pulseaudio
void asyncWrite(std::span<const std::byte> buffer, WriteCompletionCallback cb) override;
void asyncDrain(DrainCompletionCallback cb) override;
void pause() override;
void resume() override;
bool isPaused() const override;
std::chrono::microseconds getPlaybackTime() const override;
std::chrono::microseconds getLatency() const override;
void flush() override;
void pause() override;
void resume() override;
bool isPaused() const override;
void setVolume(float volume) override;
float getVolume() const override;
void connect();
void onStateChanged();
void onWriteRequested(std::size_t writableSize);
@@ -83,6 +86,7 @@ namespace lms::audio::pulseaudio
pa_threaded_mainloop* _mainLoop;
const PcmParameters _outputParameters;
PaStreamPtr _stream;
float _currentVolume{ 1.F };
WaitReadyCallback _waitReadyCallback;