Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions base/cvd/cuttlefish/host/frontend/webrtc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand All @@ -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",
Expand Down
118 changes: 118 additions & 0 deletions base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.cpp
Original file line number Diff line number Diff line change
@@ -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 <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <vector>

#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<std::vector<float>> 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<std::vector<float>> matrix(
dst_channels, std::vector<float>(src_channels, 0.0f));
const std::array<float, 6> 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
41 changes: 41 additions & 0 deletions base/cvd/cuttlefish/host/frontend/webrtc/audio_channel_matrix.h
Original file line number Diff line number Diff line change
@@ -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 <cstdint>
#include <vector>

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<std::vector<float>> BuildChannelMixingMatrix(
uint8_t dst_channels, uint8_t src_channels, float volume, float fade,
float balance, bool is_ducked = false);

} // namespace cuttlefish
Loading
Loading