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/test/testsupport/fileutils.h"
12#include "webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h"
13
14namespace {
15
16const int kSampleRateHz = 16000;
17const int kTestDurationMs = 1000;
18const int kSkipOutputMs = 50;
19const int16_t kInputValue = 15000;
20const int16_t kSilenceValue = 0;
21
22}  // namespace
23
24class FileBeforeStreamingTest : public AfterInitializationFixture {
25 protected:
26  FileBeforeStreamingTest()
27      : input_filename_(webrtc::test::OutputPath() + "file_test_input.pcm"),
28        output_filename_(webrtc::test::OutputPath() + "file_test_output.pcm") {
29  }
30
31  void SetUp() {
32    channel_ = voe_base_->CreateChannel();
33  }
34
35  void TearDown() {
36    voe_base_->DeleteChannel(channel_);
37  }
38
39  // TODO(andrew): consolidate below methods in a shared place?
40
41  // Generate input file with constant values as |kInputValue|. The file
42  // will be one second longer than the duration of the test.
43  void GenerateInputFile() {
44    FILE* input_file = fopen(input_filename_.c_str(), "wb");
45    ASSERT_TRUE(input_file != NULL);
46    for (int i = 0; i < kSampleRateHz / 1000 * (kTestDurationMs + 1000); i++) {
47      ASSERT_EQ(1u, fwrite(&kInputValue, sizeof(kInputValue), 1, input_file));
48    }
49    ASSERT_EQ(0, fclose(input_file));
50  }
51
52  void RecordOutput() {
53    // Start recording the mixed output for |kTestDurationMs| long.
54    EXPECT_EQ(0, voe_file_->StartRecordingPlayout(-1,
55        output_filename_.c_str()));
56    Sleep(kTestDurationMs);
57    EXPECT_EQ(0, voe_file_->StopRecordingPlayout(-1));
58  }
59
60  void VerifyOutput(int16_t target_value) {
61    FILE* output_file = fopen(output_filename_.c_str(), "rb");
62    ASSERT_TRUE(output_file != NULL);
63    int16_t output_value = 0;
64    int samples_read = 0;
65
66    // Skip the first segment to avoid initialization and ramping-in effects.
67    EXPECT_EQ(0, fseek(output_file, sizeof(output_value) *
68                       kSampleRateHz / 1000 * kSkipOutputMs, SEEK_SET));
69    while (fread(&output_value, sizeof(output_value), 1, output_file) == 1) {
70      samples_read++;
71      EXPECT_EQ(output_value, target_value);
72    }
73
74    // Ensure that a reasonable amount was recorded. We use a loose
75    // tolerance to avoid flaky bot failures.
76    ASSERT_GE((samples_read * 1000.0) / kSampleRateHz, 0.4 * kTestDurationMs);
77
78    // Ensure we read the entire file.
79    ASSERT_NE(0, feof(output_file));
80    ASSERT_EQ(0, fclose(output_file));
81  }
82
83void VerifyEmptyOutput() {
84  FILE* output_file = fopen(output_filename_.c_str(), "rb");
85  ASSERT_TRUE(output_file != NULL);
86  ASSERT_EQ(0, fseek(output_file, 0, SEEK_END));
87  EXPECT_EQ(0, ftell(output_file));
88  ASSERT_EQ(0, fclose(output_file));
89}
90
91  int channel_;
92  const std::string input_filename_;
93  const std::string output_filename_;
94};
95
96// This test case is to ensure that StartPlayingFileLocally() and
97// StartPlayout() can be called in any order.
98// A DC signal is used as input. And the output of mixer is supposed to be:
99// 1. the same DC signal if file is played out,
100// 2. total silence if file is not played out,
101// 3. no output if playout is not started.
102TEST_F(FileBeforeStreamingTest, TestStartPlayingFileLocallyWithStartPlayout) {
103  GenerateInputFile();
104
105  TEST_LOG("Playout is not started. File will not be played out.\n");
106  EXPECT_EQ(0, voe_file_->StartPlayingFileLocally(
107      channel_, input_filename_.c_str(), true));
108  EXPECT_EQ(1, voe_file_->IsPlayingFileLocally(channel_));
109  RecordOutput();
110  VerifyEmptyOutput();
111
112  TEST_LOG("Playout is now started. File will be played out.\n");
113  EXPECT_EQ(0, voe_base_->StartPlayout(channel_));
114  RecordOutput();
115  VerifyOutput(kInputValue);
116
117  TEST_LOG("Stop playing file. Only silence will be played out.\n");
118  EXPECT_EQ(0, voe_file_->StopPlayingFileLocally(channel_));
119  EXPECT_EQ(0, voe_file_->IsPlayingFileLocally(channel_));
120  RecordOutput();
121  VerifyOutput(kSilenceValue);
122
123  TEST_LOG("Start playing file again. File will be played out.\n");
124  EXPECT_EQ(0, voe_file_->StartPlayingFileLocally(
125      channel_, input_filename_.c_str(), true));
126  EXPECT_EQ(1, voe_file_->IsPlayingFileLocally(channel_));
127  RecordOutput();
128  VerifyOutput(kInputValue);
129
130  EXPECT_EQ(0, voe_base_->StopPlayout(channel_));
131  EXPECT_EQ(0, voe_file_->StopPlayingFileLocally(channel_));
132}
133