LAudioMixer Reference Manual & Multi-Channel Mixing Guide
The LAudioMixer class is the multi-channel audio mixing and VU level monitoring engine of the now2sdk framework, derived from the LObject class. It allows developers to register multiple audio sources (such as LFile or LLive), configure individual volume gains, toggle mute states, apply master volume rules, and query real-time peak VU levels for both inputs and master outputs.
Under the hood, LAudioMixer automatically handles sample rate conversion, channel layout mapping, and bit depth resampling to 48kHz Stereo S16 PCM via AudioMixerSink for each registered channel, ensuring glitch-free mixing of different audio sources.
1. Multi-Channel Audio Mixing Architecture
graph TD
A[Audio Source 1 - LFile/LLive] -->|pushAudioFrame| B[AudioMixerSink 1]
C[Audio Source 2 - LFile/LLive] -->|pushAudioFrame| D[AudioMixerSink 2]
B -->|Resample to 48kHz Stereo S16| E[LAudioMixer Mix Loop]
D -->|Resample to 48kHz Stereo S16| E
E -->|Apply Channel Gain & Mute| F[PCM Mixing Bus]
F -->|Apply Master Gain & Mute| G[Peak VU Calculator]
G -->|Mixed Stereo S16 Output| H[distributeAudioFrame]
G -->|Query Master/Channel VU Levels| I[getChannelLevel / getMasterLevel]
Key Audio Features:
- Automatic Resampling: Each input channel has a dedicated
AudioMixerSinkthat automatically initializes an FFmpegSwrContextresampler. It normalizes inputs (e.g., 44.1kHz Mono, or 48kHz 5.1 Surround) to standard C++ broadcast 48kHz Stereo 16-bit PCM. - Synchronized Mix Loop: Operates an internal mix loop (
mixerLoop) that runs synchronously at standard intervals matching the audio frame buffers. - Independent Volume & Mute Nodes: Allows independent control of inputs (channel-level gain and mute) and outputs (master volume and mute) on-the-fly.
- Real-Time VU Level Metering: Calculates maximum absolute peak amplitudes (range
0.0fto1.0f) for individual channels and the master mixed output, supporting modern graphic volume sliders and VU widgets.
2. API Reference & Public Methods
📌 Channel Management
void addChannel(const std::string& id, LObject* obj);
Registers an audio producer source (like LFile or LLive) with a unique id. The source is automatically attached to an internal AudioMixerSink.
void removeChannel(const std::string& id);
Deregisters the channel matching id and releases its internal sink and resampler resources.
void setChannelGain(const std::string& id, int gain);
Configures the channel's volume scale percentage. gain typically ranges from 0 (muted) to 100 (normal gain).
void setChannelMute(const std::string& id, bool mute);
Toggles the mute state of the target channel.
📌 Master Controls
void setMasterVolume(int volume);
Configures the master output volume coefficient percentage (0 to 100).
void setMasterMute(bool mute);
Toggles the mute state of the master mixed output.
void setAudioFormat(const audioFormatProps& props);
void getAudioFormat(audioFormatProps& props);
Configures target output audio properties (bits per sample, sampling rate, and channels).
📌 Peak VU Level Queries
void getChannelLevel(const std::string& id, float& left, float& right);
float getChannelLevel(const std::string& id);
Queries real-time peak volume amplitude (range 0.0f to 1.0f) for a specific channel. The single-value overload returns the average of the left and right channels.
void getMasterLevel(float& left, float& right);
float getMasterLevel();
Queries real-time peak volume amplitude (range 0.0f to 1.0f) for the master mixed output. The single-value overload returns the average of the left and right channels.
3. C++ Integration Code Example
The following example demonstrates how to set up LAudioMixer, register two playout sources, apply volume and mute configurations dynamically, and query VU levels inside a recurring GUI update loop.
#include "LAudioMixer.h"
#include "LFile.h"
#include <iostream>
#include <thread>
#include <chrono>
void setupAudioMixer() {
// 1. Create playout sources
LFile* musicPlayer = new LFile();
musicPlayer->fileNameSet("/media/music_track.mp3");
musicPlayer->setProps("loop", "true");
LFile* voicePlayer = new LFile();
voicePlayer->fileNameSet("/media/voice_over.wav");
voicePlayer->setProps("loop", "true");
// 2. Create and configure LAudioMixer
LAudioMixer* mixer = new LAudioMixer();
// Add channels to the mixer
mixer->addChannel("music", musicPlayer);
mixer->addChannel("voice", voicePlayer);
// Configure individual channel volumes
mixer->setChannelGain("music", 60); // Duck music to 60%
mixer->setChannelMute("music", false);
mixer->setChannelGain("voice", 100); // Keep voice-over at 100%
mixer->setChannelMute("voice", false);
// Configure master controls
mixer->setMasterVolume(90);
mixer->setMasterMute(false);
// 3. Start playout sources
musicPlayer->play();
voicePlayer->play();
// 4. Simulate real-time monitoring loop
for (int i = 0; i < 20; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Query Master VU levels
float masterL = 0.0f, masterR = 0.0f;
mixer->getMasterLevel(masterL, masterR);
// Query Music Channel VU level
float musicL = 0.0f, musicR = 0.0f;
mixer->getChannelLevel("music", musicL, musicR);
std::cout << "[Audio Mixer Log] "
<< "Master Peak: L=" << (int)(masterL * 100) << "% R=" << (int)(masterR * 100) << "% | "
<< "Music Peak: L=" << (int)(musicL * 100) << "% R=" << (int)(musicR * 100) << "%"
<< std::endl;
}
// Clean up
musicPlayer->stop();
voicePlayer->stop();
delete mixer;
delete musicPlayer;
delete voicePlayer;
}