Use std::array<> consistently for reusable audio buffers.
This is a minor change for places where we use AudioFrame::kMaxDataSizeSamples sized intermediary buffers. The change uses `std::array<>` instead of C style arrays which allows for use of utility templates that incorporate type based buffer size checking. Also adding `ClearSamples()` method, which complements CopySamples. Bug: chromium:335805780 Change-Id: I813feb32937e020ceb9ca4b00632dc90907c93fb Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/351681 Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org> Reviewed-by: Per Åhgren <peah@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42400}
This commit is contained in:
parent
22712ca11c
commit
19c51ea537
@ -78,9 +78,9 @@ void AudioFrame::UpdateFrame(uint32_t timestamp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const size_t length = samples_per_channel * num_channels;
|
const size_t length = samples_per_channel * num_channels;
|
||||||
RTC_CHECK_LE(length, kMaxDataSizeSamples);
|
RTC_CHECK_LE(length, data_.size());
|
||||||
if (data != nullptr) {
|
if (data != nullptr) {
|
||||||
memcpy(data_, data, sizeof(int16_t) * length);
|
memcpy(data_.data(), data, sizeof(int16_t) * length);
|
||||||
muted_ = false;
|
muted_ = false;
|
||||||
} else {
|
} else {
|
||||||
muted_ = true;
|
muted_ = true;
|
||||||
@ -98,7 +98,7 @@ void AudioFrame::CopyFrom(const AudioFrame& src) {
|
|||||||
// copying over new values. If we don't, msan might complain in some tests.
|
// copying over new values. If we don't, msan might complain in some tests.
|
||||||
// Consider locking down construction, avoiding the default constructor and
|
// Consider locking down construction, avoiding the default constructor and
|
||||||
// prefering construction that initializes all state.
|
// prefering construction that initializes all state.
|
||||||
memset(data_, 0, kMaxDataSizeBytes);
|
ClearSamples(data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
timestamp_ = src.timestamp_;
|
timestamp_ = src.timestamp_;
|
||||||
@ -115,7 +115,7 @@ void AudioFrame::CopyFrom(const AudioFrame& src) {
|
|||||||
absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms();
|
absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms();
|
||||||
|
|
||||||
auto data = src.data_view();
|
auto data = src.data_view();
|
||||||
RTC_CHECK_LE(data.size(), kMaxDataSizeSamples);
|
RTC_CHECK_LE(data.size(), data_.size());
|
||||||
if (!muted_ && !data.empty()) {
|
if (!muted_ && !data.empty()) {
|
||||||
memcpy(&data_[0], &data[0], sizeof(int16_t) * data.size());
|
memcpy(&data_[0], &data[0], sizeof(int16_t) * data.size());
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ int64_t AudioFrame::ElapsedProfileTimeMs() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int16_t* AudioFrame::data() const {
|
const int16_t* AudioFrame::data() const {
|
||||||
return muted_ ? zeroed_data().begin() : data_;
|
return muted_ ? zeroed_data().begin() : data_.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
InterleavedView<const int16_t> AudioFrame::data_view() const {
|
InterleavedView<const int16_t> AudioFrame::data_view() const {
|
||||||
@ -155,16 +155,16 @@ int16_t* AudioFrame::mutable_data() {
|
|||||||
// Consider instead if we should rather zero the buffer when `muted_` is set
|
// Consider instead if we should rather zero the buffer when `muted_` is set
|
||||||
// to `true`.
|
// to `true`.
|
||||||
if (muted_) {
|
if (muted_) {
|
||||||
memset(data_, 0, kMaxDataSizeBytes);
|
ClearSamples(data_);
|
||||||
muted_ = false;
|
muted_ = false;
|
||||||
}
|
}
|
||||||
return data_;
|
return &data_[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
InterleavedView<int16_t> AudioFrame::mutable_data(size_t samples_per_channel,
|
InterleavedView<int16_t> AudioFrame::mutable_data(size_t samples_per_channel,
|
||||||
size_t num_channels) {
|
size_t num_channels) {
|
||||||
const size_t total_samples = samples_per_channel * num_channels;
|
const size_t total_samples = samples_per_channel * num_channels;
|
||||||
RTC_CHECK_LE(total_samples, kMaxDataSizeSamples);
|
RTC_CHECK_LE(total_samples, data_.size());
|
||||||
RTC_CHECK_LE(num_channels, kMaxConcurrentChannels);
|
RTC_CHECK_LE(num_channels, kMaxConcurrentChannels);
|
||||||
// Sanity check for valid argument values during development.
|
// Sanity check for valid argument values during development.
|
||||||
// If `samples_per_channel` is < `num_channels` but larger than 0,
|
// If `samples_per_channel` is < `num_channels` but larger than 0,
|
||||||
@ -178,7 +178,7 @@ InterleavedView<int16_t> AudioFrame::mutable_data(size_t samples_per_channel,
|
|||||||
// Consider instead if we should rather zero the whole buffer when `muted_` is
|
// Consider instead if we should rather zero the whole buffer when `muted_` is
|
||||||
// set to `true`.
|
// set to `true`.
|
||||||
if (muted_) {
|
if (muted_) {
|
||||||
memset(data_, 0, total_samples * sizeof(int16_t));
|
ClearSamples(data_, total_samples);
|
||||||
muted_ = false;
|
muted_ = false;
|
||||||
}
|
}
|
||||||
samples_per_channel_ = samples_per_channel;
|
samples_per_channel_ = samples_per_channel;
|
||||||
@ -206,7 +206,7 @@ void AudioFrame::SetLayoutAndNumChannels(ChannelLayout layout,
|
|||||||
RTC_DCHECK_EQ(expected_num_channels, num_channels_);
|
RTC_DCHECK_EQ(expected_num_channels, num_channels_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
RTC_CHECK_LE(samples_per_channel_ * num_channels_, kMaxDataSizeSamples);
|
RTC_CHECK_LE(samples_per_channel_ * num_channels_, data_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioFrame::SetSampleRateAndChannelSize(int sample_rate) {
|
void AudioFrame::SetSampleRateAndChannelSize(int sample_rate) {
|
||||||
|
|||||||
@ -14,6 +14,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/audio/audio_view.h"
|
#include "api/audio/audio_view.h"
|
||||||
#include "api/audio/channel_layout.h"
|
#include "api/audio/channel_layout.h"
|
||||||
@ -146,7 +148,7 @@ class AudioFrame {
|
|||||||
// Frame is muted by default.
|
// Frame is muted by default.
|
||||||
bool muted() const;
|
bool muted() const;
|
||||||
|
|
||||||
size_t max_16bit_samples() const { return kMaxDataSizeSamples; }
|
size_t max_16bit_samples() const { return data_.size(); }
|
||||||
size_t samples_per_channel() const { return samples_per_channel_; }
|
size_t samples_per_channel() const { return samples_per_channel_; }
|
||||||
size_t num_channels() const { return num_channels_; }
|
size_t num_channels() const { return num_channels_; }
|
||||||
|
|
||||||
@ -211,7 +213,7 @@ class AudioFrame {
|
|||||||
// buffer per translation unit is to wrap a static in an inline function.
|
// buffer per translation unit is to wrap a static in an inline function.
|
||||||
static rtc::ArrayView<const int16_t> zeroed_data();
|
static rtc::ArrayView<const int16_t> zeroed_data();
|
||||||
|
|
||||||
int16_t data_[kMaxDataSizeSamples];
|
std::array<int16_t, kMaxDataSizeSamples> data_;
|
||||||
bool muted_ = true;
|
bool muted_ = true;
|
||||||
ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
|
ChannelLayout channel_layout_ = CHANNEL_LAYOUT_NONE;
|
||||||
|
|
||||||
|
|||||||
@ -248,6 +248,22 @@ void CopySamples(D& destination, const S& source) {
|
|||||||
source.size() * sizeof(typename S::value_type));
|
source.size() * sizeof(typename S::value_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets all the samples in a view to 0. This template function is a simple
|
||||||
|
// wrapper around `memset()` but adds the benefit of automatically calculating
|
||||||
|
// the byte size from the number of samples and sample type.
|
||||||
|
template <typename T>
|
||||||
|
void ClearSamples(T& view) {
|
||||||
|
memset(&view[0], 0, view.size() * sizeof(typename T::value_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as `ClearSamples()` above but allows for clearing only the first
|
||||||
|
// `sample_count` number of samples.
|
||||||
|
template <typename T>
|
||||||
|
void ClearSamples(T& view, size_t sample_count) {
|
||||||
|
RTC_DCHECK_LE(sample_count, view.size());
|
||||||
|
memset(&view[0], 0, sample_count * sizeof(typename T::value_type));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // API_AUDIO_AUDIO_VIEW_H_
|
#endif // API_AUDIO_AUDIO_VIEW_H_
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "api/audio/audio_view.h"
|
#include "api/audio/audio_view.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -155,4 +157,34 @@ TEST(AudioViewTest, CopySamples) {
|
|||||||
ASSERT_EQ(dest_arr[i], source_arr[i]) << "i == " << i;
|
ASSERT_EQ(dest_arr[i], source_arr[i]) << "i == " << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AudioViewTest, ClearSamples) {
|
||||||
|
std::array<int16_t, 100u> samples = {};
|
||||||
|
FillBuffer(rtc::ArrayView<int16_t>(samples));
|
||||||
|
ASSERT_NE(samples[0], 0);
|
||||||
|
ClearSamples(samples);
|
||||||
|
for (const auto s : samples) {
|
||||||
|
ASSERT_EQ(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<float, 100u> samples_f = {};
|
||||||
|
FillBuffer(rtc::ArrayView<float>(samples_f));
|
||||||
|
ASSERT_NE(samples_f[0], 0.0);
|
||||||
|
ClearSamples(samples_f);
|
||||||
|
for (const auto s : samples_f) {
|
||||||
|
ASSERT_EQ(s, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear only half of the buffer
|
||||||
|
FillBuffer(rtc::ArrayView<int16_t>(samples));
|
||||||
|
const auto half_way = samples.size() / 2;
|
||||||
|
ClearSamples(samples, half_way);
|
||||||
|
for (size_t i = 0u; i < samples.size(); ++i) {
|
||||||
|
if (i < half_way) {
|
||||||
|
ASSERT_EQ(samples[i], 0);
|
||||||
|
} else {
|
||||||
|
ASSERT_NE(samples[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "audio/remix_resample.h"
|
#include "audio/remix_resample.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "api/audio/audio_frame.h"
|
#include "api/audio/audio_frame.h"
|
||||||
#include "audio/utility/audio_frame_operations.h"
|
#include "audio/utility/audio_frame_operations.h"
|
||||||
#include "common_audio/resampler/include/push_resampler.h"
|
#include "common_audio/resampler/include/push_resampler.h"
|
||||||
@ -40,7 +42,7 @@ void RemixAndResample(const int16_t* src_data,
|
|||||||
AudioFrame* dst_frame) {
|
AudioFrame* dst_frame) {
|
||||||
const int16_t* audio_ptr = src_data;
|
const int16_t* audio_ptr = src_data;
|
||||||
size_t audio_ptr_num_channels = num_channels;
|
size_t audio_ptr_num_channels = num_channels;
|
||||||
int16_t downmixed_audio[AudioFrame::kMaxDataSizeSamples];
|
std::array<int16_t, AudioFrame::kMaxDataSizeSamples> downmixed_audio;
|
||||||
|
|
||||||
// Downmix before resampling.
|
// Downmix before resampling.
|
||||||
if (num_channels > dst_frame->num_channels_) {
|
if (num_channels > dst_frame->num_channels_) {
|
||||||
@ -54,7 +56,7 @@ void RemixAndResample(const int16_t* src_data,
|
|||||||
num_channels),
|
num_channels),
|
||||||
InterleavedView<int16_t>(&downmixed_audio[0], samples_per_channel,
|
InterleavedView<int16_t>(&downmixed_audio[0], samples_per_channel,
|
||||||
dst_frame->num_channels_));
|
dst_frame->num_channels_));
|
||||||
audio_ptr = downmixed_audio;
|
audio_ptr = downmixed_audio.data();
|
||||||
audio_ptr_num_channels = dst_frame->num_channels_;
|
audio_ptr_num_channels = dst_frame->num_channels_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -56,15 +56,13 @@ AcmReceiver::Config::Config(const Config&) = default;
|
|||||||
AcmReceiver::Config::~Config() = default;
|
AcmReceiver::Config::~Config() = default;
|
||||||
|
|
||||||
AcmReceiver::AcmReceiver(const Config& config)
|
AcmReceiver::AcmReceiver(const Config& config)
|
||||||
: last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
|
: neteq_(CreateNetEq(config.neteq_factory,
|
||||||
neteq_(CreateNetEq(config.neteq_factory,
|
|
||||||
config.neteq_config,
|
config.neteq_config,
|
||||||
&config.clock,
|
&config.clock,
|
||||||
config.decoder_factory)),
|
config.decoder_factory)),
|
||||||
clock_(config.clock),
|
clock_(config.clock),
|
||||||
resampled_last_output_frame_(true) {
|
resampled_last_output_frame_(true) {
|
||||||
memset(last_audio_buffer_.get(), 0,
|
ClearSamples(last_audio_buffer_);
|
||||||
sizeof(int16_t) * AudioFrame::kMaxDataSizeSamples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AcmReceiver::~AcmReceiver() = default;
|
AcmReceiver::~AcmReceiver() = default;
|
||||||
@ -170,7 +168,7 @@ int AcmReceiver::GetAudio(int desired_freq_hz,
|
|||||||
// Prime the resampler with the last frame.
|
// Prime the resampler with the last frame.
|
||||||
int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
|
int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
|
||||||
int samples_per_channel_int = resampler_.Resample10Msec(
|
int samples_per_channel_int = resampler_.Resample10Msec(
|
||||||
last_audio_buffer_.get(), current_sample_rate_hz, desired_freq_hz,
|
last_audio_buffer_.data(), current_sample_rate_hz, desired_freq_hz,
|
||||||
audio_frame->num_channels_, AudioFrame::kMaxDataSizeSamples,
|
audio_frame->num_channels_, AudioFrame::kMaxDataSizeSamples,
|
||||||
temp_output);
|
temp_output);
|
||||||
if (samples_per_channel_int < 0) {
|
if (samples_per_channel_int < 0) {
|
||||||
@ -206,7 +204,8 @@ int AcmReceiver::GetAudio(int desired_freq_hz,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store current audio in `last_audio_buffer_` for next time.
|
// Store current audio in `last_audio_buffer_` for next time.
|
||||||
memcpy(last_audio_buffer_.get(), audio_frame->data(),
|
// TODO: b/335805780 - Use CopySamples().
|
||||||
|
memcpy(last_audio_buffer_.data(), audio_frame->data(),
|
||||||
sizeof(int16_t) * audio_frame->samples_per_channel_ *
|
sizeof(int16_t) * audio_frame->samples_per_channel_ *
|
||||||
audio_frame->num_channels_);
|
audio_frame->num_channels_);
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -21,6 +22,7 @@
|
|||||||
|
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
|
#include "api/audio/audio_frame.h"
|
||||||
#include "api/audio_codecs/audio_decoder.h"
|
#include "api/audio_codecs/audio_decoder.h"
|
||||||
#include "api/audio_codecs/audio_decoder_factory.h"
|
#include "api/audio_codecs/audio_decoder_factory.h"
|
||||||
#include "api/audio_codecs/audio_format.h"
|
#include "api/audio_codecs/audio_format.h"
|
||||||
@ -233,11 +235,12 @@ class AcmReceiver {
|
|||||||
mutable Mutex mutex_;
|
mutable Mutex mutex_;
|
||||||
absl::optional<DecoderInfo> last_decoder_ RTC_GUARDED_BY(mutex_);
|
absl::optional<DecoderInfo> last_decoder_ RTC_GUARDED_BY(mutex_);
|
||||||
ACMResampler resampler_ RTC_GUARDED_BY(mutex_);
|
ACMResampler resampler_ RTC_GUARDED_BY(mutex_);
|
||||||
std::unique_ptr<int16_t[]> last_audio_buffer_ RTC_GUARDED_BY(mutex_);
|
|
||||||
CallStatistics call_stats_ RTC_GUARDED_BY(mutex_);
|
CallStatistics call_stats_ RTC_GUARDED_BY(mutex_);
|
||||||
const std::unique_ptr<NetEq> neteq_; // NetEq is thread-safe; no lock needed.
|
const std::unique_ptr<NetEq> neteq_; // NetEq is thread-safe; no lock needed.
|
||||||
Clock& clock_;
|
Clock& clock_;
|
||||||
bool resampled_last_output_frame_ RTC_GUARDED_BY(mutex_);
|
bool resampled_last_output_frame_ RTC_GUARDED_BY(mutex_);
|
||||||
|
std::array<int16_t, AudioFrame::kMaxDataSizeSamples> last_audio_buffer_
|
||||||
|
RTC_GUARDED_BY(mutex_);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace acm2
|
} // namespace acm2
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user