xref: /aosp_15_r20/external/webrtc/modules/audio_coding/test/PCMFile.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 "modules/audio_coding/test/PCMFile.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <ctype.h>
14*d9f75844SAndroid Build Coastguard Worker #include <stdio.h>
15*d9f75844SAndroid Build Coastguard Worker #include <string.h>
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
19*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker #define MAX_FILE_NAME_LENGTH_BYTE 500
24*d9f75844SAndroid Build Coastguard Worker 
PCMFile()25*d9f75844SAndroid Build Coastguard Worker PCMFile::PCMFile()
26*d9f75844SAndroid Build Coastguard Worker     : pcm_file_(NULL),
27*d9f75844SAndroid Build Coastguard Worker       samples_10ms_(160),
28*d9f75844SAndroid Build Coastguard Worker       frequency_(16000),
29*d9f75844SAndroid Build Coastguard Worker       end_of_file_(false),
30*d9f75844SAndroid Build Coastguard Worker       auto_rewind_(false),
31*d9f75844SAndroid Build Coastguard Worker       rewinded_(false),
32*d9f75844SAndroid Build Coastguard Worker       read_stereo_(false),
33*d9f75844SAndroid Build Coastguard Worker       save_stereo_(false) {
34*d9f75844SAndroid Build Coastguard Worker   timestamp_ =
35*d9f75844SAndroid Build Coastguard Worker       (((uint32_t)rand() & 0x0000FFFF) << 16) | ((uint32_t)rand() & 0x0000FFFF);
36*d9f75844SAndroid Build Coastguard Worker }
37*d9f75844SAndroid Build Coastguard Worker 
PCMFile(uint32_t timestamp)38*d9f75844SAndroid Build Coastguard Worker PCMFile::PCMFile(uint32_t timestamp)
39*d9f75844SAndroid Build Coastguard Worker     : pcm_file_(NULL),
40*d9f75844SAndroid Build Coastguard Worker       samples_10ms_(160),
41*d9f75844SAndroid Build Coastguard Worker       frequency_(16000),
42*d9f75844SAndroid Build Coastguard Worker       end_of_file_(false),
43*d9f75844SAndroid Build Coastguard Worker       auto_rewind_(false),
44*d9f75844SAndroid Build Coastguard Worker       rewinded_(false),
45*d9f75844SAndroid Build Coastguard Worker       read_stereo_(false),
46*d9f75844SAndroid Build Coastguard Worker       save_stereo_(false) {
47*d9f75844SAndroid Build Coastguard Worker   timestamp_ = timestamp;
48*d9f75844SAndroid Build Coastguard Worker }
49*d9f75844SAndroid Build Coastguard Worker 
~PCMFile()50*d9f75844SAndroid Build Coastguard Worker PCMFile::~PCMFile() {
51*d9f75844SAndroid Build Coastguard Worker   if (pcm_file_) {
52*d9f75844SAndroid Build Coastguard Worker     fclose(pcm_file_);
53*d9f75844SAndroid Build Coastguard Worker   }
54*d9f75844SAndroid Build Coastguard Worker }
55*d9f75844SAndroid Build Coastguard Worker 
ChooseFile(std::string * file_name,int16_t max_len,uint16_t * frequency_hz)56*d9f75844SAndroid Build Coastguard Worker int16_t PCMFile::ChooseFile(std::string* file_name,
57*d9f75844SAndroid Build Coastguard Worker                             int16_t max_len,
58*d9f75844SAndroid Build Coastguard Worker                             uint16_t* frequency_hz) {
59*d9f75844SAndroid Build Coastguard Worker   char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
60*d9f75844SAndroid Build Coastguard Worker 
61*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
62*d9f75844SAndroid Build Coastguard Worker   tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
63*d9f75844SAndroid Build Coastguard Worker   int16_t n = 0;
64*d9f75844SAndroid Build Coastguard Worker 
65*d9f75844SAndroid Build Coastguard Worker   // Removing trailing spaces.
66*d9f75844SAndroid Build Coastguard Worker   while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
67*d9f75844SAndroid Build Coastguard Worker           iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
68*d9f75844SAndroid Build Coastguard Worker          (static_cast<unsigned char>(tmp_name[n]) != 0) &&
69*d9f75844SAndroid Build Coastguard Worker          (n < MAX_FILE_NAME_LENGTH_BYTE)) {
70*d9f75844SAndroid Build Coastguard Worker     n++;
71*d9f75844SAndroid Build Coastguard Worker   }
72*d9f75844SAndroid Build Coastguard Worker   if (n > 0) {
73*d9f75844SAndroid Build Coastguard Worker     memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
74*d9f75844SAndroid Build Coastguard Worker   }
75*d9f75844SAndroid Build Coastguard Worker 
76*d9f75844SAndroid Build Coastguard Worker   // Removing trailing spaces.
77*d9f75844SAndroid Build Coastguard Worker   n = (int16_t)(strlen(tmp_name) - 1);
78*d9f75844SAndroid Build Coastguard Worker   if (n >= 0) {
79*d9f75844SAndroid Build Coastguard Worker     while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
80*d9f75844SAndroid Build Coastguard Worker             iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
81*d9f75844SAndroid Build Coastguard Worker            (n >= 0)) {
82*d9f75844SAndroid Build Coastguard Worker       n--;
83*d9f75844SAndroid Build Coastguard Worker     }
84*d9f75844SAndroid Build Coastguard Worker   }
85*d9f75844SAndroid Build Coastguard Worker   if (n >= 0) {
86*d9f75844SAndroid Build Coastguard Worker     tmp_name[n + 1] = '\0';
87*d9f75844SAndroid Build Coastguard Worker   }
88*d9f75844SAndroid Build Coastguard Worker 
89*d9f75844SAndroid Build Coastguard Worker   int16_t len = (int16_t)strlen(tmp_name);
90*d9f75844SAndroid Build Coastguard Worker   if (len > max_len) {
91*d9f75844SAndroid Build Coastguard Worker     return -1;
92*d9f75844SAndroid Build Coastguard Worker   }
93*d9f75844SAndroid Build Coastguard Worker   if (len > 0) {
94*d9f75844SAndroid Build Coastguard Worker     std::string tmp_string(tmp_name, len + 1);
95*d9f75844SAndroid Build Coastguard Worker     *file_name = tmp_string;
96*d9f75844SAndroid Build Coastguard Worker   }
97*d9f75844SAndroid Build Coastguard Worker   printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
98*d9f75844SAndroid Build Coastguard Worker          *frequency_hz);
99*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
100*d9f75844SAndroid Build Coastguard Worker   uint16_t tmp_frequency = (uint16_t)atoi(tmp_name);
101*d9f75844SAndroid Build Coastguard Worker   if (tmp_frequency > 0) {
102*d9f75844SAndroid Build Coastguard Worker     *frequency_hz = tmp_frequency;
103*d9f75844SAndroid Build Coastguard Worker   }
104*d9f75844SAndroid Build Coastguard Worker   return 0;
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker 
Open(absl::string_view file_name,uint16_t frequency,absl::string_view mode,bool auto_rewind)107*d9f75844SAndroid Build Coastguard Worker void PCMFile::Open(absl::string_view file_name,
108*d9f75844SAndroid Build Coastguard Worker                    uint16_t frequency,
109*d9f75844SAndroid Build Coastguard Worker                    absl::string_view mode,
110*d9f75844SAndroid Build Coastguard Worker                    bool auto_rewind) {
111*d9f75844SAndroid Build Coastguard Worker   if ((pcm_file_ = fopen(std::string(file_name).c_str(),
112*d9f75844SAndroid Build Coastguard Worker                          std::string(mode).c_str())) == NULL) {
113*d9f75844SAndroid Build Coastguard Worker     printf("Cannot open file %s.\n", std::string(file_name).c_str());
114*d9f75844SAndroid Build Coastguard Worker     ADD_FAILURE() << "Unable to read file";
115*d9f75844SAndroid Build Coastguard Worker   }
116*d9f75844SAndroid Build Coastguard Worker   frequency_ = frequency;
117*d9f75844SAndroid Build Coastguard Worker   samples_10ms_ = (uint16_t)(frequency_ / 100);
118*d9f75844SAndroid Build Coastguard Worker   auto_rewind_ = auto_rewind;
119*d9f75844SAndroid Build Coastguard Worker   end_of_file_ = false;
120*d9f75844SAndroid Build Coastguard Worker   rewinded_ = false;
121*d9f75844SAndroid Build Coastguard Worker }
122*d9f75844SAndroid Build Coastguard Worker 
SamplingFrequency() const123*d9f75844SAndroid Build Coastguard Worker int32_t PCMFile::SamplingFrequency() const {
124*d9f75844SAndroid Build Coastguard Worker   return frequency_;
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker 
PayloadLength10Ms() const127*d9f75844SAndroid Build Coastguard Worker uint16_t PCMFile::PayloadLength10Ms() const {
128*d9f75844SAndroid Build Coastguard Worker   return samples_10ms_;
129*d9f75844SAndroid Build Coastguard Worker }
130*d9f75844SAndroid Build Coastguard Worker 
Read10MsData(AudioFrame & audio_frame)131*d9f75844SAndroid Build Coastguard Worker int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
132*d9f75844SAndroid Build Coastguard Worker   uint16_t channels = 1;
133*d9f75844SAndroid Build Coastguard Worker   if (read_stereo_) {
134*d9f75844SAndroid Build Coastguard Worker     channels = 2;
135*d9f75844SAndroid Build Coastguard Worker   }
136*d9f75844SAndroid Build Coastguard Worker 
137*d9f75844SAndroid Build Coastguard Worker   int32_t payload_size =
138*d9f75844SAndroid Build Coastguard Worker       (int32_t)fread(audio_frame.mutable_data(), sizeof(uint16_t),
139*d9f75844SAndroid Build Coastguard Worker                      samples_10ms_ * channels, pcm_file_);
140*d9f75844SAndroid Build Coastguard Worker   if (payload_size < samples_10ms_ * channels) {
141*d9f75844SAndroid Build Coastguard Worker     int16_t* frame_data = audio_frame.mutable_data();
142*d9f75844SAndroid Build Coastguard Worker     for (int k = payload_size; k < samples_10ms_ * channels; k++) {
143*d9f75844SAndroid Build Coastguard Worker       frame_data[k] = 0;
144*d9f75844SAndroid Build Coastguard Worker     }
145*d9f75844SAndroid Build Coastguard Worker     if (auto_rewind_) {
146*d9f75844SAndroid Build Coastguard Worker       rewind(pcm_file_);
147*d9f75844SAndroid Build Coastguard Worker       rewinded_ = true;
148*d9f75844SAndroid Build Coastguard Worker     } else {
149*d9f75844SAndroid Build Coastguard Worker       end_of_file_ = true;
150*d9f75844SAndroid Build Coastguard Worker     }
151*d9f75844SAndroid Build Coastguard Worker   }
152*d9f75844SAndroid Build Coastguard Worker   audio_frame.samples_per_channel_ = samples_10ms_;
153*d9f75844SAndroid Build Coastguard Worker   audio_frame.sample_rate_hz_ = frequency_;
154*d9f75844SAndroid Build Coastguard Worker   audio_frame.num_channels_ = channels;
155*d9f75844SAndroid Build Coastguard Worker   audio_frame.timestamp_ = timestamp_;
156*d9f75844SAndroid Build Coastguard Worker   timestamp_ += samples_10ms_;
157*d9f75844SAndroid Build Coastguard Worker   ++blocks_read_;
158*d9f75844SAndroid Build Coastguard Worker   if (num_10ms_blocks_to_read_ && blocks_read_ >= *num_10ms_blocks_to_read_)
159*d9f75844SAndroid Build Coastguard Worker     end_of_file_ = true;
160*d9f75844SAndroid Build Coastguard Worker   return samples_10ms_;
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker 
Write10MsData(const AudioFrame & audio_frame)163*d9f75844SAndroid Build Coastguard Worker void PCMFile::Write10MsData(const AudioFrame& audio_frame) {
164*d9f75844SAndroid Build Coastguard Worker   if (audio_frame.num_channels_ == 1) {
165*d9f75844SAndroid Build Coastguard Worker     if (!save_stereo_) {
166*d9f75844SAndroid Build Coastguard Worker       if (fwrite(audio_frame.data(), sizeof(uint16_t),
167*d9f75844SAndroid Build Coastguard Worker                  audio_frame.samples_per_channel_, pcm_file_) !=
168*d9f75844SAndroid Build Coastguard Worker           static_cast<size_t>(audio_frame.samples_per_channel_)) {
169*d9f75844SAndroid Build Coastguard Worker         return;
170*d9f75844SAndroid Build Coastguard Worker       }
171*d9f75844SAndroid Build Coastguard Worker     } else {
172*d9f75844SAndroid Build Coastguard Worker       const int16_t* frame_data = audio_frame.data();
173*d9f75844SAndroid Build Coastguard Worker       int16_t* stereo_audio = new int16_t[2 * audio_frame.samples_per_channel_];
174*d9f75844SAndroid Build Coastguard Worker       for (size_t k = 0; k < audio_frame.samples_per_channel_; k++) {
175*d9f75844SAndroid Build Coastguard Worker         stereo_audio[k << 1] = frame_data[k];
176*d9f75844SAndroid Build Coastguard Worker         stereo_audio[(k << 1) + 1] = frame_data[k];
177*d9f75844SAndroid Build Coastguard Worker       }
178*d9f75844SAndroid Build Coastguard Worker       if (fwrite(stereo_audio, sizeof(int16_t),
179*d9f75844SAndroid Build Coastguard Worker                  2 * audio_frame.samples_per_channel_, pcm_file_) !=
180*d9f75844SAndroid Build Coastguard Worker           static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
181*d9f75844SAndroid Build Coastguard Worker         return;
182*d9f75844SAndroid Build Coastguard Worker       }
183*d9f75844SAndroid Build Coastguard Worker       delete[] stereo_audio;
184*d9f75844SAndroid Build Coastguard Worker     }
185*d9f75844SAndroid Build Coastguard Worker   } else {
186*d9f75844SAndroid Build Coastguard Worker     if (fwrite(audio_frame.data(), sizeof(int16_t),
187*d9f75844SAndroid Build Coastguard Worker                audio_frame.num_channels_ * audio_frame.samples_per_channel_,
188*d9f75844SAndroid Build Coastguard Worker                pcm_file_) !=
189*d9f75844SAndroid Build Coastguard Worker         static_cast<size_t>(audio_frame.num_channels_ *
190*d9f75844SAndroid Build Coastguard Worker                             audio_frame.samples_per_channel_)) {
191*d9f75844SAndroid Build Coastguard Worker       return;
192*d9f75844SAndroid Build Coastguard Worker     }
193*d9f75844SAndroid Build Coastguard Worker   }
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker 
Write10MsData(const int16_t * playout_buffer,size_t length_smpls)196*d9f75844SAndroid Build Coastguard Worker void PCMFile::Write10MsData(const int16_t* playout_buffer,
197*d9f75844SAndroid Build Coastguard Worker                             size_t length_smpls) {
198*d9f75844SAndroid Build Coastguard Worker   if (fwrite(playout_buffer, sizeof(uint16_t), length_smpls, pcm_file_) !=
199*d9f75844SAndroid Build Coastguard Worker       length_smpls) {
200*d9f75844SAndroid Build Coastguard Worker     return;
201*d9f75844SAndroid Build Coastguard Worker   }
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker 
Close()204*d9f75844SAndroid Build Coastguard Worker void PCMFile::Close() {
205*d9f75844SAndroid Build Coastguard Worker   fclose(pcm_file_);
206*d9f75844SAndroid Build Coastguard Worker   pcm_file_ = NULL;
207*d9f75844SAndroid Build Coastguard Worker   blocks_read_ = 0;
208*d9f75844SAndroid Build Coastguard Worker }
209*d9f75844SAndroid Build Coastguard Worker 
FastForward(int num_10ms_blocks)210*d9f75844SAndroid Build Coastguard Worker void PCMFile::FastForward(int num_10ms_blocks) {
211*d9f75844SAndroid Build Coastguard Worker   const int channels = read_stereo_ ? 2 : 1;
212*d9f75844SAndroid Build Coastguard Worker   long num_bytes_to_move =
213*d9f75844SAndroid Build Coastguard Worker       num_10ms_blocks * sizeof(int16_t) * samples_10ms_ * channels;
214*d9f75844SAndroid Build Coastguard Worker   int error = fseek(pcm_file_, num_bytes_to_move, SEEK_CUR);
215*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(error, 0);
216*d9f75844SAndroid Build Coastguard Worker }
217*d9f75844SAndroid Build Coastguard Worker 
Rewind()218*d9f75844SAndroid Build Coastguard Worker void PCMFile::Rewind() {
219*d9f75844SAndroid Build Coastguard Worker   rewind(pcm_file_);
220*d9f75844SAndroid Build Coastguard Worker   end_of_file_ = false;
221*d9f75844SAndroid Build Coastguard Worker   blocks_read_ = 0;
222*d9f75844SAndroid Build Coastguard Worker }
223*d9f75844SAndroid Build Coastguard Worker 
Rewinded()224*d9f75844SAndroid Build Coastguard Worker bool PCMFile::Rewinded() {
225*d9f75844SAndroid Build Coastguard Worker   return rewinded_;
226*d9f75844SAndroid Build Coastguard Worker }
227*d9f75844SAndroid Build Coastguard Worker 
SaveStereo(bool is_stereo)228*d9f75844SAndroid Build Coastguard Worker void PCMFile::SaveStereo(bool is_stereo) {
229*d9f75844SAndroid Build Coastguard Worker   save_stereo_ = is_stereo;
230*d9f75844SAndroid Build Coastguard Worker }
231*d9f75844SAndroid Build Coastguard Worker 
ReadStereo(bool is_stereo)232*d9f75844SAndroid Build Coastguard Worker void PCMFile::ReadStereo(bool is_stereo) {
233*d9f75844SAndroid Build Coastguard Worker   read_stereo_ = is_stereo;
234*d9f75844SAndroid Build Coastguard Worker }
235*d9f75844SAndroid Build Coastguard Worker 
SetNum10MsBlocksToRead(int value)236*d9f75844SAndroid Build Coastguard Worker void PCMFile::SetNum10MsBlocksToRead(int value) {
237*d9f75844SAndroid Build Coastguard Worker   num_10ms_blocks_to_read_ = value;
238*d9f75844SAndroid Build Coastguard Worker }
239*d9f75844SAndroid Build Coastguard Worker 
240*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
241