blob: 3dc510dd3c1e0784881898ba12de732db7968416 [file] [log] [blame]
Niels Möllerd377f042018-02-13 15:03:43 +01001/*
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 "rtc_base/checks.h"
14#include "rtc_base/numerics/safe_conversions.h"
15#include "rtc_base/timeutils.h"
16
17namespace webrtc {
18
19AudioFrame::AudioFrame() {
20 // Visual Studio doesn't like this in the class definition.
21 static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
22}
23
24void AudioFrame::Reset() {
25 ResetWithoutMuting();
26 muted_ = true;
27}
28
29void AudioFrame::ResetWithoutMuting() {
30 // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize
31 // to an invalid value, or add a new member to indicate invalidity.
32 timestamp_ = 0;
33 elapsed_time_ms_ = -1;
34 ntp_time_ms_ = -1;
35 samples_per_channel_ = 0;
36 sample_rate_hz_ = 0;
37 num_channels_ = 0;
38 speech_type_ = kUndefined;
39 vad_activity_ = kVadUnknown;
40 profile_timestamp_ms_ = 0;
41}
42
43void AudioFrame::UpdateFrame(uint32_t timestamp,
44 const int16_t* data,
45 size_t samples_per_channel,
46 int sample_rate_hz,
47 SpeechType speech_type,
48 VADActivity vad_activity,
49 size_t num_channels) {
50 timestamp_ = timestamp;
51 samples_per_channel_ = samples_per_channel;
52 sample_rate_hz_ = sample_rate_hz;
53 speech_type_ = speech_type;
54 vad_activity_ = vad_activity;
55 num_channels_ = num_channels;
56
57 const size_t length = samples_per_channel * num_channels;
58 RTC_CHECK_LE(length, kMaxDataSizeSamples);
59 if (data != nullptr) {
60 memcpy(data_, data, sizeof(int16_t) * length);
61 muted_ = false;
62 } else {
63 muted_ = true;
64 }
65}
66
67void AudioFrame::CopyFrom(const AudioFrame& src) {
68 if (this == &src) return;
69
70 timestamp_ = src.timestamp_;
71 elapsed_time_ms_ = src.elapsed_time_ms_;
72 ntp_time_ms_ = src.ntp_time_ms_;
73 muted_ = src.muted();
74 samples_per_channel_ = src.samples_per_channel_;
75 sample_rate_hz_ = src.sample_rate_hz_;
76 speech_type_ = src.speech_type_;
77 vad_activity_ = src.vad_activity_;
78 num_channels_ = src.num_channels_;
79
80 const size_t length = samples_per_channel_ * num_channels_;
81 RTC_CHECK_LE(length, kMaxDataSizeSamples);
82 if (!src.muted()) {
83 memcpy(data_, src.data(), sizeof(int16_t) * length);
84 muted_ = false;
85 }
86}
87
88void AudioFrame::UpdateProfileTimeStamp() {
89 profile_timestamp_ms_ = rtc::TimeMillis();
90}
91
92int64_t AudioFrame::ElapsedProfileTimeMs() const {
93 if (profile_timestamp_ms_ == 0) {
94 // Profiling has not been activated.
95 return -1;
96 }
97 return rtc::TimeSince(profile_timestamp_ms_);
98}
99
100const int16_t* AudioFrame::data() const {
101 return muted_ ? empty_data() : data_;
102}
103
104// TODO(henrik.lundin) Can we skip zeroing the buffer?
105// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647.
106int16_t* AudioFrame::mutable_data() {
107 if (muted_) {
108 memset(data_, 0, kMaxDataSizeBytes);
109 muted_ = false;
110 }
111 return data_;
112}
113
114void AudioFrame::Mute() {
115 muted_ = true;
116}
117
118bool AudioFrame::muted() const { return muted_; }
119
120AudioFrame& AudioFrame::operator>>=(const int rhs) {
121 RTC_CHECK_GT(num_channels_, 0);
122 RTC_CHECK_LT(num_channels_, 3);
123 if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
124 if (muted_) return *this;
125
126 for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
127 data_[i] = static_cast<int16_t>(data_[i] >> rhs);
128 }
129 return *this;
130}
131
132AudioFrame& AudioFrame::operator+=(const AudioFrame& rhs) {
133 // Sanity check
134 RTC_CHECK_GT(num_channels_, 0);
135 RTC_CHECK_LT(num_channels_, 3);
136 if ((num_channels_ > 2) || (num_channels_ < 1)) return *this;
137 if (num_channels_ != rhs.num_channels_) return *this;
138
139 bool noPrevData = muted_;
140 if (samples_per_channel_ != rhs.samples_per_channel_) {
141 if (samples_per_channel_ == 0) {
142 // special case we have no data to start with
143 samples_per_channel_ = rhs.samples_per_channel_;
144 noPrevData = true;
145 } else {
146 return *this;
147 }
148 }
149
150 if ((vad_activity_ == kVadActive) || rhs.vad_activity_ == kVadActive) {
151 vad_activity_ = kVadActive;
152 } else if (vad_activity_ == kVadUnknown || rhs.vad_activity_ == kVadUnknown) {
153 vad_activity_ = kVadUnknown;
154 }
155
156 if (speech_type_ != rhs.speech_type_) speech_type_ = kUndefined;
157
158 if (!rhs.muted()) {
159 muted_ = false;
160 if (noPrevData) {
161 memcpy(data_, rhs.data(),
162 sizeof(int16_t) * rhs.samples_per_channel_ * num_channels_);
163 } else {
164 // IMPROVEMENT this can be done very fast in assembly
165 for (size_t i = 0; i < samples_per_channel_ * num_channels_; i++) {
166 int32_t wrap_guard =
167 static_cast<int32_t>(data_[i]) + static_cast<int32_t>(rhs.data_[i]);
168 data_[i] = rtc::saturated_cast<int16_t>(wrap_guard);
169 }
170 }
171 }
172
173 return *this;
174}
175
176// static
177const int16_t* AudioFrame::empty_data() {
178 static const int16_t kEmptyData[kMaxDataSizeSamples] = {0};
179 static_assert(sizeof(kEmptyData) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
180 return kEmptyData;
181}
182
183} // namespace webrtc