// TODO: If these prove to be a bottleneck, they can be SSSE3-optimized
// (usually including multiple channels at a time).
+void convert_fixed16_to_fp32(float *dst, size_t out_channel, size_t out_num_channels,
+ const uint8_t *src, size_t in_channel, size_t in_num_channels,
+ size_t num_samples)
+{
+ assert(in_channel < in_num_channels);
+ assert(out_channel < out_num_channels);
+ src += in_channel * 2;
+ dst += out_channel;
+
+ for (size_t i = 0; i < num_samples; ++i) {
+ int16_t s = le16toh(*(int16_t *)src);
+ *dst = s * (1.0f / 32768.0f);
+
+ src += 2 * in_num_channels;
+ dst += out_num_channels;
+ }
+}
+
void convert_fixed24_to_fp32(float *dst, size_t out_channel, size_t out_num_channels,
const uint8_t *src, size_t in_channel, size_t in_num_channels,
size_t num_samples)
} 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, OUTPUT_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()));
}
device->next_local_pts = 0;
}
unsigned num_channels = device->interesting_channels.size();
assert(num_channels > 0);
- // Convert the audio to stereo fp32.
+ // Convert the audio to fp32.
vector<float> audio;
audio.resize(num_samples * num_channels);
unsigned channel_index = 0;
case 0:
assert(num_samples == 0);
break;
+ case 16:
+ convert_fixed16_to_fp32(&audio[0], channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples);
+ break;
case 24:
convert_fixed24_to_fp32(&audio[0], channel_index, num_channels, data, *channel_it, audio_format.num_channels, num_samples);
break;
lock_guard<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 (unsigned card_index = 0; card_index < num_cards; ++card_index) {
AudioDevice *device = &cards[card_index];
if (!device->interesting_channels.empty()) {
return samples_out;
}
-vector<string> AudioMixer::get_names() const
+map<DeviceSpec, DeviceInfo> AudioMixer::get_devices() const
{
lock_guard<mutex> lock(audio_mutex);
- vector<string> names;
+ 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 = &cards[card_index];
- names.push_back(device->name);
+ DeviceInfo info;
+ info.name = device->name;
+ info.num_channels = 8; // FIXME: This is wrong for fake cards.
+ devices.insert(make_pair(spec, info));
}
- return names;
+ return devices;
}
void AudioMixer::set_name(DeviceSpec device_spec, const string &name)
{
lock_guard<mutex> lock(audio_mutex);
- // FIXME: This needs to be keyed on DeviceSpec.
- map<unsigned, set<unsigned>> interesting_channels;
+ map<DeviceSpec, set<unsigned>> interesting_channels;
for (const InputMapping::Bus &bus : new_input_mapping.buses) {
if (bus.device.type == InputSourceType::CAPTURE_CARD) {
for (unsigned channel = 0; channel < 2; ++channel) {
if (bus.source_channel[channel] != -1) {
- interesting_channels[bus.device.index].insert(bus.source_channel[channel]);
+ interesting_channels[bus.device].insert(bus.source_channel[channel]);
}
}
}
// Reset resamplers for all cards that don't have the exact same state as before.
for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
+ DeviceSpec device_spec{InputSourceType::CAPTURE_CARD, card_index};
AudioDevice *device = &cards[card_index];
- if (device->interesting_channels != interesting_channels[card_index]) {
- device->interesting_channels = interesting_channels[card_index];
+ if (device->interesting_channels != interesting_channels[device_spec]) {
+ device->interesting_channels = interesting_channels[device_spec];
reset_device_mutex_held(DeviceSpec{InputSourceType::CAPTURE_CARD, card_index});
}
}