audio_frame.cc (8125B)
1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "api/audio/audio_frame.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <optional> 16 17 #include "api/array_view.h" 18 #include "api/audio/audio_view.h" 19 #include "api/audio/channel_layout.h" 20 #include "api/rtp_packet_infos.h" 21 #include "rtc_base/checks.h" 22 23 namespace webrtc { 24 25 AudioFrame::AudioFrame() { 26 // Visual Studio doesn't like this in the class definition. 27 static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes"); 28 } 29 30 AudioFrame::AudioFrame(int sample_rate_hz, 31 size_t num_channels, 32 ChannelLayout layout /*= CHANNEL_LAYOUT_UNSUPPORTED*/) 33 : samples_per_channel_(SampleRateToDefaultChannelSize(sample_rate_hz)), 34 sample_rate_hz_(sample_rate_hz), 35 num_channels_(num_channels), 36 channel_layout_(layout == CHANNEL_LAYOUT_UNSUPPORTED 37 ? GuessChannelLayout(num_channels) 38 : layout) { 39 RTC_DCHECK_LE(num_channels_, kMaxNumberOfAudioChannels); 40 RTC_DCHECK_GT(sample_rate_hz_, 0); 41 RTC_DCHECK_GT(samples_per_channel_, 0u); 42 } 43 44 void AudioFrame::Reset() { 45 ResetWithoutMuting(); 46 muted_ = true; 47 } 48 49 void AudioFrame::ResetWithoutMuting() { 50 // TODO(wu): Zero is a valid value for `timestamp_`. We should initialize 51 // to an invalid value, or add a new member to indicate invalidity. 52 timestamp_ = 0; 53 elapsed_time_ms_ = -1; 54 ntp_time_ms_ = -1; 55 samples_per_channel_ = 0; 56 sample_rate_hz_ = 0; 57 num_channels_ = 0; 58 channel_layout_ = CHANNEL_LAYOUT_NONE; 59 speech_type_ = kUndefined; 60 vad_activity_ = kVadUnknown; 61 packet_infos_ = RtpPacketInfos(); 62 absolute_capture_timestamp_ms_ = std::nullopt; 63 } 64 65 void AudioFrame::UpdateFrame(uint32_t timestamp, 66 const int16_t* data, 67 size_t samples_per_channel, 68 int sample_rate_hz, 69 SpeechType speech_type, 70 VADActivity vad_activity, 71 size_t num_channels) { 72 RTC_CHECK_LE(num_channels, kMaxNumberOfAudioChannels); 73 timestamp_ = timestamp; 74 samples_per_channel_ = samples_per_channel; 75 sample_rate_hz_ = sample_rate_hz; 76 speech_type_ = speech_type; 77 vad_activity_ = vad_activity; 78 num_channels_ = num_channels; 79 channel_layout_ = GuessChannelLayout(num_channels); 80 if (channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED) { 81 RTC_DCHECK_EQ(num_channels, ChannelLayoutToChannelCount(channel_layout_)); 82 } 83 84 const size_t length = samples_per_channel * num_channels; 85 RTC_CHECK_LE(length, data_.size()); 86 if (data != nullptr) { 87 memcpy(data_.data(), data, sizeof(int16_t) * length); 88 muted_ = false; 89 } else { 90 muted_ = true; 91 } 92 } 93 94 void AudioFrame::CopyFrom(const AudioFrame& src) { 95 if (this == &src) 96 return; 97 98 if (muted_ && !src.muted()) { 99 // TODO: bugs.webrtc.org/5647 - Since the default value for `muted_` is 100 // false and `data_` may still be uninitialized (because we don't initialize 101 // data_ as part of construction), we clear the full buffer here before 102 // copying over new values. If we don't, msan might complain in some tests. 103 // Consider locking down construction, avoiding the default constructor and 104 // prefering construction that initializes all state. 105 ClearSamples(data_); 106 } 107 108 timestamp_ = src.timestamp_; 109 elapsed_time_ms_ = src.elapsed_time_ms_; 110 ntp_time_ms_ = src.ntp_time_ms_; 111 packet_infos_ = src.packet_infos_; 112 muted_ = src.muted(); 113 samples_per_channel_ = src.samples_per_channel_; 114 sample_rate_hz_ = src.sample_rate_hz_; 115 speech_type_ = src.speech_type_; 116 vad_activity_ = src.vad_activity_; 117 num_channels_ = src.num_channels_; 118 channel_layout_ = src.channel_layout_; 119 absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms(); 120 121 auto data = src.data_view(); 122 RTC_CHECK_LE(data.size(), data_.size()); 123 if (!muted_ && !data.empty()) { 124 memcpy(&data_[0], &data[0], sizeof(int16_t) * data.size()); 125 } 126 } 127 128 const int16_t* AudioFrame::data() const { 129 return muted_ ? zeroed_data().begin() : data_.data(); 130 } 131 132 InterleavedView<const int16_t> AudioFrame::data_view() const { 133 // If you get a nullptr from `data_view()`, it's likely because the 134 // samples_per_channel_ and/or num_channels_ members haven't been properly 135 // set. Since `data_view()` returns an InterleavedView<> (which internally 136 // uses ArrayView<>), we inherit the behavior in InterleavedView when 137 // the view size is 0 that ArrayView<>::data() returns nullptr. So, even when 138 // an AudioFrame is muted and we want to return `zeroed_data()`, if 139 // samples_per_channel_ or num_channels_ is 0, the view will point to 140 // nullptr. 141 return InterleavedView<const int16_t>(muted_ ? &zeroed_data()[0] : &data_[0], 142 samples_per_channel_, num_channels_); 143 } 144 145 int16_t* AudioFrame::mutable_data() { 146 // TODO: bugs.webrtc.org/5647 - Can we skip zeroing the buffer? 147 // Consider instead if we should rather zero the buffer when `muted_` is set 148 // to `true`. 149 if (muted_) { 150 ClearSamples(data_); 151 muted_ = false; 152 } 153 return &data_[0]; 154 } 155 156 InterleavedView<int16_t> AudioFrame::mutable_data(size_t samples_per_channel, 157 size_t num_channels) { 158 const size_t total_samples = samples_per_channel * num_channels; 159 RTC_CHECK_LE(total_samples, data_.size()); 160 RTC_CHECK_LE(num_channels, kMaxNumberOfAudioChannels); 161 // Sanity check for valid argument values during development. 162 // If `samples_per_channel` is < `num_channels` but larger than 0, 163 // then chances are the order of arguments is incorrect. 164 RTC_DCHECK((samples_per_channel == 0 && num_channels == 0) || 165 num_channels <= samples_per_channel) 166 << "samples_per_channel=" << samples_per_channel 167 << "num_channels=" << num_channels; 168 169 // TODO: bugs.webrtc.org/5647 - Can we skip zeroing the buffer? 170 // Consider instead if we should rather zero the whole buffer when `muted_` is 171 // set to `true`. 172 if (muted_) { 173 ClearSamples(data_, total_samples); 174 muted_ = false; 175 } 176 samples_per_channel_ = samples_per_channel; 177 num_channels_ = num_channels; 178 return InterleavedView<int16_t>(&data_[0], samples_per_channel, num_channels); 179 } 180 181 void AudioFrame::Mute() { 182 muted_ = true; 183 } 184 185 bool AudioFrame::muted() const { 186 return muted_; 187 } 188 189 void AudioFrame::SetLayoutAndNumChannels(ChannelLayout layout, 190 size_t num_channels) { 191 channel_layout_ = layout; 192 num_channels_ = num_channels; 193 #if RTC_DCHECK_IS_ON 194 // Do a sanity check that the layout and num_channels match. 195 // If this lookup yield 0u, then the layout is likely CHANNEL_LAYOUT_DISCRETE. 196 auto expected_num_channels = ChannelLayoutToChannelCount(layout); 197 if (expected_num_channels) { // If expected_num_channels is 0 198 RTC_DCHECK_EQ(expected_num_channels, num_channels_); 199 } 200 #endif 201 RTC_CHECK_LE(samples_per_channel_ * num_channels_, data_.size()); 202 } 203 204 void AudioFrame::SetSampleRateAndChannelSize(int sample_rate) { 205 sample_rate_hz_ = sample_rate; 206 // We could call `AudioProcessing::GetFrameSize()` here, but that requires 207 // adding a dependency on the ":audio_processing" build target, which can 208 // complicate the dependency tree. Some refactoring is probably in order to 209 // get some consistency around this since there are many places across the 210 // code that assume this default buffer size. 211 samples_per_channel_ = SampleRateToDefaultChannelSize(sample_rate_hz_); 212 } 213 214 // static 215 ArrayView<const int16_t> AudioFrame::zeroed_data() { 216 static int16_t* null_data = new int16_t[kMaxDataSizeSamples](); 217 return ArrayView<const int16_t>(null_data, kMaxDataSizeSamples); 218 } 219 220 } // namespace webrtc