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 <string.h>
14 #include <algorithm>
15 #include <utility>
16 
17 #include "rtc_base/checks.h"
18 #include "rtc_base/time_utils.h"
19 
20 namespace webrtc {
21 
AudioFrame()22 AudioFrame::AudioFrame() {
23   // Visual Studio doesn't like this in the class definition.
24   static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
25 }
26 
swap(AudioFrame & a,AudioFrame & b)27 void swap(AudioFrame& a, AudioFrame& b) {
28   using std::swap;
29   swap(a.timestamp_, b.timestamp_);
30   swap(a.elapsed_time_ms_, b.elapsed_time_ms_);
31   swap(a.ntp_time_ms_, b.ntp_time_ms_);
32   swap(a.samples_per_channel_, b.samples_per_channel_);
33   swap(a.sample_rate_hz_, b.sample_rate_hz_);
34   swap(a.num_channels_, b.num_channels_);
35   swap(a.channel_layout_, b.channel_layout_);
36   swap(a.speech_type_, b.speech_type_);
37   swap(a.vad_activity_, b.vad_activity_);
38   swap(a.profile_timestamp_ms_, b.profile_timestamp_ms_);
39   swap(a.packet_infos_, b.packet_infos_);
40   const size_t length_a = a.samples_per_channel_ * a.num_channels_;
41   const size_t length_b = b.samples_per_channel_ * b.num_channels_;
42   RTC_DCHECK_LE(length_a, AudioFrame::kMaxDataSizeSamples);
43   RTC_DCHECK_LE(length_b, AudioFrame::kMaxDataSizeSamples);
44   std::swap_ranges(a.data_, a.data_ + std::max(length_a, length_b), b.data_);
45   swap(a.muted_, b.muted_);
46   swap(a.absolute_capture_timestamp_ms_, b.absolute_capture_timestamp_ms_);
47 }
48 
Reset()49 void AudioFrame::Reset() {
50   ResetWithoutMuting();
51   muted_ = true;
52 }
53 
ResetWithoutMuting()54 void AudioFrame::ResetWithoutMuting() {
55   // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize
56   // to an invalid value, or add a new member to indicate invalidity.
57   timestamp_ = 0;
58   elapsed_time_ms_ = -1;
59   ntp_time_ms_ = -1;
60   samples_per_channel_ = 0;
61   sample_rate_hz_ = 0;
62   num_channels_ = 0;
63   channel_layout_ = CHANNEL_LAYOUT_NONE;
64   speech_type_ = kUndefined;
65   vad_activity_ = kVadUnknown;
66   profile_timestamp_ms_ = 0;
67   packet_infos_ = RtpPacketInfos();
68   absolute_capture_timestamp_ms_ = absl::nullopt;
69 }
70 
UpdateFrame(uint32_t timestamp,const int16_t * data,size_t samples_per_channel,int sample_rate_hz,SpeechType speech_type,VADActivity vad_activity,size_t num_channels)71 void AudioFrame::UpdateFrame(uint32_t timestamp,
72                              const int16_t* data,
73                              size_t samples_per_channel,
74                              int sample_rate_hz,
75                              SpeechType speech_type,
76                              VADActivity vad_activity,
77                              size_t num_channels) {
78   timestamp_ = timestamp;
79   samples_per_channel_ = samples_per_channel;
80   sample_rate_hz_ = sample_rate_hz;
81   speech_type_ = speech_type;
82   vad_activity_ = vad_activity;
83   num_channels_ = num_channels;
84   channel_layout_ = GuessChannelLayout(num_channels);
85   if (channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED) {
86     RTC_DCHECK_EQ(num_channels, ChannelLayoutToChannelCount(channel_layout_));
87   }
88 
89   const size_t length = samples_per_channel * num_channels;
90   RTC_CHECK_LE(length, kMaxDataSizeSamples);
91   if (data != nullptr) {
92     memcpy(data_, data, sizeof(int16_t) * length);
93     muted_ = false;
94   } else {
95     muted_ = true;
96   }
97 }
98 
CopyFrom(const AudioFrame & src)99 void AudioFrame::CopyFrom(const AudioFrame& src) {
100   if (this == &src)
101     return;
102 
103   timestamp_ = src.timestamp_;
104   elapsed_time_ms_ = src.elapsed_time_ms_;
105   ntp_time_ms_ = src.ntp_time_ms_;
106   packet_infos_ = src.packet_infos_;
107   muted_ = src.muted();
108   samples_per_channel_ = src.samples_per_channel_;
109   sample_rate_hz_ = src.sample_rate_hz_;
110   speech_type_ = src.speech_type_;
111   vad_activity_ = src.vad_activity_;
112   num_channels_ = src.num_channels_;
113   channel_layout_ = src.channel_layout_;
114   absolute_capture_timestamp_ms_ = src.absolute_capture_timestamp_ms();
115 
116   const size_t length = samples_per_channel_ * num_channels_;
117   RTC_CHECK_LE(length, kMaxDataSizeSamples);
118   if (!src.muted()) {
119     memcpy(data_, src.data(), sizeof(int16_t) * length);
120     muted_ = false;
121   }
122 }
123 
UpdateProfileTimeStamp()124 void AudioFrame::UpdateProfileTimeStamp() {
125   profile_timestamp_ms_ = rtc::TimeMillis();
126 }
127 
ElapsedProfileTimeMs() const128 int64_t AudioFrame::ElapsedProfileTimeMs() const {
129   if (profile_timestamp_ms_ == 0) {
130     // Profiling has not been activated.
131     return -1;
132   }
133   return rtc::TimeSince(profile_timestamp_ms_);
134 }
135 
data() const136 const int16_t* AudioFrame::data() const {
137   return muted_ ? empty_data() : data_;
138 }
139 
140 // TODO(henrik.lundin) Can we skip zeroing the buffer?
141 // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647.
mutable_data()142 int16_t* AudioFrame::mutable_data() {
143   if (muted_) {
144     memset(data_, 0, kMaxDataSizeBytes);
145     muted_ = false;
146   }
147   return data_;
148 }
149 
Mute()150 void AudioFrame::Mute() {
151   muted_ = true;
152 }
153 
muted() const154 bool AudioFrame::muted() const {
155   return muted_;
156 }
157 
158 // static
empty_data()159 const int16_t* AudioFrame::empty_data() {
160   static int16_t* null_data = new int16_t[kMaxDataSizeSamples]();
161   return &null_data[0];
162 }
163 
164 }  // namespace webrtc
165