+ typedef std::function<void(float level_lufs, float peak_db,
+ std::vector<BusLevel> bus_levels,
+ float global_level_lufs, float range_low_lufs, float range_high_lufs,
+ float final_makeup_gain_db,
+ float correlation)> audio_level_callback_t;
+ void set_audio_level_callback(audio_level_callback_t callback)
+ {
+ audio_level_callback = callback;
+ }
+
+ typedef std::function<void()> state_changed_callback_t;
+ void set_state_changed_callback(state_changed_callback_t callback)
+ {
+ state_changed_callback = callback;
+ }
+
+ state_changed_callback_t get_state_changed_callback() const
+ {
+ return state_changed_callback;
+ }
+
+ void trigger_state_changed_callback()
+ {
+ if (state_changed_callback != nullptr) {
+ state_changed_callback();
+ }
+ }
+
+ // A combination of all settings for a bus. Useful if you want to get
+ // or store them as a whole without bothering to call all of the get_*
+ // or set_* functions for that bus.
+ struct BusSettings {
+ float fader_volume_db;
+ bool muted;
+ bool locut_enabled;
+ float eq_level_db[NUM_EQ_BANDS];
+ float gain_staging_db;
+ bool level_compressor_enabled;
+ float compressor_threshold_dbfs;
+ bool compressor_enabled;
+ };
+ static BusSettings get_default_bus_settings();
+ BusSettings get_bus_settings(unsigned bus_index) const;
+ void set_bus_settings(unsigned bus_index, const BusSettings &settings);
+
+private:
+ struct AudioDevice {
+ std::unique_ptr<ResamplingQueue> resampling_queue;
+ std::string display_name;
+ unsigned capture_frequency = OUTPUT_FREQUENCY;
+ // Which channels we consider interesting (ie., are part of some input_mapping).
+ std::set<unsigned> interesting_channels;
+ bool silenced = false;
+ };
+
+ const AudioDevice *find_audio_device(DeviceSpec device_spec) const
+ {
+ return const_cast<AudioMixer *>(this)->find_audio_device(device_spec);
+ }
+
+ AudioDevice *find_audio_device(DeviceSpec device_spec);
+
+ void find_sample_src_from_device(const std::map<DeviceSpec, std::vector<float>> &samples_card, DeviceSpec device_spec, int source_channel, const float **srcptr, unsigned *stride);
+ void fill_audio_bus(const std::map<DeviceSpec, std::vector<float>> &samples_card, const InputMapping::Bus &bus, unsigned num_samples, float *output);
+ void reset_resampler_mutex_held(DeviceSpec device_spec);
+ void apply_eq(unsigned bus_index, std::vector<float> *samples_bus);
+ void update_meters(const std::vector<float> &samples);
+ void add_bus_to_master(unsigned bus_index, const std::vector<float> &samples_bus, std::vector<float> *samples_out);
+ void measure_bus_levels(unsigned bus_index, const std::vector<float> &left, const std::vector<float> &right);
+ void send_audio_level_callback();
+ std::vector<DeviceSpec> get_active_devices() const;
+ void set_input_mapping_lock_held(const InputMapping &input_mapping);
+
+ unsigned num_capture_cards, num_ffmpeg_inputs;
+
+ mutable std::timed_mutex audio_mutex;
+
+ ALSAPool alsa_pool;
+ AudioDevice video_cards[MAX_VIDEO_CARDS]; // Under audio_mutex.
+ AudioDevice alsa_inputs[MAX_ALSA_CARDS]; // Under audio_mutex.
+ std::unique_ptr<AudioDevice[]> ffmpeg_inputs; // Under audio_mutex.
+
+ std::atomic<float> locut_cutoff_hz{120};
+ StereoFilter locut[MAX_BUSES]; // Default cutoff 120 Hz, 24 dB/oct.
+ std::atomic<bool> locut_enabled[MAX_BUSES];
+ StereoFilter eq[MAX_BUSES][NUM_EQ_BANDS]; // The one for EQBand::MID isn't actually used (see comments in apply_eq()).