AudioServer: Add software volume control

This commit is contained in:
2026-08-19 21:32:36 +03:00
parent 1231b16cc3
commit 78e40ca353
3 changed files with 29 additions and 16 deletions
+27 -16
View File
@@ -111,17 +111,18 @@ bool AudioServer::on_client_packet(int fd, LibAudio::Packet packet)
{
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
double hw_percent = 1.0;
const auto& volume = device().volume;
if (volume.min_mdB == volume.max_mdB)
response = 1000;
else
if (volume.min_mdB != volume.max_mdB)
{
const double min_dB = volume.min_mdB / 1000.0;
const double max_dB = volume.max_mdB / 1000.0;
const double dB = volume.mdB / 1000.0;
const double percent = (BAN::Math::pow(10.0, (dB - min_dB) / (max_dB - min_dB)) - 1.0) / 9.0;
response = BAN::Math::round(percent * 1000.0);
const double min_mdB = volume.min_mdB;
const double max_mdB = volume.max_mdB;
hw_percent = (BAN::Math::pow(10.0, (device().volume.mdB - min_mdB) / (max_mdB - min_mdB)) - 1.0) / 9.0;
}
response = BAN::Math::round(device().volume_mult * hw_percent * 1000.0);
break;
}
case LibAudio::Packet::SetVolume:
@@ -129,16 +130,24 @@ bool AudioServer::on_client_packet(int fd, LibAudio::Packet packet)
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
const auto& volume = device().volume;
const double min_dB = volume.min_mdB / 1000.0;
const double max_dB = volume.max_mdB / 1000.0;
const double min_mdB = volume.min_mdB;
const double max_mdB = volume.max_mdB;
const double percent = packet.parameter / 1000.0;
const double dB = min_dB + (max_dB - min_dB) * BAN::Math::log10(1.0 + 9.0 * percent);
const int32_t mdB = BAN::Math::round(min_mdB + (max_mdB - min_mdB) * BAN::Math::log10(1.0 + 9.0 * percent));
const int32_t mdB = BAN::Math::round(dB * 1000.0);
if (ioctl(device().fd, SND_SET_VOLUME_MDB, &mdB) != 0)
dwarnln("Failed to set volume: {}", strerror(errno));
else if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
dwarnln("Failed to query new volume: {}", strerror(errno));
dwarnln("Failed to set hardware volume: {}", strerror(errno));
if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
{
dwarnln("Failed to query new hardware volume: {}", strerror(errno));
device().volume_mult = 1.0;
}
else
{
const double hw_percent = (BAN::Math::pow(10.0, (device().volume.mdB - min_mdB) / (max_mdB - min_mdB)) - 1.0) / 9.0;
device().volume_mult = percent / hw_percent;
}
break;
}
@@ -313,11 +322,13 @@ void AudioServer::send_samples()
auto buffer = BAN::ByteSpan(static_cast<uint8_t*>(alloca(samples_to_send * sizeof(kernel_sample_t))), samples_to_send * sizeof(kernel_sample_t));
{
const double sample_mult = device().volume_mult * BAN::numeric_limits<kernel_sample_t>::max();
auto sample_buffer = buffer.as_span<kernel_sample_t>();
for (size_t i = 0; i < samples_to_send; i++)
{
sample_buffer[i] = BAN::Math::clamp<sample_t>(
m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
sample_mult * m_samples[m_samples_sent + i],
BAN::numeric_limits<kernel_sample_t>::min(),
BAN::numeric_limits<kernel_sample_t>::max()
);
@@ -17,6 +17,7 @@ struct AudioDevice
uint32_t sample_rate;
uint32_t total_pins;
uint32_t current_pin;
double volume_mult;
snd_volume_info volume;
};
+1
View File
@@ -60,6 +60,7 @@ static BAN::Optional<AudioDevice> initialize_audio_device(int fd)
{
AudioDevice result {};
result.fd = fd;
result.volume_mult = 1.0;
if (ioctl(fd, SND_GET_CHANNELS, &result.channels) != 0)
return {};
if (ioctl(fd, SND_GET_SAMPLE_RATE, &result.sample_rate) != 0)