Skip to content

Commit

Permalink
Migrate audio pipeline to float from 16-bit int
Browse files Browse the repository at this point in the history
Float is the native format of opus codec and most if not all capture
backends.
  • Loading branch information
ns6089 committed Jul 20, 2024
1 parent f694137 commit d83e93b
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 27 deletions.
6 changes: 3 additions & 3 deletions src/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
namespace audio {
using namespace std::literals;
using opus_t = util::safe_ptr<OpusMSEncoder, opus_multistream_encoder_destroy>;
using sample_queue_t = std::shared_ptr<safe::queue_t<std::vector<std::int16_t>>>;
using sample_queue_t = std::shared_ptr<safe::queue_t<std::vector<float>>>;

struct audio_ctx_t {
// We want to change the sink for the first stream only
Expand Down Expand Up @@ -128,7 +128,7 @@ namespace audio {
while (auto sample = samples->pop()) {
buffer_t packet { 1400 };

int bytes = opus_multistream_encode(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size());
int bytes = opus_multistream_encode_float(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size());
if (bytes < 0) {
BOOST_LOG(error) << "Couldn't encode audio: "sv << opus_strerror(bytes);
packets->stop();
Expand Down Expand Up @@ -228,7 +228,7 @@ namespace audio {
int samples_per_frame = frame_size * stream.channelCount;

while (!shutdown_event->peek()) {
std::vector<std::int16_t> sample_buffer;
std::vector<float> sample_buffer;
sample_buffer.resize(samples_per_frame);

auto status = mic->sample(sample_buffer);
Expand Down
2 changes: 1 addition & 1 deletion src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ namespace platf {
class mic_t {
public:
virtual capture_e
sample(std::vector<std::int16_t> &frame_buffer) = 0;
sample(std::vector<float> &frame_buffer) = 0;

virtual ~mic_t() = default;
};
Expand Down
11 changes: 6 additions & 5 deletions src/platform/linux/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace platf {
to_string(const char *name, const std::uint8_t *mapping, int channels) {
std::stringstream ss;

ss << "rate=48000 sink_name="sv << name << " format=s16le channels="sv << channels << " channel_map="sv;
ss << "rate=48000 sink_name="sv << name << " format=float channels="sv << channels << " channel_map="sv;
std::for_each_n(mapping, channels - 1, [&ss](std::uint8_t pos) {
ss << pa_channel_position_to_string(position_mapping[pos]) << ',';
});
Expand All @@ -54,12 +54,12 @@ namespace platf {
util::safe_ptr<pa_simple, pa_simple_free> mic;

capture_e
sample(std::vector<std::int16_t> &sample_buf) override {
sample(std::vector<float> &sample_buf) override {

Check warning on line 57 in src/platform/linux/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/audio.cpp#L57

Added line #L57 was not covered by tests
auto sample_size = sample_buf.size();

auto buf = sample_buf.data();
int status;
if (pa_simple_read(mic.get(), buf, sample_size * 2, &status)) {
if (pa_simple_read(mic.get(), buf, sample_size * sizeof(float), &status)) {
BOOST_LOG(error) << "pa_simple_read() failed: "sv << pa_strerror(status);

return capture_e::error;
Expand All @@ -73,7 +73,7 @@ namespace platf {
microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size, std::string source_name) {
auto mic = std::make_unique<mic_attr_t>();

pa_sample_spec ss { PA_SAMPLE_S16LE, sample_rate, (std::uint8_t) channels };
pa_sample_spec ss { PA_SAMPLE_FLOAT32, sample_rate, (std::uint8_t) channels };

Check warning on line 76 in src/platform/linux/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/audio.cpp#L76

Added line #L76 was not covered by tests
pa_channel_map pa_map;

pa_map.channels = channels;
Expand All @@ -82,7 +82,8 @@ namespace platf {
});

pa_buffer_attr pa_attr = {};
pa_attr.maxlength = frame_size * 8;
pa_attr.fragsize = frame_size * channels * sizeof(float);

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'unsigned long'.
pa_attr.maxlength = pa_attr.fragsize * 2;

Check warning on line 86 in src/platform/linux/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/audio.cpp#L85-L86

Added lines #L85 - L86 were not covered by tests

int status;

Expand Down
2 changes: 1 addition & 1 deletion src/platform/macos/av_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "third-party/TPCircularBuffer/TPCircularBuffer.h"

#define kBufferLength 2048
#define kBufferLength 4096

@interface AVAudio: NSObject <AVCaptureAudioDataOutputSampleBufferDelegate> {
@public
Expand Down
4 changes: 2 additions & 2 deletions src/platform/macos/av_audio.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ - (int)setupMicrophone:(AVCaptureDevice *)device sampleRate:(UInt32)sampleRate f
(NSString *) AVFormatIDKey: [NSNumber numberWithUnsignedInt:kAudioFormatLinearPCM],
(NSString *) AVSampleRateKey: [NSNumber numberWithUnsignedInt:sampleRate],
(NSString *) AVNumberOfChannelsKey: [NSNumber numberWithUnsignedInt:channels],
(NSString *) AVLinearPCMBitDepthKey: [NSNumber numberWithUnsignedInt:16],
(NSString *) AVLinearPCMIsFloatKey: @NO,
(NSString *) AVLinearPCMBitDepthKey: [NSNumber numberWithUnsignedInt:32],
(NSString *) AVLinearPCMIsFloatKey: @YES,

Check warning on line 91 in src/platform/macos/av_audio.m

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/av_audio.m#L90-L91

Added lines #L90 - L91 were not covered by tests
(NSString *) AVLinearPCMIsNonInterleaved: @NO
}];

Expand Down
10 changes: 5 additions & 5 deletions src/platform/macos/microphone.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
}

capture_e
sample(std::vector<std::int16_t> &sample_in) override {
sample(std::vector<float> &sample_in) override {

Check warning on line 22 in src/platform/macos/microphone.mm

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/microphone.mm#L22

Added line #L22 was not covered by tests
auto sample_size = sample_in.size();

uint32_t length = 0;
void *byteSampleBuffer = TPCircularBufferTail(&av_audio_capture->audioSampleBuffer, &length);

while (length < sample_size * sizeof(std::int16_t)) {
while (length < sample_size * sizeof(float)) {
[av_audio_capture.samplesArrivedSignal wait];
byteSampleBuffer = TPCircularBufferTail(&av_audio_capture->audioSampleBuffer, &length);
}

const int16_t *sampleBuffer = (int16_t *) byteSampleBuffer;
std::vector<int16_t> vectorBuffer(sampleBuffer, sampleBuffer + sample_size);
const float *sampleBuffer = (float *) byteSampleBuffer;
std::vector<float> vectorBuffer(sampleBuffer, sampleBuffer + sample_size);

Check warning on line 34 in src/platform/macos/microphone.mm

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/microphone.mm#L33-L34

Added lines #L33 - L34 were not covered by tests

std::copy_n(std::begin(vectorBuffer), sample_size, std::begin(sample_in));

TPCircularBufferConsume(&av_audio_capture->audioSampleBuffer, sample_size * sizeof(std::int16_t));
TPCircularBufferConsume(&av_audio_capture->audioSampleBuffer, sample_size * sizeof(float));

return capture_e::ok;
}
Expand Down
20 changes: 10 additions & 10 deletions src/platform/windows/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,22 @@ namespace platf::audio {
wave_format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wave_format.Format.nChannels = format.channels;
wave_format.Format.nSamplesPerSec = SAMPLE_RATE;
wave_format.Format.wBitsPerSample = 16;
wave_format.Format.wBitsPerSample = 32;

Check warning on line 155 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L155

Added line #L155 was not covered by tests
wave_format.Format.nBlockAlign = wave_format.Format.nChannels * wave_format.Format.wBitsPerSample / 8;
wave_format.Format.nAvgBytesPerSec = wave_format.Format.nSamplesPerSec * wave_format.Format.nBlockAlign;
wave_format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);

wave_format.Samples.wValidBitsPerSample = 16;
wave_format.Samples.wValidBitsPerSample = 32;

Check warning on line 160 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L160

Added line #L160 was not covered by tests
wave_format.dwChannelMask = format.channel_mask;
wave_format.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wave_format.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;

Check warning on line 162 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L162

Added line #L162 was not covered by tests

return wave_format;
}

int
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Check warning on line 170 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L170

Added line #L170 was not covered by tests

switch (wave_format->wFormatTag) {
case WAVE_FORMAT_PCM:
Expand All @@ -176,7 +176,7 @@ namespace platf::audio {
break;
case WAVE_FORMAT_EXTENSIBLE: {
auto wave_ex = (PWAVEFORMATEXTENSIBLE) wave_format.get();
wave_ex->Samples.wValidBitsPerSample = 16;
wave_ex->Samples.wValidBitsPerSample = 24;

Check warning on line 179 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L179

Added line #L179 was not covered by tests
wave_ex->dwChannelMask = format.channel_mask;
wave_ex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
Expand Down Expand Up @@ -341,7 +341,7 @@ namespace platf::audio {
class mic_wasapi_t: public mic_t {
public:
capture_e
sample(std::vector<std::int16_t> &sample_out) override {
sample(std::vector<float> &sample_out) override {

Check warning on line 344 in src/platform/windows/audio.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/audio.cpp#L344

Added line #L344 was not covered by tests
auto sample_size = sample_out.size();

// Refill the sample buffer if needed
Expand Down Expand Up @@ -432,7 +432,7 @@ namespace platf::audio {
}

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type High

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
sample_buf_pos = std::begin(sample_buf);

status = audio_client->GetService(IID_IAudioCaptureClient, (void **) &audio_capture);
Expand Down Expand Up @@ -489,7 +489,7 @@ namespace platf::audio {
// Total number of samples
struct sample_aligned_t {
std::uint32_t uninitialized;
std::int16_t *samples;
float *samples;
} sample_aligned;

// number of samples / number of channels
Expand Down Expand Up @@ -588,8 +588,8 @@ namespace platf::audio {

REFERENCE_TIME default_latency_ms;

util::buffer_t<std::int16_t> sample_buf;
std::int16_t *sample_buf_pos;
util::buffer_t<float> sample_buf;
float *sample_buf_pos;
int channels;

HANDLE mmcss_task_handle = NULL;
Expand Down

0 comments on commit d83e93b

Please sign in to comment.