]> git.sesse.net Git - nageru/blobdiff - audio_mixer.cpp
Update to a bmusb version where fake cards output 8-channel audio.
[nageru] / audio_mixer.cpp
index e28acfeb00154d2926e1f00c9fa26382c511aae8..a2f25f0a2d93fb5a8c29dae5548ed33cee723302 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "db.h"
 #include "flags.h"
+#include "mixer.h"
 #include "timebase.h"
 
 using namespace bmusb;
@@ -190,8 +191,7 @@ AudioMixer::AudioMixer(unsigned num_cards)
        new_input_mapping.buses.push_back(input);
        set_input_mapping(new_input_mapping);
 
-       // Look for ALSA cards.
-       available_alsa_cards = ALSAInput::enumerate_devices();
+       alsa_pool.init();
 
        r128.init(2, OUTPUT_FREQUENCY);
        r128.integr_start();
@@ -201,17 +201,6 @@ AudioMixer::AudioMixer(unsigned num_cards)
        peak_resampler.setup(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY * 4, /*num_channels=*/2, /*hlen=*/16, /*frel=*/1.0);
 }
 
-AudioMixer::~AudioMixer()
-{
-       for (unsigned card_index = 0; card_index < available_alsa_cards.size(); ++card_index) {
-               const AudioDevice &device = alsa_inputs[card_index];
-               if (device.alsa_device != nullptr) {
-                       device.alsa_device->stop_capture_thread();
-               }
-       }
-}
-
-
 void AudioMixer::reset_resampler(DeviceSpec device_spec)
 {
        lock_guard<timed_mutex> lock(audio_mutex);
@@ -232,25 +221,6 @@ void AudioMixer::reset_resampler_mutex_held(DeviceSpec device_spec)
        device->next_local_pts = 0;
 }
 
-void AudioMixer::reset_alsa_mutex_held(DeviceSpec device_spec)
-{
-       assert(device_spec.type == InputSourceType::ALSA_INPUT);
-       unsigned card_index = device_spec.index;
-       AudioDevice *device = find_audio_device(device_spec);
-
-       if (device->alsa_device != nullptr) {
-               device->alsa_device->stop_capture_thread();
-       }
-       if (device->interesting_channels.empty()) {
-               device->alsa_device.reset();
-       } else {
-               const ALSAInput::Device &alsa_dev = available_alsa_cards[card_index];
-               device->alsa_device.reset(new ALSAInput(alsa_dev.address.c_str(), OUTPUT_FREQUENCY, alsa_dev.num_channels, bind(&AudioMixer::add_audio, this, device_spec, _1, _2, _3, _4)));
-               device->capture_frequency = device->alsa_device->get_sample_rate();
-               device->alsa_device->start_capture_thread();
-       }
-}
-
 bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned num_samples, AudioFormat audio_format, int64_t frame_length)
 {
        AudioDevice *device = find_audio_device(device_spec);
@@ -324,6 +294,22 @@ bool AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame,
        return true;
 }
 
+bool AudioMixer::silence_card(DeviceSpec device_spec, bool silence)
+{
+       AudioDevice *device = find_audio_device(device_spec);
+
+       unique_lock<timed_mutex> lock(audio_mutex, defer_lock);
+       if (!lock.try_lock_for(chrono::milliseconds(10))) {
+               return false;
+       }
+
+       if (device->silenced && !silence) {
+               reset_resampler_mutex_held(device_spec);
+       }
+       device->silenced = silence;
+       return true;
+}
+
 AudioMixer::AudioDevice *AudioMixer::find_audio_device(DeviceSpec device)
 {
        switch (device.type) {
@@ -384,6 +370,24 @@ void AudioMixer::fill_audio_bus(const map<DeviceSpec, vector<float>> &samples_ca
        }
 }
 
+vector<DeviceSpec> AudioMixer::get_active_devices() const
+{
+       vector<DeviceSpec> ret;
+       for (unsigned card_index = 0; card_index < MAX_VIDEO_CARDS; ++card_index) {
+               const DeviceSpec device_spec{InputSourceType::CAPTURE_CARD, card_index};
+               if (!find_audio_device(device_spec)->interesting_channels.empty()) {
+                       ret.push_back(device_spec);
+               }
+       }
+       for (unsigned card_index = 0; card_index < MAX_ALSA_CARDS; ++card_index) {
+               const DeviceSpec device_spec{InputSourceType::ALSA_INPUT, card_index};
+               if (!find_audio_device(device_spec)->interesting_channels.empty()) {
+                       ret.push_back(device_spec);
+               }
+       }
+       return ret;
+}
+
 vector<float> AudioMixer::get_output(double pts, unsigned num_samples, ResamplingQueue::RateAdjustmentPolicy rate_adjustment_policy)
 {
        map<DeviceSpec, vector<float>> samples_card;
@@ -392,14 +396,12 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
        lock_guard<timed_mutex> lock(audio_mutex);
 
        // Pick out all the interesting channels from all the cards.
-       // TODO: If the card has been hotswapped, the number of channels
-       // might have changed; if so, we need to do some sort of remapping
-       // to silence.
-       for (const auto &spec_and_info : get_devices_mutex_held()) {
-               const DeviceSpec &device_spec = spec_and_info.first;
+       for (const DeviceSpec &device_spec : get_active_devices()) {
                AudioDevice *device = find_audio_device(device_spec);
-               if (!device->interesting_channels.empty()) {
-                       samples_card[device_spec].resize(num_samples * device->interesting_channels.size());
+               samples_card[device_spec].resize(num_samples * device->interesting_channels.size());
+               if (device->silenced) {
+                       memset(&samples_card[device_spec][0], 0, samples_card[device_spec].size() * sizeof(float));
+               } else {
                        device->resampling_queue->get_output_samples(
                                pts,
                                &samples_card[device_spec][0],
@@ -730,26 +732,23 @@ void AudioMixer::send_audio_level_callback()
                correlation.get_correlation());
 }
 
-map<DeviceSpec, DeviceInfo> AudioMixer::get_devices() const
+map<DeviceSpec, DeviceInfo> AudioMixer::get_devices()
 {
        lock_guard<timed_mutex> lock(audio_mutex);
-       return get_devices_mutex_held();
-}
 
-map<DeviceSpec, DeviceInfo> AudioMixer::get_devices_mutex_held() const
-{
        map<DeviceSpec, DeviceInfo> devices;
        for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
                const DeviceSpec spec{ InputSourceType::CAPTURE_CARD, card_index };
                const AudioDevice *device = &video_cards[card_index];
                DeviceInfo info;
                info.name = device->name;
-               info.num_channels = 8;  // FIXME: This is wrong for fake cards.
+               info.num_channels = 8;
                devices.insert(make_pair(spec, info));
        }
-       for (unsigned card_index = 0; card_index < available_alsa_cards.size(); ++card_index) {
+       vector<ALSAPool::Device> available_alsa_devices = alsa_pool.get_devices();
+       for (unsigned card_index = 0; card_index < available_alsa_devices.size(); ++card_index) {
                const DeviceSpec spec{ InputSourceType::ALSA_INPUT, card_index };
-               const ALSAInput::Device &device = available_alsa_cards[card_index];
+               const ALSAPool::Device &device = available_alsa_devices[card_index];
                DeviceInfo info;
                info.name = device.name + " (" + device.info + ")";
                info.num_channels = device.num_channels;
@@ -783,14 +782,25 @@ void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping)
        }
 
        // Reset resamplers for all cards that don't have the exact same state as before.
-       for (const auto &spec_and_info : get_devices_mutex_held()) {
-               const DeviceSpec &device_spec = spec_and_info.first;
+       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);
                if (device->interesting_channels != interesting_channels[device_spec]) {
                        device->interesting_channels = interesting_channels[device_spec];
-                       if (device_spec.type == InputSourceType::ALSA_INPUT) {
-                               reset_alsa_mutex_held(device_spec);
-                       }
+                       reset_resampler_mutex_held(device_spec);
+               }
+       }
+       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);
+               }
+               if (device->interesting_channels != interesting_channels[device_spec]) {
+                       device->interesting_channels = interesting_channels[device_spec];
+                       alsa_pool.reset_device(device_spec.index);
                        reset_resampler_mutex_held(device_spec);
                }
        }