X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Faudio_mixer.cpp;h=a04d204f21f0b765b5a6f8855d2c6c0c0f52f122;hb=5156378d4ad09d54791083e4067cf002e5431cb5;hp=360689b83406b04e6737cb6b7815d4092aca0a90;hpb=25326c82bda01dfa1b86fb4f074d7697705239f8;p=nageru diff --git a/nageru/audio_mixer.cpp b/nageru/audio_mixer.cpp index 360689b..a04d204 100644 --- a/nageru/audio_mixer.cpp +++ b/nageru/audio_mixer.cpp @@ -19,6 +19,7 @@ #include #include "decibel.h" +#include "delay_analyzer.h" #include "flags.h" #include "shared/metrics.h" #include "state.pb.h" @@ -227,6 +228,14 @@ void deinterleave_samples(const vector &in, vector *out_l, vector< } } +double get_delay_seconds(double extra_delay_ms) +{ + // Make sure we never get negative delay. Even 1 ms is probably way less than we + // could ever hope to actually have; this is just a failsafe. + double delay_ms = max(global_flags.audio_queue_length_ms + extra_delay_ms, 1.0); + return delay_ms * 0.001; +} + } // namespace AudioMixer::AudioMixer(unsigned num_capture_cards, unsigned num_ffmpeg_inputs) @@ -263,7 +272,7 @@ AudioMixer::AudioMixer(unsigned num_capture_cards, unsigned num_ffmpeg_inputs) // Must happen after ALSAPool is initialized, as it needs to know the card list. current_mapping_mode = MappingMode::MULTICHANNEL; InputMapping new_input_mapping; - if (!load_input_mapping_from_file(get_devices(), + if (!load_input_mapping_from_file(get_devices(HOLD_ALSA_DEVICES), global_flags.input_mapping_filename, &new_input_mapping)) { fprintf(stderr, "Failed to load input mapping from '%s', exiting.\n", @@ -302,12 +311,16 @@ void AudioMixer::reset_resampler_mutex_held(DeviceSpec device_spec) } else { device->resampling_queue.reset(new ResamplingQueue( device_spec, device->capture_frequency, OUTPUT_FREQUENCY, device->interesting_channels.size(), - global_flags.audio_queue_length_ms * 0.001)); + get_delay_seconds(device->extra_delay_ms))); } } bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned num_samples, AudioFormat audio_format, steady_clock::time_point frame_time) { + if (delay_analyzer != nullptr && delay_analyzer->is_grabbing()) { + delay_analyzer->add_audio(device_spec, data, num_samples, audio_format, frame_time); + } + AudioDevice *device = find_audio_device(device_spec); unique_lock lock(audio_mutex, defer_lock); @@ -326,23 +339,7 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned unique_ptr audio(new float[num_samples * num_channels]); unsigned channel_index = 0; for (auto channel_it = device->interesting_channels.cbegin(); channel_it != device->interesting_channels.end(); ++channel_it, ++channel_index) { - switch (audio_format.bits_per_sample) { - case 0: - assert(num_samples == 0); - break; - case 16: - convert_fixed16_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); - break; - case 24: - convert_fixed24_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); - break; - case 32: - convert_fixed32_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples); - break; - default: - fprintf(stderr, "Cannot handle audio with %u bits per sample\n", audio_format.bits_per_sample); - assert(false); - } + convert_audio_to_fp32(audio.get(), channel_index, num_channels, data, *channel_it, audio_format, num_samples); } // If we changed frequency since last frame, we'll need to reset the resampler. @@ -356,6 +353,7 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned return true; } +// Converts all channels. vector convert_audio_to_fixed32(const uint8_t *data, unsigned num_samples, bmusb::AudioFormat audio_format, unsigned num_channels) { vector audio; @@ -388,6 +386,30 @@ vector convert_audio_to_fixed32(const uint8_t *data, unsigned num_sampl return audio; } +// Converts only one channel. +void convert_audio_to_fp32(float *dst, size_t out_channel, size_t out_num_channels, + const uint8_t *src, size_t in_channel, bmusb::AudioFormat in_audio_format, + size_t num_samples) +{ + switch (in_audio_format.bits_per_sample) { + case 0: + assert(num_samples == 0); + break; + case 16: + convert_fixed16_to_fp32(dst, out_channel, out_num_channels, src, in_channel, in_audio_format.num_channels, num_samples); + break; + case 24: + convert_fixed24_to_fp32(dst, out_channel, out_num_channels, src, in_channel, in_audio_format.num_channels, num_samples); + break; + case 32: + convert_fixed32_to_fp32(dst, out_channel, out_num_channels, src, in_channel, in_audio_format.num_channels, num_samples); + break; + default: + fprintf(stderr, "Cannot handle audio with %u bits per sample\n", in_audio_format.bits_per_sample); + assert(false); + } +} + bool AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame, unsigned num_frames) { AudioDevice *device = find_audio_device(device_spec); @@ -1017,7 +1039,7 @@ void AudioMixer::send_audio_level_callback() correlation.get_correlation()); } -map AudioMixer::get_devices() +map AudioMixer::get_devices(HoldDevices hold_devices) { lock_guard lock(audio_mutex); @@ -1030,7 +1052,7 @@ map AudioMixer::get_devices() info.num_channels = 8; devices.insert(make_pair(spec, info)); } - vector available_alsa_devices = alsa_pool.get_devices(); + vector available_alsa_devices = alsa_pool.get_devices(hold_devices); for (unsigned card_index = 0; card_index < available_alsa_devices.size(); ++card_index) { const DeviceSpec spec{ InputSourceType::ALSA_INPUT, card_index }; const ALSAPool::Device &device = available_alsa_devices[card_index]; @@ -1100,6 +1122,8 @@ void AudioMixer::set_simple_input(unsigned card_index) new_input_mapping.buses.push_back(input); + // NOTE: Delay is implicitly at 0.0 ms, since none has been set in the mapping. + lock_guard lock(audio_mutex); current_mapping_mode = MappingMode::SIMPLE; set_input_mapping_lock_held(new_input_mapping); @@ -1213,34 +1237,48 @@ void AudioMixer::set_input_mapping_lock_held(const InputMapping &new_input_mappi } // Reset resamplers for all cards that don't have the exact same state as before. + map new_extra_delay_ms = new_input_mapping.extra_delay_ms; // Convenience so we can use []. for (unsigned card_index = 0; card_index < MAX_VIDEO_CARDS; ++card_index) { const DeviceSpec device_spec{InputSourceType::CAPTURE_CARD, card_index}; AudioDevice *device = find_audio_device(device_spec); + double extra_delay_ms = new_extra_delay_ms[device_spec]; if (device->interesting_channels != interesting_channels[device_spec]) { device->interesting_channels = interesting_channels[device_spec]; + device->extra_delay_ms = extra_delay_ms; reset_resampler_mutex_held(device_spec); + } else if (device->extra_delay_ms != extra_delay_ms && + device->resampling_queue != nullptr) { + device->extra_delay_ms = extra_delay_ms; + device->resampling_queue->change_expected_delay(get_delay_seconds(extra_delay_ms)); } } for (unsigned card_index = 0; card_index < MAX_ALSA_CARDS; ++card_index) { const DeviceSpec device_spec{InputSourceType::ALSA_INPUT, card_index}; AudioDevice *device = find_audio_device(device_spec); - if (interesting_channels[device_spec].empty()) { - alsa_pool.release_device(card_index); - } else { - alsa_pool.hold_device(card_index); - } + double extra_delay_ms = new_extra_delay_ms[device_spec]; if (device->interesting_channels != interesting_channels[device_spec]) { device->interesting_channels = interesting_channels[device_spec]; - alsa_pool.reset_device(device_spec.index); + device->extra_delay_ms = extra_delay_ms; reset_resampler_mutex_held(device_spec); + } else if (device->extra_delay_ms != extra_delay_ms && + device->resampling_queue != nullptr) { + device->extra_delay_ms = extra_delay_ms; + device->resampling_queue->change_expected_delay(get_delay_seconds(extra_delay_ms)); } + start_or_stop_alsa_capture(device_spec); } for (unsigned card_index = 0; card_index < num_ffmpeg_inputs; ++card_index) { const DeviceSpec device_spec{InputSourceType::FFMPEG_VIDEO_INPUT, card_index}; AudioDevice *device = find_audio_device(device_spec); + double extra_delay_ms = new_extra_delay_ms[device_spec]; if (device->interesting_channels != interesting_channels[device_spec]) { device->interesting_channels = interesting_channels[device_spec]; + device->extra_delay_ms = extra_delay_ms; reset_resampler_mutex_held(device_spec); + } else if (device->extra_delay_ms != extra_delay_ms && + device->resampling_queue != nullptr) { + device->extra_delay_ms = extra_delay_ms; + device->resampling_queue->change_expected_delay(get_delay_seconds(extra_delay_ms)); } } @@ -1253,6 +1291,16 @@ InputMapping AudioMixer::get_input_mapping() const return input_mapping; } +void AudioMixer::set_extra_devices(const set &devices) +{ + lock_guard lock(audio_mutex); + extra_devices = devices; + for (unsigned card_index = 0; card_index < MAX_ALSA_CARDS; ++card_index) { + const DeviceSpec device_spec{InputSourceType::ALSA_INPUT, card_index}; + start_or_stop_alsa_capture(device_spec); + } +} + unsigned AudioMixer::num_buses() const { lock_guard lock(audio_mutex); @@ -1286,4 +1334,20 @@ bool AudioMixer::is_mono(unsigned bus_index) } } +void AudioMixer::start_or_stop_alsa_capture(DeviceSpec device_spec) +{ + assert(device_spec.type == InputSourceType::ALSA_INPUT); + AudioDevice *device = find_audio_device(device_spec); + bool previously_held = alsa_pool.device_is_held(device_spec.index); + bool should_be_held = !device->interesting_channels.empty() || extra_devices.count(device_spec); + if (should_be_held) { + alsa_pool.hold_device(device_spec.index); + } else { + alsa_pool.release_device(device_spec.index); + } + if (previously_held != should_be_held) { + alsa_pool.reset_device(device_spec.index); + } +} + AudioMixer *global_audio_mixer = nullptr;