]> git.sesse.net Git - nageru/blobdiff - audio_mixer.cpp
Fix an issue where video frames would not be properly shown, most commonly in previews.
[nageru] / audio_mixer.cpp
index e4d4cff4b86222e41d6b0d8181b8d519a1f1b6a1..6a08f2167d62a434a1b31a7af160ff61a6378b3d 100644 (file)
@@ -25,6 +25,7 @@
 
 using namespace bmusb;
 using namespace std;
+using namespace std::chrono;
 using namespace std::placeholders;
 
 namespace {
@@ -170,8 +171,6 @@ AudioMixer::AudioMixer(unsigned num_cards)
          limiter(OUTPUT_FREQUENCY),
          correlation(OUTPUT_FREQUENCY)
 {
-       global_audio_mixer = this;
-
        for (unsigned bus_index = 0; bus_index < MAX_BUSES; ++bus_index) {
                locut[bus_index].init(FILTER_HPF, 2);
                eq[bus_index][EQ_BAND_BASS].init(FILTER_LOW_SHELF, 1);
@@ -184,9 +183,19 @@ AudioMixer::AudioMixer(unsigned num_cards)
        }
        set_limiter_enabled(global_flags.limiter_enabled);
        set_final_makeup_gain_auto(global_flags.final_makeup_gain_auto);
+
+       r128.init(2, OUTPUT_FREQUENCY);
+       r128.integr_start();
+
+       // hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise,
+       // and there's a limit to how important the peak meter is.
+       peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0);
+
+       global_audio_mixer = this;
        alsa_pool.init();
 
        if (!global_flags.input_mapping_filename.empty()) {
+               // 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(),
@@ -203,13 +212,6 @@ AudioMixer::AudioMixer(unsigned num_cards)
                        current_mapping_mode = MappingMode::MULTICHANNEL;
                }
        }
-
-       r128.init(2, OUTPUT_FREQUENCY);
-       r128.integr_start();
-
-       // hlen=16 is pretty low quality, but we use quite a bit of CPU otherwise,
-       // and there's a limit to how important the peak meter is.
-       peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0);
 }
 
 void AudioMixer::reset_resampler(DeviceSpec device_spec)
@@ -227,12 +229,13 @@ void AudioMixer::reset_resampler_mutex_held(DeviceSpec device_spec)
        } else {
                // TODO: ResamplingQueue should probably take the full device spec.
                // (It's only used for console output, though.)
-               device->resampling_queue.reset(new ResamplingQueue(device_spec.index, device->capture_frequency, OUTPUT_FREQUENCY, device->interesting_channels.size()));
+               device->resampling_queue.reset(new ResamplingQueue(
+                       device_spec.index, device->capture_frequency, OUTPUT_FREQUENCY, device->interesting_channels.size(),
+                       global_flags.audio_queue_length_ms * 0.001));
        }
-       device->next_local_pts = 0;
 }
 
-bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned num_samples, AudioFormat audio_format, int64_t frame_length)
+bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned num_samples, AudioFormat audio_format, int64_t frame_length, steady_clock::time_point frame_time)
 {
        AudioDevice *device = find_audio_device(device_spec);
 
@@ -271,10 +274,14 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned
                }
        }
 
+       // If we changed frequency since last frame, we'll need to reset the resampler.
+       if (audio_format.sample_rate != device->capture_frequency) {
+               device->capture_frequency = audio_format.sample_rate;
+               reset_resampler_mutex_held(device_spec);
+       }
+
        // Now add it.
-       int64_t local_pts = device->next_local_pts;
-       device->resampling_queue->add_input_samples(local_pts / double(TIMEBASE), audio.get(), num_samples);
-       device->next_local_pts = local_pts + frame_length;
+       device->resampling_queue->add_input_samples(frame_time, audio.get(), num_samples, ResamplingQueue::ADJUST_RATE);
        return true;
 }
 
@@ -296,11 +303,7 @@ bool AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame,
 
        vector<float> silence(samples_per_frame * num_channels, 0.0f);
        for (unsigned i = 0; i < num_frames; ++i) {
-               device->resampling_queue->add_input_samples(device->next_local_pts / double(TIMEBASE), silence.data(), samples_per_frame);
-               // Note that if the format changed in the meantime, we have
-               // no way of detecting that; we just have to assume the frame length
-               // is always the same.
-               device->next_local_pts += frame_length;
+               device->resampling_queue->add_input_samples(steady_clock::now(), silence.data(), samples_per_frame, ResamplingQueue::DO_NOT_ADJUST_RATE);
        }
        return true;
 }
@@ -473,7 +476,7 @@ void apply_gain(float db, float last_db, vector<float> *samples)
 
 }  // namespace
 
-vector<float> AudioMixer::get_output(double pts, unsigned num_samples, ResamplingQueue::RateAdjustmentPolicy rate_adjustment_policy)
+vector<float> AudioMixer::get_output(steady_clock::time_point ts, unsigned num_samples, ResamplingQueue::RateAdjustmentPolicy rate_adjustment_policy)
 {
        map<DeviceSpec, vector<float>> samples_card;
        vector<float> samples_bus;
@@ -488,7 +491,7 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
                        memset(&samples_card[device_spec][0], 0, samples_card[device_spec].size() * sizeof(float));
                } else {
                        device->resampling_queue->get_output_samples(
-                               pts,
+                               ts,
                                &samples_card[device_spec][0],
                                num_samples,
                                rate_adjustment_policy);