xref: /aosp_15_r20/external/webrtc/audio/utility/audio_frame_operations.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "audio/utility/audio_frame_operations.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <string.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
16*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
17*d9f75844SAndroid Build Coastguard Worker #include <utility>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "common_audio/include/audio_util.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
24*d9f75844SAndroid Build Coastguard Worker namespace {
25*d9f75844SAndroid Build Coastguard Worker 
26*d9f75844SAndroid Build Coastguard Worker // 2.7ms @ 48kHz, 4ms @ 32kHz, 8ms @ 16kHz.
27*d9f75844SAndroid Build Coastguard Worker const size_t kMuteFadeFrames = 128;
28*d9f75844SAndroid Build Coastguard Worker const float kMuteFadeInc = 1.0f / kMuteFadeFrames;
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker }  // namespace
31*d9f75844SAndroid Build Coastguard Worker 
Add(const AudioFrame & frame_to_add,AudioFrame * result_frame)32*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::Add(const AudioFrame& frame_to_add,
33*d9f75844SAndroid Build Coastguard Worker                                AudioFrame* result_frame) {
34*d9f75844SAndroid Build Coastguard Worker   // Sanity check.
35*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(result_frame);
36*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(result_frame->num_channels_, 0);
37*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_);
38*d9f75844SAndroid Build Coastguard Worker 
39*d9f75844SAndroid Build Coastguard Worker   bool no_previous_data = result_frame->muted();
40*d9f75844SAndroid Build Coastguard Worker   if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) {
41*d9f75844SAndroid Build Coastguard Worker     // Special case we have no data to start with.
42*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0);
43*d9f75844SAndroid Build Coastguard Worker     result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_;
44*d9f75844SAndroid Build Coastguard Worker     no_previous_data = true;
45*d9f75844SAndroid Build Coastguard Worker   }
46*d9f75844SAndroid Build Coastguard Worker 
47*d9f75844SAndroid Build Coastguard Worker   if (result_frame->vad_activity_ == AudioFrame::kVadActive ||
48*d9f75844SAndroid Build Coastguard Worker       frame_to_add.vad_activity_ == AudioFrame::kVadActive) {
49*d9f75844SAndroid Build Coastguard Worker     result_frame->vad_activity_ = AudioFrame::kVadActive;
50*d9f75844SAndroid Build Coastguard Worker   } else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown ||
51*d9f75844SAndroid Build Coastguard Worker              frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) {
52*d9f75844SAndroid Build Coastguard Worker     result_frame->vad_activity_ = AudioFrame::kVadUnknown;
53*d9f75844SAndroid Build Coastguard Worker   }
54*d9f75844SAndroid Build Coastguard Worker 
55*d9f75844SAndroid Build Coastguard Worker   if (result_frame->speech_type_ != frame_to_add.speech_type_)
56*d9f75844SAndroid Build Coastguard Worker     result_frame->speech_type_ = AudioFrame::kUndefined;
57*d9f75844SAndroid Build Coastguard Worker 
58*d9f75844SAndroid Build Coastguard Worker   if (!frame_to_add.muted()) {
59*d9f75844SAndroid Build Coastguard Worker     const int16_t* in_data = frame_to_add.data();
60*d9f75844SAndroid Build Coastguard Worker     int16_t* out_data = result_frame->mutable_data();
61*d9f75844SAndroid Build Coastguard Worker     size_t length =
62*d9f75844SAndroid Build Coastguard Worker         frame_to_add.samples_per_channel_ * frame_to_add.num_channels_;
63*d9f75844SAndroid Build Coastguard Worker     if (no_previous_data) {
64*d9f75844SAndroid Build Coastguard Worker       std::copy(in_data, in_data + length, out_data);
65*d9f75844SAndroid Build Coastguard Worker     } else {
66*d9f75844SAndroid Build Coastguard Worker       for (size_t i = 0; i < length; i++) {
67*d9f75844SAndroid Build Coastguard Worker         const int32_t wrap_guard = static_cast<int32_t>(out_data[i]) +
68*d9f75844SAndroid Build Coastguard Worker                                    static_cast<int32_t>(in_data[i]);
69*d9f75844SAndroid Build Coastguard Worker         out_data[i] = rtc::saturated_cast<int16_t>(wrap_guard);
70*d9f75844SAndroid Build Coastguard Worker       }
71*d9f75844SAndroid Build Coastguard Worker     }
72*d9f75844SAndroid Build Coastguard Worker   }
73*d9f75844SAndroid Build Coastguard Worker }
74*d9f75844SAndroid Build Coastguard Worker 
MonoToStereo(AudioFrame * frame)75*d9f75844SAndroid Build Coastguard Worker int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
76*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 1) {
77*d9f75844SAndroid Build Coastguard Worker     return -1;
78*d9f75844SAndroid Build Coastguard Worker   }
79*d9f75844SAndroid Build Coastguard Worker   UpmixChannels(2, frame);
80*d9f75844SAndroid Build Coastguard Worker   return 0;
81*d9f75844SAndroid Build Coastguard Worker }
82*d9f75844SAndroid Build Coastguard Worker 
StereoToMono(AudioFrame * frame)83*d9f75844SAndroid Build Coastguard Worker int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
84*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 2) {
85*d9f75844SAndroid Build Coastguard Worker     return -1;
86*d9f75844SAndroid Build Coastguard Worker   }
87*d9f75844SAndroid Build Coastguard Worker   DownmixChannels(1, frame);
88*d9f75844SAndroid Build Coastguard Worker   return frame->num_channels_ == 1 ? 0 : -1;
89*d9f75844SAndroid Build Coastguard Worker }
90*d9f75844SAndroid Build Coastguard Worker 
QuadToStereo(const int16_t * src_audio,size_t samples_per_channel,int16_t * dst_audio)91*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
92*d9f75844SAndroid Build Coastguard Worker                                         size_t samples_per_channel,
93*d9f75844SAndroid Build Coastguard Worker                                         int16_t* dst_audio) {
94*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < samples_per_channel; i++) {
95*d9f75844SAndroid Build Coastguard Worker     dst_audio[i * 2] =
96*d9f75844SAndroid Build Coastguard Worker         (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
97*d9f75844SAndroid Build Coastguard Worker     dst_audio[i * 2 + 1] =
98*d9f75844SAndroid Build Coastguard Worker         (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
99*d9f75844SAndroid Build Coastguard Worker         1;
100*d9f75844SAndroid Build Coastguard Worker   }
101*d9f75844SAndroid Build Coastguard Worker }
102*d9f75844SAndroid Build Coastguard Worker 
QuadToStereo(AudioFrame * frame)103*d9f75844SAndroid Build Coastguard Worker int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
104*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 4) {
105*d9f75844SAndroid Build Coastguard Worker     return -1;
106*d9f75844SAndroid Build Coastguard Worker   }
107*d9f75844SAndroid Build Coastguard Worker 
108*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
109*d9f75844SAndroid Build Coastguard Worker                 AudioFrame::kMaxDataSizeSamples);
110*d9f75844SAndroid Build Coastguard Worker 
111*d9f75844SAndroid Build Coastguard Worker   if (!frame->muted()) {
112*d9f75844SAndroid Build Coastguard Worker     QuadToStereo(frame->data(), frame->samples_per_channel_,
113*d9f75844SAndroid Build Coastguard Worker                  frame->mutable_data());
114*d9f75844SAndroid Build Coastguard Worker   }
115*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = 2;
116*d9f75844SAndroid Build Coastguard Worker 
117*d9f75844SAndroid Build Coastguard Worker   return 0;
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker 
DownmixChannels(const int16_t * src_audio,size_t src_channels,size_t samples_per_channel,size_t dst_channels,int16_t * dst_audio)120*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
121*d9f75844SAndroid Build Coastguard Worker                                            size_t src_channels,
122*d9f75844SAndroid Build Coastguard Worker                                            size_t samples_per_channel,
123*d9f75844SAndroid Build Coastguard Worker                                            size_t dst_channels,
124*d9f75844SAndroid Build Coastguard Worker                                            int16_t* dst_audio) {
125*d9f75844SAndroid Build Coastguard Worker   if (src_channels > 1 && dst_channels == 1) {
126*d9f75844SAndroid Build Coastguard Worker     DownmixInterleavedToMono(src_audio, samples_per_channel, src_channels,
127*d9f75844SAndroid Build Coastguard Worker                              dst_audio);
128*d9f75844SAndroid Build Coastguard Worker     return;
129*d9f75844SAndroid Build Coastguard Worker   } else if (src_channels == 4 && dst_channels == 2) {
130*d9f75844SAndroid Build Coastguard Worker     QuadToStereo(src_audio, samples_per_channel, dst_audio);
131*d9f75844SAndroid Build Coastguard Worker     return;
132*d9f75844SAndroid Build Coastguard Worker   }
133*d9f75844SAndroid Build Coastguard Worker 
134*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_NOTREACHED() << "src_channels: " << src_channels
135*d9f75844SAndroid Build Coastguard Worker                           << ", dst_channels: " << dst_channels;
136*d9f75844SAndroid Build Coastguard Worker }
137*d9f75844SAndroid Build Coastguard Worker 
DownmixChannels(size_t dst_channels,AudioFrame * frame)138*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::DownmixChannels(size_t dst_channels,
139*d9f75844SAndroid Build Coastguard Worker                                            AudioFrame* frame) {
140*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LE(frame->samples_per_channel_ * frame->num_channels_,
141*d9f75844SAndroid Build Coastguard Worker                 AudioFrame::kMaxDataSizeSamples);
142*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ > 1 && dst_channels == 1) {
143*d9f75844SAndroid Build Coastguard Worker     if (!frame->muted()) {
144*d9f75844SAndroid Build Coastguard Worker       DownmixInterleavedToMono(frame->data(), frame->samples_per_channel_,
145*d9f75844SAndroid Build Coastguard Worker                                frame->num_channels_, frame->mutable_data());
146*d9f75844SAndroid Build Coastguard Worker     }
147*d9f75844SAndroid Build Coastguard Worker     frame->num_channels_ = 1;
148*d9f75844SAndroid Build Coastguard Worker   } else if (frame->num_channels_ == 4 && dst_channels == 2) {
149*d9f75844SAndroid Build Coastguard Worker     int err = QuadToStereo(frame);
150*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(err, 0);
151*d9f75844SAndroid Build Coastguard Worker   } else {
152*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_NOTREACHED() << "src_channels: " << frame->num_channels_
153*d9f75844SAndroid Build Coastguard Worker                             << ", dst_channels: " << dst_channels;
154*d9f75844SAndroid Build Coastguard Worker   }
155*d9f75844SAndroid Build Coastguard Worker }
156*d9f75844SAndroid Build Coastguard Worker 
UpmixChannels(size_t target_number_of_channels,AudioFrame * frame)157*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::UpmixChannels(size_t target_number_of_channels,
158*d9f75844SAndroid Build Coastguard Worker                                          AudioFrame* frame) {
159*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(frame->num_channels_, 1);
160*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LE(frame->samples_per_channel_ * target_number_of_channels,
161*d9f75844SAndroid Build Coastguard Worker                 AudioFrame::kMaxDataSizeSamples);
162*d9f75844SAndroid Build Coastguard Worker 
163*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 1 ||
164*d9f75844SAndroid Build Coastguard Worker       frame->samples_per_channel_ * target_number_of_channels >
165*d9f75844SAndroid Build Coastguard Worker           AudioFrame::kMaxDataSizeSamples) {
166*d9f75844SAndroid Build Coastguard Worker     return;
167*d9f75844SAndroid Build Coastguard Worker   }
168*d9f75844SAndroid Build Coastguard Worker 
169*d9f75844SAndroid Build Coastguard Worker   if (!frame->muted()) {
170*d9f75844SAndroid Build Coastguard Worker     // Up-mixing done in place. Going backwards through the frame ensure nothing
171*d9f75844SAndroid Build Coastguard Worker     // is irrevocably overwritten.
172*d9f75844SAndroid Build Coastguard Worker     int16_t* frame_data = frame->mutable_data();
173*d9f75844SAndroid Build Coastguard Worker     for (int i = frame->samples_per_channel_ - 1; i >= 0; i--) {
174*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < target_number_of_channels; ++j) {
175*d9f75844SAndroid Build Coastguard Worker         frame_data[target_number_of_channels * i + j] = frame_data[i];
176*d9f75844SAndroid Build Coastguard Worker       }
177*d9f75844SAndroid Build Coastguard Worker     }
178*d9f75844SAndroid Build Coastguard Worker   }
179*d9f75844SAndroid Build Coastguard Worker   frame->num_channels_ = target_number_of_channels;
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker 
SwapStereoChannels(AudioFrame * frame)182*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
183*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
184*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 2 || frame->muted()) {
185*d9f75844SAndroid Build Coastguard Worker     return;
186*d9f75844SAndroid Build Coastguard Worker   }
187*d9f75844SAndroid Build Coastguard Worker 
188*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
189*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
190*d9f75844SAndroid Build Coastguard Worker     std::swap(frame_data[i], frame_data[i + 1]);
191*d9f75844SAndroid Build Coastguard Worker   }
192*d9f75844SAndroid Build Coastguard Worker }
193*d9f75844SAndroid Build Coastguard Worker 
Mute(AudioFrame * frame,bool previous_frame_muted,bool current_frame_muted)194*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::Mute(AudioFrame* frame,
195*d9f75844SAndroid Build Coastguard Worker                                 bool previous_frame_muted,
196*d9f75844SAndroid Build Coastguard Worker                                 bool current_frame_muted) {
197*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
198*d9f75844SAndroid Build Coastguard Worker   if (!previous_frame_muted && !current_frame_muted) {
199*d9f75844SAndroid Build Coastguard Worker     // Not muted, don't touch.
200*d9f75844SAndroid Build Coastguard Worker   } else if (previous_frame_muted && current_frame_muted) {
201*d9f75844SAndroid Build Coastguard Worker     // Frame fully muted.
202*d9f75844SAndroid Build Coastguard Worker     size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
203*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
204*d9f75844SAndroid Build Coastguard Worker     frame->Mute();
205*d9f75844SAndroid Build Coastguard Worker   } else {
206*d9f75844SAndroid Build Coastguard Worker     // Fade is a no-op on a muted frame.
207*d9f75844SAndroid Build Coastguard Worker     if (frame->muted()) {
208*d9f75844SAndroid Build Coastguard Worker       return;
209*d9f75844SAndroid Build Coastguard Worker     }
210*d9f75844SAndroid Build Coastguard Worker 
211*d9f75844SAndroid Build Coastguard Worker     // Limit number of samples to fade, if frame isn't long enough.
212*d9f75844SAndroid Build Coastguard Worker     size_t count = kMuteFadeFrames;
213*d9f75844SAndroid Build Coastguard Worker     float inc = kMuteFadeInc;
214*d9f75844SAndroid Build Coastguard Worker     if (frame->samples_per_channel_ < kMuteFadeFrames) {
215*d9f75844SAndroid Build Coastguard Worker       count = frame->samples_per_channel_;
216*d9f75844SAndroid Build Coastguard Worker       if (count > 0) {
217*d9f75844SAndroid Build Coastguard Worker         inc = 1.0f / count;
218*d9f75844SAndroid Build Coastguard Worker       }
219*d9f75844SAndroid Build Coastguard Worker     }
220*d9f75844SAndroid Build Coastguard Worker 
221*d9f75844SAndroid Build Coastguard Worker     size_t start = 0;
222*d9f75844SAndroid Build Coastguard Worker     size_t end = count;
223*d9f75844SAndroid Build Coastguard Worker     float start_g = 0.0f;
224*d9f75844SAndroid Build Coastguard Worker     if (current_frame_muted) {
225*d9f75844SAndroid Build Coastguard Worker       // Fade out the last `count` samples of frame.
226*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK(!previous_frame_muted);
227*d9f75844SAndroid Build Coastguard Worker       start = frame->samples_per_channel_ - count;
228*d9f75844SAndroid Build Coastguard Worker       end = frame->samples_per_channel_;
229*d9f75844SAndroid Build Coastguard Worker       start_g = 1.0f;
230*d9f75844SAndroid Build Coastguard Worker       inc = -inc;
231*d9f75844SAndroid Build Coastguard Worker     } else {
232*d9f75844SAndroid Build Coastguard Worker       // Fade in the first `count` samples of frame.
233*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK(previous_frame_muted);
234*d9f75844SAndroid Build Coastguard Worker     }
235*d9f75844SAndroid Build Coastguard Worker 
236*d9f75844SAndroid Build Coastguard Worker     // Perform fade.
237*d9f75844SAndroid Build Coastguard Worker     int16_t* frame_data = frame->mutable_data();
238*d9f75844SAndroid Build Coastguard Worker     size_t channels = frame->num_channels_;
239*d9f75844SAndroid Build Coastguard Worker     for (size_t j = 0; j < channels; ++j) {
240*d9f75844SAndroid Build Coastguard Worker       float g = start_g;
241*d9f75844SAndroid Build Coastguard Worker       for (size_t i = start * channels; i < end * channels; i += channels) {
242*d9f75844SAndroid Build Coastguard Worker         g += inc;
243*d9f75844SAndroid Build Coastguard Worker         frame_data[i + j] *= g;
244*d9f75844SAndroid Build Coastguard Worker       }
245*d9f75844SAndroid Build Coastguard Worker     }
246*d9f75844SAndroid Build Coastguard Worker   }
247*d9f75844SAndroid Build Coastguard Worker }
248*d9f75844SAndroid Build Coastguard Worker 
Mute(AudioFrame * frame)249*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::Mute(AudioFrame* frame) {
250*d9f75844SAndroid Build Coastguard Worker   Mute(frame, true, true);
251*d9f75844SAndroid Build Coastguard Worker }
252*d9f75844SAndroid Build Coastguard Worker 
ApplyHalfGain(AudioFrame * frame)253*d9f75844SAndroid Build Coastguard Worker void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
254*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(frame);
255*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(frame->num_channels_, 0);
256*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ < 1 || frame->muted()) {
257*d9f75844SAndroid Build Coastguard Worker     return;
258*d9f75844SAndroid Build Coastguard Worker   }
259*d9f75844SAndroid Build Coastguard Worker 
260*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
261*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
262*d9f75844SAndroid Build Coastguard Worker        i++) {
263*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = frame_data[i] >> 1;
264*d9f75844SAndroid Build Coastguard Worker   }
265*d9f75844SAndroid Build Coastguard Worker }
266*d9f75844SAndroid Build Coastguard Worker 
Scale(float left,float right,AudioFrame * frame)267*d9f75844SAndroid Build Coastguard Worker int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
268*d9f75844SAndroid Build Coastguard Worker   if (frame->num_channels_ != 2) {
269*d9f75844SAndroid Build Coastguard Worker     return -1;
270*d9f75844SAndroid Build Coastguard Worker   } else if (frame->muted()) {
271*d9f75844SAndroid Build Coastguard Worker     return 0;
272*d9f75844SAndroid Build Coastguard Worker   }
273*d9f75844SAndroid Build Coastguard Worker 
274*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
275*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel_; i++) {
276*d9f75844SAndroid Build Coastguard Worker     frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
277*d9f75844SAndroid Build Coastguard Worker     frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
278*d9f75844SAndroid Build Coastguard Worker   }
279*d9f75844SAndroid Build Coastguard Worker   return 0;
280*d9f75844SAndroid Build Coastguard Worker }
281*d9f75844SAndroid Build Coastguard Worker 
ScaleWithSat(float scale,AudioFrame * frame)282*d9f75844SAndroid Build Coastguard Worker int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
283*d9f75844SAndroid Build Coastguard Worker   if (frame->muted()) {
284*d9f75844SAndroid Build Coastguard Worker     return 0;
285*d9f75844SAndroid Build Coastguard Worker   }
286*d9f75844SAndroid Build Coastguard Worker 
287*d9f75844SAndroid Build Coastguard Worker   int16_t* frame_data = frame->mutable_data();
288*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
289*d9f75844SAndroid Build Coastguard Worker        i++) {
290*d9f75844SAndroid Build Coastguard Worker     frame_data[i] = rtc::saturated_cast<int16_t>(scale * frame_data[i]);
291*d9f75844SAndroid Build Coastguard Worker   }
292*d9f75844SAndroid Build Coastguard Worker   return 0;
293*d9f75844SAndroid Build Coastguard Worker }
294*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
295