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