using namespace bmusb;
using namespace std;
+using namespace std::placeholders;
namespace {
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<mutex> lock(audio_mutex);
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);
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);
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<DeviceSpec, vector<float>> &samples_card, DeviceSpec device_spec, int source_channel, const float **srcptr, unsigned *stride)
{
static float zero = 0.0f;
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;
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;
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;
}
map<DeviceSpec, set<unsigned>> 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]);
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);
}
}
#include <set>
#include <vector>
+#include "alsa_input.h"
#include "bmusb/bmusb.h"
#include "db.h"
#include "defs.h"
struct AudioFormat;
} // namespace bmusb
-enum class InputSourceType { SILENCE, CAPTURE_CARD };
+enum class InputSourceType { SILENCE, CAPTURE_CARD, ALSA_INPUT };
struct DeviceSpec {
InputSourceType type;
unsigned index;
class AudioMixer {
public:
AudioMixer(unsigned num_cards);
+ ~AudioMixer();
void reset_resampler(DeviceSpec device_spec);
// frame_length is in TIMEBASE units.
unsigned capture_frequency = OUTPUT_FREQUENCY;
// Which channels we consider interesting (ie., are part of some input_mapping).
std::set<unsigned> interesting_channels;
+ // Only used for ALSA cards, obviously.
+ std::unique_ptr<ALSAInput> alsa_device;
};
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 reset_alsa_mutex_held(DeviceSpec device_spec);
std::map<DeviceSpec, DeviceInfo> get_devices_mutex_held() const;
unsigned num_cards;
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<ALSAInput::Device> available_alsa_cards;
+
StereoFilter locut; // Default cutoff 120 Hz, 24 dB/oct.
std::atomic<float> locut_cutoff_hz;
std::atomic<bool> locut_enabled{true};