From: Steinar H. Gunderson Date: Sat, 13 Aug 2016 12:29:01 +0000 (+0200) Subject: Add support for ALSA inputs to the mixer. X-Git-Tag: 1.4.0~100 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;ds=sidebyside;h=0b0e067a60997906a192dd184434260dd97938da;p=nageru Add support for ALSA inputs to the mixer. --- diff --git a/audio_mixer.cpp b/audio_mixer.cpp index c1f7410..acd48c5 100644 --- a/audio_mixer.cpp +++ b/audio_mixer.cpp @@ -13,6 +13,7 @@ using namespace bmusb; using namespace std; +using namespace std::placeholders; namespace { @@ -104,8 +105,22 @@ AudioMixer::AudioMixer(unsigned num_cards) InputMapping new_input_mapping; new_input_mapping.buses.push_back(input); set_input_mapping(new_input_mapping); + + // Look for ALSA cards. + available_alsa_cards = ALSAInput::enumerate_devices(); +} + +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 lock(audio_mutex); @@ -126,6 +141,24 @@ 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 { + device->alsa_device.reset(new ALSAInput(available_alsa_cards[card_index].address.c_str(), OUTPUT_FREQUENCY, 2, 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(); + } +} + void 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); @@ -197,6 +230,8 @@ AudioMixer::AudioDevice *AudioMixer::find_audio_device(DeviceSpec device) switch (device.type) { case InputSourceType::CAPTURE_CARD: return &video_cards[device.index]; + case InputSourceType::ALSA_INPUT: + return &alsa_inputs[device.index]; case InputSourceType::SILENCE: default: assert(false); @@ -204,6 +239,8 @@ AudioMixer::AudioDevice *AudioMixer::find_audio_device(DeviceSpec device) return nullptr; } +// Get a pointer to the given channel from the given device. +// The channel must be picked out earlier and resampled. void AudioMixer::find_sample_src_from_device(const map> &samples_card, DeviceSpec device_spec, int source_channel, const float **srcptr, unsigned *stride) { static float zero = 0.0f; @@ -213,6 +250,7 @@ void AudioMixer::find_sample_src_from_device(const map return; } AudioDevice *device = find_audio_device(device_spec); + assert(device->interesting_channels.count(source_channel) != 0); unsigned channel_index = 0; for (int channel : device->interesting_channels) { if (channel == source_channel) break; @@ -231,7 +269,8 @@ void AudioMixer::fill_audio_bus(const map> &samples_ca if (bus.device.type == InputSourceType::SILENCE) { memset(output, 0, num_samples * sizeof(*output)); } else { - assert(bus.device.type == InputSourceType::CAPTURE_CARD); + assert(bus.device.type == InputSourceType::CAPTURE_CARD || + bus.device.type == InputSourceType::ALSA_INPUT); const float *lsrc, *rsrc; unsigned lstride, rstride; float *dptr = output; @@ -419,6 +458,14 @@ map AudioMixer::get_devices_mutex_held() const info.num_channels = 8; // FIXME: This is wrong for fake cards. devices.insert(make_pair(spec, info)); } + for (unsigned card_index = 0; card_index < available_alsa_cards.size(); ++card_index) { + const DeviceSpec spec{ InputSourceType::ALSA_INPUT, card_index }; + const ALSAInput::Device &device = available_alsa_cards[card_index]; + DeviceInfo info; + info.name = device.name + " (" + device.info + ")"; + info.num_channels = device.num_channels; + devices.insert(make_pair(spec, info)); + } return devices; } @@ -436,7 +483,8 @@ void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping) map> interesting_channels; for (const InputMapping::Bus &bus : new_input_mapping.buses) { - if (bus.device.type == InputSourceType::CAPTURE_CARD) { + if (bus.device.type == InputSourceType::CAPTURE_CARD || + bus.device.type == InputSourceType::ALSA_INPUT) { for (unsigned channel = 0; channel < 2; ++channel) { if (bus.source_channel[channel] != -1) { interesting_channels[bus.device].insert(bus.source_channel[channel]); @@ -451,6 +499,9 @@ void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping) 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); } } diff --git a/audio_mixer.h b/audio_mixer.h index 30675b8..23b020d 100644 --- a/audio_mixer.h +++ b/audio_mixer.h @@ -20,6 +20,7 @@ #include #include +#include "alsa_input.h" #include "bmusb/bmusb.h" #include "db.h" #include "defs.h" @@ -31,7 +32,7 @@ namespace bmusb { struct AudioFormat; } // namespace bmusb -enum class InputSourceType { SILENCE, CAPTURE_CARD }; +enum class InputSourceType { SILENCE, CAPTURE_CARD, ALSA_INPUT }; struct DeviceSpec { InputSourceType type; unsigned index; @@ -74,6 +75,7 @@ struct InputMapping { class AudioMixer { public: AudioMixer(unsigned num_cards); + ~AudioMixer(); void reset_resampler(DeviceSpec device_spec); // frame_length is in TIMEBASE units. @@ -204,12 +206,15 @@ private: unsigned capture_frequency = OUTPUT_FREQUENCY; // Which channels we consider interesting (ie., are part of some input_mapping). std::set interesting_channels; + // Only used for ALSA cards, obviously. + std::unique_ptr alsa_device; }; AudioDevice *find_audio_device(DeviceSpec device_spec); void find_sample_src_from_device(const std::map> &samples_card, DeviceSpec device_spec, int source_channel, const float **srcptr, unsigned *stride); void fill_audio_bus(const std::map> &samples_card, const InputMapping::Bus &bus, unsigned num_samples, float *output); void reset_resampler_mutex_held(DeviceSpec device_spec); + void reset_alsa_mutex_held(DeviceSpec device_spec); std::map get_devices_mutex_held() const; unsigned num_cards; @@ -218,6 +223,10 @@ private: AudioDevice video_cards[MAX_VIDEO_CARDS]; // Under audio_mutex. + // TODO: Figure out a better way to unify these two, as they are sharing indexing. + AudioDevice alsa_inputs[MAX_ALSA_CARDS]; // Under audio_mutex. + std::vector available_alsa_cards; + StereoFilter locut; // Default cutoff 120 Hz, 24 dB/oct. std::atomic locut_cutoff_hz; std::atomic locut_enabled{true}; diff --git a/defs.h b/defs.h index 15e6f3c..08708ad 100644 --- a/defs.h +++ b/defs.h @@ -7,6 +7,7 @@ #define HEIGHT 720 #define FAKE_FPS 25 // Must be an integer. #define MAX_VIDEO_CARDS 16 +#define MAX_ALSA_CARDS 16 #define MAX_BUSES 256 // Audio buses. // For deinterlacing. See also comments on InputState. diff --git a/input_mapping_dialog.cpp b/input_mapping_dialog.cpp index 2d40cc2..9c8180c 100644 --- a/input_mapping_dialog.cpp +++ b/input_mapping_dialog.cpp @@ -75,7 +75,8 @@ void InputMappingDialog::setup_channel_choices_from_bus(unsigned row, const Inpu for (unsigned channel = 0; channel < 2; ++channel) { QComboBox *channel_combo = new QComboBox; channel_combo->addItem(QString("(none)")); - if (bus.device.type == InputSourceType::CAPTURE_CARD) { + if (bus.device.type == InputSourceType::CAPTURE_CARD || + bus.device.type == InputSourceType::ALSA_INPUT) { auto device_it = devices.find(bus.device); assert(device_it != devices.end()); unsigned num_device_channels = device_it->second.num_channels;