blob: e069a42de1436d613ddc15d30197ff0585de52dd [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_coding/test/PCMFile.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "absl/strings/string_view.h"
#include "rtc_base/checks.h"
#include "test/gtest.h"
namespace webrtc {
#define MAX_FILE_NAME_LENGTH_BYTE 500
PCMFile::PCMFile()
: pcm_file_(NULL),
samples_10ms_(160),
frequency_(16000),
end_of_file_(false),
auto_rewind_(false),
rewinded_(false),
read_stereo_(false),
save_stereo_(false) {
timestamp_ =
(((uint32_t)rand() & 0x0000FFFF) << 16) | ((uint32_t)rand() & 0x0000FFFF);
}
PCMFile::PCMFile(uint32_t timestamp)
: pcm_file_(NULL),
samples_10ms_(160),
frequency_(16000),
end_of_file_(false),
auto_rewind_(false),
rewinded_(false),
read_stereo_(false),
save_stereo_(false) {
timestamp_ = timestamp;
}
PCMFile::~PCMFile() {
if (pcm_file_) {
fclose(pcm_file_);
}
}
int16_t PCMFile::ChooseFile(std::string* file_name,
int16_t max_len,
uint16_t* frequency_hz) {
char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
int16_t n = 0;
// Removing trailing spaces.
while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
(static_cast<unsigned char>(tmp_name[n]) != 0) &&
(n < MAX_FILE_NAME_LENGTH_BYTE)) {
n++;
}
if (n > 0) {
memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
}
// Removing trailing spaces.
n = (int16_t)(strlen(tmp_name) - 1);
if (n >= 0) {
while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
(n >= 0)) {
n--;
}
}
if (n >= 0) {
tmp_name[n + 1] = '\0';
}
int16_t len = (int16_t)strlen(tmp_name);
if (len > max_len) {
return -1;
}
if (len > 0) {
std::string tmp_string(tmp_name, len + 1);
*file_name = tmp_string;
}
printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
*frequency_hz);
EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
uint16_t tmp_frequency = (uint16_t)atoi(tmp_name);
if (tmp_frequency > 0) {
*frequency_hz = tmp_frequency;
}
return 0;
}
void PCMFile::Open(absl::string_view file_name,
uint16_t frequency,
absl::string_view mode,
bool auto_rewind) {
if ((pcm_file_ = fopen(std::string(file_name).c_str(),
std::string(mode).c_str())) == NULL) {
printf("Cannot open file %s.\n", std::string(file_name).c_str());
ADD_FAILURE() << "Unable to read file";
}
frequency_ = frequency;
samples_10ms_ = (uint16_t)(frequency_ / 100);
auto_rewind_ = auto_rewind;
end_of_file_ = false;
rewinded_ = false;
}
int32_t PCMFile::SamplingFrequency() const {
return frequency_;
}
uint16_t PCMFile::PayloadLength10Ms() const {
return samples_10ms_;
}
int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
uint16_t channels = 1;
if (read_stereo_) {
channels = 2;
}
int32_t payload_size =
(int32_t)fread(audio_frame.mutable_data(), sizeof(uint16_t),
samples_10ms_ * channels, pcm_file_);
if (payload_size < samples_10ms_ * channels) {
int16_t* frame_data = audio_frame.mutable_data();
for (int k = payload_size; k < samples_10ms_ * channels; k++) {
frame_data[k] = 0;
}
if (auto_rewind_) {
rewind(pcm_file_);
rewinded_ = true;
} else {
end_of_file_ = true;
}
}
audio_frame.samples_per_channel_ = samples_10ms_;
audio_frame.sample_rate_hz_ = frequency_;
audio_frame.num_channels_ = channels;
audio_frame.timestamp_ = timestamp_;
timestamp_ += samples_10ms_;
++blocks_read_;
if (num_10ms_blocks_to_read_ && blocks_read_ >= *num_10ms_blocks_to_read_)
end_of_file_ = true;
return samples_10ms_;
}
void PCMFile::Write10MsData(const AudioFrame& audio_frame) {
if (audio_frame.num_channels_ == 1) {
if (!save_stereo_) {
if (fwrite(audio_frame.data(), sizeof(uint16_t),
audio_frame.samples_per_channel_, pcm_file_) !=
static_cast<size_t>(audio_frame.samples_per_channel_)) {
return;
}
} else {
const int16_t* frame_data = audio_frame.data();
int16_t* stereo_audio = new int16_t[2 * audio_frame.samples_per_channel_];
for (size_t k = 0; k < audio_frame.samples_per_channel_; k++) {
stereo_audio[k << 1] = frame_data[k];
stereo_audio[(k << 1) + 1] = frame_data[k];
}
if (fwrite(stereo_audio, sizeof(int16_t),
2 * audio_frame.samples_per_channel_, pcm_file_) !=
static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
return;
}
delete[] stereo_audio;
}
} else {
if (fwrite(audio_frame.data(), sizeof(int16_t),
audio_frame.num_channels_ * audio_frame.samples_per_channel_,
pcm_file_) !=
static_cast<size_t>(audio_frame.num_channels_ *
audio_frame.samples_per_channel_)) {
return;
}
}
}
void PCMFile::Write10MsData(const int16_t* playout_buffer,
size_t length_smpls) {
if (fwrite(playout_buffer, sizeof(uint16_t), length_smpls, pcm_file_) !=
length_smpls) {
return;
}
}
void PCMFile::Close() {
fclose(pcm_file_);
pcm_file_ = NULL;
blocks_read_ = 0;
}
void PCMFile::FastForward(int num_10ms_blocks) {
const int channels = read_stereo_ ? 2 : 1;
long num_bytes_to_move =
num_10ms_blocks * sizeof(int16_t) * samples_10ms_ * channels;
int error = fseek(pcm_file_, num_bytes_to_move, SEEK_CUR);
RTC_DCHECK_EQ(error, 0);
}
void PCMFile::Rewind() {
rewind(pcm_file_);
end_of_file_ = false;
blocks_read_ = 0;
}
bool PCMFile::Rewinded() {
return rewinded_;
}
void PCMFile::SaveStereo(bool is_stereo) {
save_stereo_ = is_stereo;
}
void PCMFile::ReadStereo(bool is_stereo) {
read_stereo_ = is_stereo;
}
void PCMFile::SetNum10MsBlocksToRead(int value) {
num_10ms_blocks_to_read_ = value;
}
} // namespace webrtc