/* * 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 #include #include #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(tmp_name[n])) || iscntrl(static_cast(tmp_name[n]))) && (static_cast(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(tmp_name[n])) || iscntrl(static_cast(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(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(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(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