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();
}
-void AudioMixer::reset_device(DeviceSpec device_spec)
+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);
- reset_device_mutex_held(device_spec);
+ lock_guard<timed_mutex> lock(audio_mutex);
+ reset_resampler_mutex_held(device_spec);
}
-void AudioMixer::reset_device_mutex_held(DeviceSpec device_spec)
+void AudioMixer::reset_resampler_mutex_held(DeviceSpec device_spec)
{
AudioDevice *device = find_audio_device(device_spec);
+
if (device->interesting_channels.empty()) {
device->resampling_queue.reset();
} else {
device->next_local_pts = 0;
}
-void AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned num_samples, AudioFormat audio_format, int64_t frame_length)
+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);
- lock_guard<mutex> lock(audio_mutex);
+ 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();
+ }
+}
+
+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);
+
+ unique_lock<timed_mutex> lock(audio_mutex, defer_lock);
+ if (!lock.try_lock_for(chrono::milliseconds(10))) {
+ return false;
+ }
if (device->resampling_queue == nullptr) {
// No buses use this device; throw it away.
- return;
+ return true;
}
unsigned num_channels = device->interesting_channels.size();
int64_t local_pts = device->next_local_pts;
device->resampling_queue->add_input_samples(local_pts / double(TIMEBASE), audio.data(), num_samples);
device->next_local_pts = local_pts + frame_length;
+ return true;
}
-void AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame, unsigned num_frames, int64_t frame_length)
+bool AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame, unsigned num_frames, int64_t frame_length)
{
AudioDevice *device = find_audio_device(device_spec);
- lock_guard<mutex> lock(audio_mutex);
+ unique_lock<timed_mutex> lock(audio_mutex, defer_lock);
+ if (!lock.try_lock_for(chrono::milliseconds(10))) {
+ return false;
+ }
if (device->resampling_queue == nullptr) {
// No buses use this device; throw it away.
- return;
+ return true;
}
unsigned num_channels = device->interesting_channels.size();
// is always the same.
device->next_local_pts += frame_length;
}
+ return true;
}
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);
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;
map<DeviceSpec, vector<float>> samples_card;
vector<float> samples_bus;
- lock_guard<mutex> lock(audio_mutex);
+ 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
map<DeviceSpec, DeviceInfo> AudioMixer::get_devices() const
{
- lock_guard<mutex> lock(audio_mutex);
+ lock_guard<timed_mutex> lock(audio_mutex);
return get_devices_mutex_held();
}
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;
}
{
AudioDevice *device = find_audio_device(device_spec);
- lock_guard<mutex> lock(audio_mutex);
+ lock_guard<timed_mutex> lock(audio_mutex);
device->name = name;
}
void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping)
{
- lock_guard<mutex> lock(audio_mutex);
+ lock_guard<timed_mutex> lock(audio_mutex);
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];
- reset_device_mutex_held(device_spec);
+ if (device_spec.type == InputSourceType::ALSA_INPUT) {
+ reset_alsa_mutex_held(device_spec);
+ }
+ reset_resampler_mutex_held(device_spec);
}
}
InputMapping AudioMixer::get_input_mapping() const
{
- lock_guard<mutex> lock(audio_mutex);
+ lock_guard<timed_mutex> lock(audio_mutex);
return input_mapping;
}