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