blob: 0b61bbbdf3fc56117bd2f8357b898a0787f4856b [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
leozwang@webrtc.org91b359e2012-02-28 17:26:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000011#include "PCMFile.h"
12
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <cctype>
14#include <stdio.h>
15#include <string.h>
16
kjellander@webrtc.org543c3ea2011-11-23 12:20:35 +000017#include "gtest/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018#include "module_common_types.h"
19
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000020namespace webrtc {
21
niklase@google.com470e71d2011-07-07 08:21:25 +000022#define MAX_FILE_NAME_LENGTH_BYTE 500
23
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000024PCMFile::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) {
pbos@webrtc.org0946a562013-04-09 00:28:06 +000033 timestamp_ = (((uint32_t)rand() & 0x0000FFFF) << 16) |
34 ((uint32_t)rand() & 0x0000FFFF);
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
pbos@webrtc.org0946a562013-04-09 00:28:06 +000037PCMFile::PCMFile(uint32_t timestamp)
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000038 : 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;
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
pbos@webrtc.org0946a562013-04-09 00:28:06 +000049int16_t PCMFile::ChooseFile(std::string* file_name, int16_t max_len) {
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000050 char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
niklase@google.com470e71d2011-07-07 08:21:25 +000051
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000052 EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
53 tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
pbos@webrtc.org0946a562013-04-09 00:28:06 +000054 int16_t n = 0;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000055
56 // Removing leading spaces.
57 while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (tmp_name[n] != 0)
58 && (n < MAX_FILE_NAME_LENGTH_BYTE)) {
59 n++;
60 }
61 if (n > 0) {
62 memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
63 }
64
65 // Removing trailing spaces.
pbos@webrtc.org0946a562013-04-09 00:28:06 +000066 n = (int16_t)(strlen(tmp_name) - 1);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000067 if (n >= 0) {
68 while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (n >= 0)) {
69 n--;
niklase@google.com470e71d2011-07-07 08:21:25 +000070 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000071 }
72 if (n >= 0) {
73 tmp_name[n + 1] = '\0';
74 }
75
pbos@webrtc.org0946a562013-04-09 00:28:06 +000076 int16_t len = (int16_t) strlen(tmp_name);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000077 if (len > max_len) {
78 return -1;
79 }
80 if (len > 0) {
tina.legrand@webrtc.orgba468042012-08-17 10:38:28 +000081 std::string tmp_string(tmp_name, len + 1);
82 *file_name = tmp_string;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000083 }
84 return 0;
85}
86
pbos@webrtc.org0946a562013-04-09 00:28:06 +000087int16_t PCMFile::ChooseFile(std::string* file_name,
88 int16_t max_len,
89 uint16_t* frequency_hz) {
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000090 char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
91
92 EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
93 tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
pbos@webrtc.org0946a562013-04-09 00:28:06 +000094 int16_t n = 0;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +000095
96 // Removing trailing spaces.
97 while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (tmp_name[n] != 0)
98 && (n < MAX_FILE_NAME_LENGTH_BYTE)) {
99 n++;
100 }
101 if (n > 0) {
102 memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
103 }
104
105 // Removing trailing spaces.
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000106 n = (int16_t)(strlen(tmp_name) - 1);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000107 if (n >= 0) {
108 while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (n >= 0)) {
109 n--;
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000111 }
112 if (n >= 0) {
113 tmp_name[n + 1] = '\0';
114 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000116 int16_t len = (int16_t) strlen(tmp_name);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000117 if (len > max_len) {
118 return -1;
119 }
120 if (len > 0) {
tina.legrand@webrtc.orgba468042012-08-17 10:38:28 +0000121 std::string tmp_string(tmp_name, len + 1);
122 *file_name = tmp_string;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000123 }
124 printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
125 *frequency_hz);
126 EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000127 uint16_t tmp_frequency = (uint16_t) atoi(tmp_name);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000128 if (tmp_frequency > 0) {
129 *frequency_hz = tmp_frequency;
130 }
131 return 0;
132}
133
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000134void PCMFile::Open(const std::string& file_name, uint16_t frequency,
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000135 const char* mode, bool auto_rewind) {
tina.legrand@webrtc.orgba468042012-08-17 10:38:28 +0000136 if ((pcm_file_ = fopen(file_name.c_str(), mode)) == NULL) {
137 printf("Cannot open file %s.\n", file_name.c_str());
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000138 ADD_FAILURE() << "Unable to read file";
139 }
140 frequency_ = frequency;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000141 samples_10ms_ = (uint16_t)(frequency_ / 100);
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000142 auto_rewind_ = auto_rewind;
143 end_of_file_ = false;
144 rewinded_ = false;
145}
146
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000147int32_t PCMFile::SamplingFrequency() const {
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000148 return frequency_;
149}
150
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000151uint16_t PCMFile::PayloadLength10Ms() const {
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000152 return samples_10ms_;
153}
154
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000155int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
156 uint16_t channels = 1;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000157 if (read_stereo_) {
158 channels = 2;
159 }
160
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000161 int32_t payload_size = (int32_t) fread(audio_frame.data_,
162 sizeof(uint16_t),
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000163 samples_10ms_ * channels,
164 pcm_file_);
165 if (payload_size < samples_10ms_ * channels) {
166 for (int k = payload_size; k < samples_10ms_ * channels; k++) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000167 audio_frame.data_[k] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000169 if (auto_rewind_) {
170 rewind(pcm_file_);
171 rewinded_ = true;
172 } else {
173 end_of_file_ = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000175 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000176 audio_frame.samples_per_channel_ = samples_10ms_;
177 audio_frame.sample_rate_hz_ = frequency_;
178 audio_frame.num_channels_ = channels;
179 audio_frame.timestamp_ = timestamp_;
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000180 timestamp_ += samples_10ms_;
181 return samples_10ms_;
182}
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000184void PCMFile::Write10MsData(AudioFrame& audio_frame) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000185 if (audio_frame.num_channels_ == 1) {
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000186 if (!save_stereo_) {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000187 if (fwrite(audio_frame.data_, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000188 audio_frame.samples_per_channel_, pcm_file_) !=
189 static_cast<size_t>(audio_frame.samples_per_channel_)) {
190 return;
191 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000192 } else {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000193 int16_t* stereo_audio =
194 new int16_t[2 * audio_frame.samples_per_channel_];
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000195 int k;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000196 for (k = 0; k < audio_frame.samples_per_channel_; k++) {
197 stereo_audio[k << 1] = audio_frame.data_[k];
198 stereo_audio[(k << 1) + 1] = audio_frame.data_[k];
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000199 }
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000200 if (fwrite(stereo_audio, sizeof(int16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000201 2 * audio_frame.samples_per_channel_, pcm_file_) !=
202 static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
203 return;
204 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000205 delete[] stereo_audio;
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000207 } else {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000208 if (fwrite(audio_frame.data_, sizeof(int16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000209 audio_frame.num_channels_ * audio_frame.samples_per_channel_,
210 pcm_file_) != static_cast<size_t>(
211 audio_frame.num_channels_ * audio_frame.samples_per_channel_)) {
212 return;
213 }
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000214 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000215}
216
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000217void PCMFile::Write10MsData(int16_t* playout_buffer,
218 uint16_t length_smpls) {
219 if (fwrite(playout_buffer, sizeof(uint16_t),
leozwang@webrtc.org354b0ed2012-06-01 17:46:21 +0000220 length_smpls, pcm_file_) != length_smpls) {
221 return;
222 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000223}
224
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000225void PCMFile::Close() {
226 fclose(pcm_file_);
227 pcm_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228}
229
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000230void PCMFile::Rewind() {
231 rewind(pcm_file_);
232 end_of_file_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000233}
234
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000235bool PCMFile::Rewinded() {
236 return rewinded_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237}
238
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000239void PCMFile::SaveStereo(bool is_stereo) {
240 save_stereo_ = is_stereo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241}
242
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000243void PCMFile::ReadStereo(bool is_stereo) {
244 read_stereo_ = is_stereo;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245}
246
tina.legrand@webrtc.orga6ecd1e2012-04-26 07:54:30 +0000247} // namespace webrtc