]> git.sesse.net Git - nageru/blobdiff - nageru/audio_mixer.cpp
Fix an assertion error when FFmpeg inputs were dropping frames.
[nageru] / nageru / audio_mixer.cpp
index 891fb227c779f4917201345718b242bc3f71fd39..cef3c3c87fb31416b78e50c7ac601797265f41f3 100644 (file)
@@ -52,6 +52,26 @@ void convert_fixed16_to_fp32(float *dst, size_t out_channel, size_t out_num_chan
        }
 }
 
+void convert_fixed16_to_fixed32(int32_t *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) {
+               uint32_t s = uint32_t(uint16_t(le16toh(*(int16_t *)src))) << 16;
+
+               // Keep the sign bit in place, repeat the other 15 bits as far as they go.
+               *dst = s | ((s & 0x7fffffff) >> 15) | ((s & 0x7fffffff) >> 30);
+
+               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)
@@ -73,6 +93,29 @@ void convert_fixed24_to_fp32(float *dst, size_t out_channel, size_t out_num_chan
        }
 }
 
+void convert_fixed24_to_fixed32(int32_t *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 * 3;
+       dst += out_channel;
+
+       for (size_t i = 0; i < num_samples; ++i) {
+               uint32_t s1 = src[0];
+               uint32_t s2 = src[1];
+               uint32_t s3 = src[2];
+               uint32_t s = (s1 << 8) | (s2 << 16) | (s3 << 24);
+
+               // Keep the sign bit in place, repeat the other 23 bits as far as they go.
+               *dst = s | ((s & 0x7fffffff) >> 23);
+
+               src += 3 * in_num_channels;
+               dst += out_num_channels;
+       }
+}
+
 void convert_fixed32_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)
@@ -91,6 +134,25 @@ void convert_fixed32_to_fp32(float *dst, size_t out_channel, size_t out_num_chan
        }
 }
 
+// Basically just a reinterleave.
+void convert_fixed32_to_fixed32(int32_t *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 * 4;
+       dst += out_channel;
+
+       for (size_t i = 0; i < num_samples; ++i) {
+               int32_t s = le32toh(*(int32_t *)src);
+               *dst = s;
+
+               src += 4 * in_num_channels;
+               dst += out_num_channels;
+       }
+}
+
 float find_peak_plain(const float *samples, size_t num_samples) __attribute__((unused));
 
 float find_peak_plain(const float *samples, size_t num_samples)
@@ -206,7 +268,7 @@ AudioMixer::AudioMixer(unsigned num_capture_cards, unsigned num_ffmpeg_inputs)
                                                  &new_input_mapping)) {
                        fprintf(stderr, "Failed to load input mapping from '%s', exiting.\n",
                                global_flags.input_mapping_filename.c_str());
-                       exit(1);
+                       abort();
                }
                set_input_mapping(new_input_mapping);
        } else {
@@ -258,7 +320,12 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned
        }
 
        unsigned num_channels = device->interesting_channels.size();
-       assert(num_channels > 0);
+       if (num_channels == 0) {
+               // No buses use this device; throw it away. (Normally, we should not
+               // be here, but probably, we are in the process of changing a mapping,
+               // and the queue just isn't gone yet. In any case, returning is harmless.)
+               return true;
+       }
 
        // Convert the audio to fp32.
        unique_ptr<float[]> audio(new float[num_samples * num_channels]);
@@ -294,6 +361,38 @@ bool AudioMixer::add_audio(DeviceSpec device_spec, const uint8_t *data, unsigned
        return true;
 }
 
+vector<int32_t> convert_audio_to_fixed32(const uint8_t *data, unsigned num_samples, bmusb::AudioFormat audio_format, unsigned num_channels)
+{
+       vector<int32_t> audio;
+
+       if (num_channels > audio_format.num_channels) {
+               audio.resize(num_samples * num_channels, 0);
+       } else {
+               audio.resize(num_samples * num_channels);
+       }
+       for (unsigned channel_index = 0; channel_index < num_channels && channel_index < audio_format.num_channels; ++channel_index) {
+               switch (audio_format.bits_per_sample) {
+               case 0:
+                       assert(num_samples == 0);
+                       break;
+               case 16:
+                       convert_fixed16_to_fixed32(&audio[0], channel_index, num_channels, data, channel_index, audio_format.num_channels, num_samples);
+                       break;
+               case 24:
+                       convert_fixed24_to_fixed32(&audio[0], channel_index, num_channels, data, channel_index, audio_format.num_channels, num_samples);
+                       break;
+               case 32:
+                       convert_fixed32_to_fixed32(&audio[0], channel_index, num_channels, data, channel_index, audio_format.num_channels, num_samples);
+                       break;
+               default:
+                       fprintf(stderr, "Cannot handle audio with %u bits per sample\n", audio_format.bits_per_sample);
+                       assert(false);
+               }
+       }
+
+       return audio;
+}
+
 bool AudioMixer::add_silence(DeviceSpec device_spec, unsigned samples_per_frame, unsigned num_frames)
 {
        AudioDevice *device = find_audio_device(device_spec);