diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/BUILD.bazel b/base/cvd/cuttlefish/host/frontend/webrtc/BUILD.bazel index ab1d9ec05cd..56debf52e64 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/BUILD.bazel +++ b/base/cvd/cuttlefish/host/frontend/webrtc/BUILD.bazel @@ -88,6 +88,18 @@ cf_cc_library( ], ) +cf_cc_library( + name = "libcuttlefish_webrtc_audio_channel_matrix", + srcs = ["audio_channel_matrix.cpp"], + hdrs = ["audio_channel_matrix.h"], + clang_format_enabled = False, + depend_on_what_you_use_enabled = False, + include_cleaner_enabled = False, + deps = [ + ":libcuttlefish_webrtc_audio_settings", + ], +) + cf_cc_library( name = "libcuttlefish_webrtc_audio_mixer", srcs = ["audio_mixer.cpp"], @@ -96,6 +108,7 @@ cf_cc_library( depend_on_what_you_use_enabled = False, include_cleaner_enabled = False, deps = [ + ":libcuttlefish_webrtc_audio_channel_matrix", ":libcuttlefish_webrtc_audio_settings", "//cuttlefish/host/frontend/webrtc/libdevice:audio_sink", "//libbase", diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.cpp b/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.cpp new file mode 100644 index 00000000000..feb2b2b8208 --- /dev/null +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cuttlefish/host/frontend/webrtc/audio_channel_matrix.h" + +#include +#include +#include +#include +#include + +#include "cuttlefish/host/frontend/webrtc/audio_settings.h" + +namespace cuttlefish { +namespace { + +constexpr float kMinus3dB = 0.7071f; // 1 / sqrt(2) for Center & Surround +constexpr float kMinus6dB = 0.5000f; // 1 / 2 for LFE (Subwoofer) and Stereo-to-Mono +constexpr float kDuckingGain = 0.2000f; // -14 dB (AAOS standard ducking) + +} // namespace + +std::vector> BuildChannelMixingMatrix( + uint8_t dst_channels, uint8_t src_channels, float volume, float fade, + float balance, bool is_ducked) { + constexpr uint8_t kMono = GetChannelsCount(AudioChannelsLayout::Mono); // 1 + constexpr uint8_t kStereo = GetChannelsCount(AudioChannelsLayout::Stereo); // 2 + constexpr uint8_t kSurround51 = + GetChannelsCount(AudioChannelsLayout::Surround51); // 6 + + // 1. Fold ducking into effective volume + const float duck_factor = is_ducked ? kDuckingGain : 1.0f; + const float effective_volume = volume * duck_factor; + + // Compute acoustic cabin attenuation for the 4 quadrants + const float front_gain = (fade >= 0.0f) ? 1.0f : (1.0f + fade); + const float rear_gain = (fade <= 0.0f) ? 1.0f : (1.0f - fade); + const float left_gain = (balance <= 0.0f) ? 1.0f : (1.0f - balance); + const float right_gain = (balance >= 0.0f) ? 1.0f : (1.0f + balance); + + const float fl_gain = effective_volume * (front_gain * left_gain); + const float fr_gain = effective_volume * (front_gain * right_gain); + const float fc_gain = effective_volume * front_gain; + const float rl_gain = effective_volume * (rear_gain * left_gain); + const float rr_gain = effective_volume * (rear_gain * right_gain); + + // Case 1: Stereo Destination Output (Laptop Speakers / WebRTC sink) + if (dst_channels == kStereo) { + if (src_channels == kSurround51) { + // 5.1 Surround -> Stereo (ITU-R BS.775 with left/right balance & front/rear fade) + return { + {fl_gain, 0.0f, kMinus3dB * fc_gain * left_gain, + kMinus6dB * effective_volume * left_gain, kMinus3dB * rl_gain, 0.0f}, + {0.0f, fr_gain, kMinus3dB * fc_gain * right_gain, + kMinus6dB * effective_volume * right_gain, 0.0f, kMinus3dB * rr_gain}, + }; + } + if (src_channels == kStereo) { + // Stereo -> Stereo (Direct with left/right balance & front/rear fade) + return { + {fl_gain, 0.0f}, + {0.0f, fr_gain}, + }; + } + if (src_channels == kMono) { + // Mono -> Stereo (Center mono panned by balance) + return { + {fl_gain}, + {fr_gain}, + }; + } + } + + // Case 2: Mono Destination Output + if (dst_channels == kMono) { + if (src_channels == kSurround51) { + return { + {kMinus3dB * fl_gain, kMinus3dB * fr_gain, fc_gain, + kMinus6dB * effective_volume, kMinus3dB * rl_gain, kMinus3dB * rr_gain}, + }; + } + if (src_channels == kStereo) { + return { + {kMinus6dB * fl_gain, kMinus6dB * fr_gain}, + }; + } + if (src_channels == kMono) { + return { + {fl_gain}, + }; + } + } + + // Fallback: generic diagonal matrix + std::vector> matrix( + dst_channels, std::vector(src_channels, 0.0f)); + const std::array spatial_gains = {fl_gain, fr_gain, fc_gain, + effective_volume, rl_gain, rr_gain}; + for (size_t i = 0; i < std::min(dst_channels, src_channels); ++i) { + matrix[i][i] = (i < spatial_gains.size()) ? spatial_gains[i] : effective_volume; + } + return matrix; +} + +} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.h b/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.h new file mode 100644 index 00000000000..48fd0723d7a --- /dev/null +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace cuttlefish { + +/** + * Builds the channel mixing matrix of dimension [dst_channels][src_channels]. + * + * Implements standard ITU-R BS.775 downmixing (e.g. 5.1 -> Stereo, 5.1 -> Mono) + * combined with per-stream spatial cabin attenuation (fade and balance). + * + * @param dst_channels Destination speaker channels (e.g. 2 for Stereo host sink) + * @param src_channels Source stream channels (e.g. 6 for 5.1 Surround, 2 for Stereo) + * @param volume Master stream volume [0.0 - 1.0] + * @param fade Front/Rear cabin fader [-1.0 (Rear) to 1.0 (Front)] + * @param balance Left/Right cabin balance [-1.0 (Left) to 1.0 (Right)] + * @param is_ducked Whether the stream is ducked (-14 dB attenuation) + */ +std::vector> BuildChannelMixingMatrix( + uint8_t dst_channels, uint8_t src_channels, float volume, float fade, + float balance, bool is_ducked = false); + +} // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.cpp b/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.cpp index 453a7f49e97..dfde7c3a27e 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.cpp +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.cpp @@ -130,6 +130,76 @@ virtio_snd_ctl_info GetVirtioCtlInfoMute( return info; } +virtio_snd_ctl_info GetVirtioCtlInfoDuck( + AudioStreamSettings::Direction stream_direction, uint32_t card_id, + uint32_t device_id, uint32_t control_index) { + virtio_snd_ctl_info info{ + .hdr = + { + .hda_fn_nid = Le32(control_index), + }, + .role = Le32(0), + .type = Le32(static_cast(AudioControlType::VIRTIO_SND_CTL_TYPE_BOOLEAN)), + .access = Le32((1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_READ) | + (1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_WRITE)), + .count = Le32(1), + .index = Le32(0), + .name = {}, + .value = {} // Ignored when VIRTIO_SND_CTL_TYPE_BOOLEAN + }; + std::format_to_n(info.name, sizeof(info.name) - 1, "Master {} Duck (C{}D{})", + GetDirectionString(stream_direction), card_id, device_id); + return info; +} + +virtio_snd_ctl_info GetVirtioCtlInfoFade( + AudioStreamSettings::Direction stream_direction, uint32_t card_id, + uint32_t device_id, uint32_t ctl_id) { + virtio_snd_ctl_info info = { + .hdr = {.hda_fn_nid = Le32(ctl_id)}, + .role = Le32( + static_cast(AudioControlRole::VIRTIO_SND_CTL_ROLE_VOLUME)), + .type = Le32( + static_cast(AudioControlType::VIRTIO_SND_CTL_TYPE_INTEGER)), + .access = Le32((1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_READ) | + (1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_WRITE)), + .count = Le32(1), + .index = Le32(0), + .name = {}, + .value = {.integer = { + .min = Le32(static_cast(-100)), + .max = Le32(100), + .step = Le32(1), + }}}; + std::format_to_n(info.name, sizeof(info.name) - 1, "{} Fade (C{}D{})", + GetDirectionString(stream_direction), card_id, device_id); + return info; +} + +virtio_snd_ctl_info GetVirtioCtlInfoBalance( + AudioStreamSettings::Direction stream_direction, uint32_t card_id, + uint32_t device_id, uint32_t ctl_id) { + virtio_snd_ctl_info info = { + .hdr = {.hda_fn_nid = Le32(ctl_id)}, + .role = Le32( + static_cast(AudioControlRole::VIRTIO_SND_CTL_ROLE_VOLUME)), + .type = Le32( + static_cast(AudioControlType::VIRTIO_SND_CTL_TYPE_INTEGER)), + .access = Le32((1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_READ) | + (1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_WRITE)), + .count = Le32(1), + .index = Le32(0), + .name = {}, + .value = {.integer = { + .min = Le32(static_cast(-100)), + .max = Le32(100), + .step = Le32(1), + }}}; + std::format_to_n(info.name, sizeof(info.name) - 1, "{} Balance (C{}D{})", + GetDirectionString(stream_direction), card_id, device_id); + return info; +} + virtio_snd_pcm_info GetVirtioSndPcmInfo(const AudioStreamSettings& settings) { return { .hdr = @@ -333,7 +403,8 @@ AudioHandler::AudioHandler( chmaps_[stream_id] = GetVirtioSndChmapInfo(settings); constexpr uint32_t kCardId = 0; // As of now only one card is supported - if (settings.has_mute_control) { + if (settings.direction == AudioStreamSettings::Direction::Playback || + settings.has_mute_control) { controls_.push_back(GetVirtioCtlInfoMute(settings.direction, kCardId, settings.id, controls_.size())); controls_to_streams_map_.push_back( @@ -356,7 +427,26 @@ AudioHandler::AudioHandler( .current = control.max, }; } + + if (settings.direction == AudioStreamSettings::Direction::Playback) { + controls_.push_back(GetVirtioCtlInfoDuck(settings.direction, kCardId, + settings.id, controls_.size())); + controls_to_streams_map_.push_back( + ControlDesc{.type = ControlDesc::Type::Duck, .stream_id = stream_id}); + + controls_.push_back(GetVirtioCtlInfoFade(settings.direction, kCardId, + settings.id, controls_.size())); + controls_to_streams_map_.push_back( + ControlDesc{.type = ControlDesc::Type::Fade, .stream_id = stream_id}); + + controls_.push_back(GetVirtioCtlInfoBalance(settings.direction, kCardId, + settings.id, controls_.size())); + controls_to_streams_map_.push_back( + ControlDesc{.type = ControlDesc::Type::Balance, .stream_id = stream_id}); + } } + LOG(INFO) << "[Host AudioHandler] Initialized " << streams_.size() + << " streams and " << controls_.size() << " virtio-snd controls."; } AudioHandler::~AudioHandler() { audio_mixer_->Stop(); } @@ -545,13 +635,108 @@ AudioStatus AudioHandler::HandleControlVolume(ControlCommand& cmd) { return AudioStatus::VIRTIO_SND_S_NOT_SUPP; } +AudioStatus AudioHandler::HandleControlFade(ControlCommand& cmd) { + const auto stream_id = controls_to_streams_map_[cmd.control_id()].stream_id; + auto& stream = stream_descs_[stream_id]; + std::lock_guard lock(stream.mtx); + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_READ) { + auto& val = cmd.value()->value.integer; + val[0] = Le32(static_cast(static_cast(stream.fade * 100.0f))); + LOG(INFO) << "[Host AudioHandler] HandleControlFade READ for stream " << stream_id + << " -> returning " << static_cast(stream.fade * 100.0f); + return AudioStatus::VIRTIO_SND_S_OK; + } + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_WRITE) { + const auto raw_val = cmd.value()->value.integer[0].as_uint32_t(); + const auto val = static_cast(raw_val); + if (val < -100 || val > 100) { + LOG(ERROR) << "[Host AudioHandler] Wrong Fade value for control " << cmd.control_id() + << " (stream " << stream_id << ") provided: " << val; + return AudioStatus::VIRTIO_SND_S_BAD_MSG; + } + stream.fade = static_cast(val) / 100.0f; + LOG(INFO) << "[Host AudioHandler] Setting Fade for stream " << stream_id + << " to " << val << " (fade level: " << stream.fade << ")"; + return AudioStatus::VIRTIO_SND_S_OK; + } + + return AudioStatus::VIRTIO_SND_S_NOT_SUPP; +} + +AudioStatus AudioHandler::HandleControlBalance(ControlCommand& cmd) { + const auto stream_id = controls_to_streams_map_[cmd.control_id()].stream_id; + auto& stream = stream_descs_[stream_id]; + std::lock_guard lock(stream.mtx); + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_READ) { + auto& val = cmd.value()->value.integer; + val[0] = Le32(static_cast(static_cast(stream.balance * 100.0f))); + LOG(INFO) << "[Host AudioHandler] HandleControlBalance READ for stream " << stream_id + << " -> returning " << static_cast(stream.balance * 100.0f); + return AudioStatus::VIRTIO_SND_S_OK; + } + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_WRITE) { + const auto raw_val = cmd.value()->value.integer[0].as_uint32_t(); + const auto val = static_cast(raw_val); + if (val < -100 || val > 100) { + LOG(ERROR) << "[Host AudioHandler] Wrong Balance value for control " << cmd.control_id() + << " (stream " << stream_id << ") provided: " << val; + return AudioStatus::VIRTIO_SND_S_BAD_MSG; + } + stream.balance = static_cast(val) / 100.0f; + LOG(INFO) << "[Host AudioHandler] Setting Balance for stream " << stream_id + << " to " << val << " (balance level: " << stream.balance << ")"; + return AudioStatus::VIRTIO_SND_S_OK; + } + + return AudioStatus::VIRTIO_SND_S_NOT_SUPP; +} + +AudioStatus AudioHandler::HandleControlDuck(ControlCommand& cmd) { + const auto stream_id = controls_to_streams_map_[cmd.control_id()].stream_id; + auto& stream = stream_descs_[stream_id]; + std::lock_guard lock(stream.mtx); + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_READ) { + auto& val = cmd.value()->value.integer; + val[0] = Le32(stream.is_ducked ? 1 : 0); + LOG(INFO) << "[Host AudioHandler] HandleControlDuck READ for stream " << stream_id + << " -> returning " << (stream.is_ducked ? 1 : 0); + return AudioStatus::VIRTIO_SND_S_OK; + } + + if (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_WRITE) { + const auto val = cmd.value()->value.integer[0].as_uint32_t(); + if (val > 1) { + LOG(ERROR) << "[Host AudioHandler] Wrong Duck value for control " << cmd.control_id() + << " (stream " << stream_id << ") provided: " << val; + return AudioStatus::VIRTIO_SND_S_BAD_MSG; + } + stream.is_ducked = (val == 1); + LOG(INFO) << "[Host AudioHandler] Setting Duck for stream " << stream_id + << " to " << (stream.is_ducked ? "DUCKED (1)" : "UNDUCKED (0)"); + return AudioStatus::VIRTIO_SND_S_OK; + } + + return AudioStatus::VIRTIO_SND_S_NOT_SUPP; +} + void AudioHandler::OnControlCommand(ControlCommand& cmd) { const auto id = cmd.control_id(); if (id >= controls_.size()) { + LOG(ERROR) << "[Host AudioHandler] OnControlCommand with invalid control ID: " + << id << " (max: " << controls_.size() << ")"; cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG); return; } + LOG(INFO) << "[Host AudioHandler] OnControlCommand: control_id=" << id + << " ('" << controls_[id].name << "'), type=" + << (cmd.type() == AudioCommandType::VIRTIO_SND_R_CTL_WRITE ? "WRITE" : "READ"); + auto result = AudioStatus::VIRTIO_SND_S_NOT_SUPP; switch (controls_to_streams_map_[id].type) { case ControlDesc::Type::Mute: @@ -560,6 +745,15 @@ void AudioHandler::OnControlCommand(ControlCommand& cmd) { case ControlDesc::Type::Volume: result = HandleControlVolume(cmd); break; + case ControlDesc::Type::Fade: + result = HandleControlFade(cmd); + break; + case ControlDesc::Type::Balance: + result = HandleControlBalance(cmd); + break; + case ControlDesc::Type::Duck: + result = HandleControlDuck(cmd); + break; } cmd.Reply(result); } @@ -577,6 +771,9 @@ void AudioHandler::OnPlaybackBuffer(TxBuffer buffer) { uint8_t channels = 0; uint8_t bits_per_channel = 0; float volume = 0; + float fade = 0; + float balance = 0; + bool is_ducked = false; { auto& stream_desc = stream_descs_[stream_id]; std::lock_guard lock(stream_desc.mtx); @@ -594,9 +791,13 @@ void AudioHandler::OnPlaybackBuffer(TxBuffer buffer) { sample_rate = stream_desc.sample_rate; channels = stream_desc.channels; bits_per_channel = stream_desc.bits_per_sample; + fade = stream_desc.fade; + balance = stream_desc.balance; + is_ducked = stream_desc.is_ducked; } audio_mixer_->OnPlayback(stream_id, sample_rate, channels, bits_per_channel, - volume, buffer.get(), buffer.len()); + volume, fade, balance, is_ducked, buffer.get(), + buffer.len()); buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len()); } diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.h b/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.h index d2893c64a32..6f6b82c6767 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.h +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_handler.h @@ -54,12 +54,18 @@ class AudioHandler : public AudioServerExecutor { }; Volume volume; bool muted = false; + bool is_ducked = false; + float fade = 0.0f; + float balance = 0.0f; }; struct ControlDesc { enum class Type { Mute, Volume, + Fade, + Balance, + Duck, }; Type type = Type::Mute; @@ -97,6 +103,9 @@ class AudioHandler : public AudioServerExecutor { AudioStatus HandleControlMute(ControlCommand& cmd); AudioStatus HandleControlVolume(ControlCommand& cmd); + AudioStatus HandleControlFade(ControlCommand& cmd); + AudioStatus HandleControlBalance(ControlCommand& cmd); + AudioStatus HandleControlDuck(ControlCommand& cmd); std::unique_ptr audio_server_; std::thread server_thread_; diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.cpp b/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.cpp index 882beb91628..4a2cd13d8da 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.cpp +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.cpp @@ -2,10 +2,11 @@ #include #include -#include -#include "audio_settings.h" +#include "cuttlefish/host/frontend/webrtc/audio_channel_matrix.h" +#include "cuttlefish/host/frontend/webrtc/audio_settings.h" #include "absl/log/check.h" +#include "absl/log/log.h" namespace cuttlefish { namespace { @@ -164,6 +165,7 @@ void AudioMixer::OnStreamStopped(uint32_t stream_id) { void AudioMixer::OnPlayback(uint32_t stream_id, uint32_t stream_sample_rate, uint8_t stream_channels_count, uint8_t stream_bits_per_channel, float volume, + float fade, float balance, bool is_ducked, const uint8_t* buffer, size_t size) { const auto stream_frames_count = GetFramesCount(size, stream_channels_count, stream_bits_per_channel); @@ -172,10 +174,8 @@ void AudioMixer::OnPlayback(uint32_t stream_id, uint32_t stream_sample_rate, std::unique_lock lock(mutex_); - // As of now we only use direct channel mapping - for(size_t i = 0; i < channles_map.size(); ++i) { - channles_map[i][i] = volume; - } + const auto channel_matrix = BuildChannelMixingMatrix( + channels_count_, stream_channels_count, volume, fade, balance, is_ducked); const bool need_notify = next_frame_.empty(); // no active streams @@ -204,7 +204,7 @@ void AudioMixer::OnPlayback(uint32_t stream_id, uint32_t stream_sample_rate, const auto filled_frames_count = convert_fn(mixed_buffer_.data() + next_frame_id * frame_size_bytes_, channels_count_, sample_rate_, buffer, stream_channels_count, - stream_sample_rate, stream_frames_count, channles_map); + stream_sample_rate, stream_frames_count, channel_matrix); CHECK(filled_frames_count <= frames_count); next_frame_[stream_id] = next_frame_id + filled_frames_count; diff --git a/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.h b/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.h index 4ecd8e3d2a2..a41fc451bb8 100644 --- a/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.h +++ b/base/cvd/cuttlefish/host/frontend/webrtc/audio_mixer.h @@ -22,12 +22,13 @@ class AudioMixer { void Start(); void Stop(); - // Called by auido_handler whenever new playback data chunk is given + // Called by audio_handler whenever new playback data chunk is given // Can be called on different threads void OnPlayback(uint32_t stream_id, uint32_t stream_sample_rate, uint8_t stream_channels_count, - uint8_t stream_bits_per_channel, float volume, const uint8_t* buffer, - size_t size); + uint8_t stream_bits_per_channel, float volume, + float fade, float balance, bool is_ducked, + const uint8_t* buffer, size_t size); void OnStreamStopped(uint32_t stream_id); private: @@ -48,7 +49,7 @@ class AudioMixer { ///////////////// Guarded by mutex_ //////////////// //////////////////////////////////////////////////// - // Buffer stores mixed auido data for every active stream. Consumed by + // Buffer stores mixed audio data for every active stream. Consumed by // MixerLoop std::vector mixed_buffer_; @@ -58,16 +59,6 @@ class AudioMixer { // Frame index per stream to put next available data to std::unordered_map next_frame_; - // Used to remap channels and apply volume levels - std::vector> channles_map = {{ - {1, 0, 0, 0, 0, 0}, - {0, 1, 0, 0, 0, 0}, - {0, 0, 1, 0, 0, 0}, - {0, 0, 0, 1, 0, 0}, - {0, 0, 0, 0, 1, 0}, - {0, 0, 0, 0, 0, 1}, - }}; - //////////////////////////////////////////////////// //////////////////////////////////////////////////// diff --git a/frontend/go.work.sum b/frontend/go.work.sum new file mode 100644 index 00000000000..41698fb92ec --- /dev/null +++ b/frontend/go.work.sum @@ -0,0 +1,5 @@ +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=