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? // NOTE: maybe we should map [0->100%] -> [min, 0] instead?
double hw_percent = 1.0;
const auto& volume = device().volume; const auto& volume = device().volume;
if (volume.min_mdB == volume.max_mdB) if (volume.min_mdB != volume.max_mdB)
response = 1000;
else
{ {
const double min_dB = volume.min_mdB / 1000.0; const double min_mdB = volume.min_mdB;
const double max_dB = volume.max_mdB / 1000.0; const double max_mdB = volume.max_mdB;
const double dB = volume.mdB / 1000.0; hw_percent = (BAN::Math::pow(10.0, (device().volume.mdB - min_mdB) / (max_mdB - min_mdB)) - 1.0) / 9.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);
} }
response = BAN::Math::round(device().volume_mult * hw_percent * 1000.0);
break; break;
} }
case LibAudio::Packet::SetVolume: 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? // NOTE: maybe we should map [0->100%] -> [min, 0] instead?
const auto& volume = device().volume; const auto& volume = device().volume;
const double min_dB = volume.min_mdB / 1000.0; const double min_mdB = volume.min_mdB;
const double max_dB = volume.max_mdB / 1000.0; const double max_mdB = volume.max_mdB;
const double percent = packet.parameter / 1000.0; 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) if (ioctl(device().fd, SND_SET_VOLUME_MDB, &mdB) != 0)
dwarnln("Failed to set volume: {}", strerror(errno)); dwarnln("Failed to set hardware volume: {}", strerror(errno));
else if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
dwarnln("Failed to query new 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; 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)); 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>(); auto sample_buffer = buffer.as_span<kernel_sample_t>();
for (size_t i = 0; i < samples_to_send; i++) for (size_t i = 0; i < samples_to_send; i++)
{ {
sample_buffer[i] = BAN::Math::clamp<sample_t>( 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>::min(),
BAN::numeric_limits<kernel_sample_t>::max() BAN::numeric_limits<kernel_sample_t>::max()
); );
@@ -17,6 +17,7 @@ struct AudioDevice
uint32_t sample_rate; uint32_t sample_rate;
uint32_t total_pins; uint32_t total_pins;
uint32_t current_pin; uint32_t current_pin;
double volume_mult;
snd_volume_info volume; snd_volume_info volume;
}; };
+1
View File
@@ -60,6 +60,7 @@ static BAN::Optional<AudioDevice> initialize_audio_device(int fd)
{ {
AudioDevice result {}; AudioDevice result {};
result.fd = fd; result.fd = fd;
result.volume_mult = 1.0;
if (ioctl(fd, SND_GET_CHANNELS, &result.channels) != 0) if (ioctl(fd, SND_GET_CHANNELS, &result.channels) != 0)
return {}; return {};
if (ioctl(fd, SND_GET_SAMPLE_RATE, &result.sample_rate) != 0) if (ioctl(fd, SND_GET_SAMPLE_RATE, &result.sample_rate) != 0)