1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stdio.h>
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <string>
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
148ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org#include "webrtc/system_wrappers/interface/sleep.h"
15471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/test/testsupport/fileutils.h"
16471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/test/auto_test/fixtures/after_initialization_fixture.h"
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace {
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst int16_t kLimiterHeadroom = 29204;  // == -1 dbFS
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst int16_t kInt16Max = 0x7fff;
23d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgconst int kPayloadType = 105;
24d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgconst int kInSampleRateHz = 16000;  // Input file taken as 16 kHz by default.
25d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgconst int kRecSampleRateHz = 16000;  // Recorded with 16 kHz L16.
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgconst int kTestDurationMs = 3000;
27d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgconst CodecInst kCodecL16 = {kPayloadType, "L16", 16000, 160, 1, 256000};
28d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgconst CodecInst kCodecOpus = {kPayloadType, "opus", 48000, 960, 1, 32000};
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgclass MixingTest : public AfterInitializationFixture {
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org protected:
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  MixingTest()
358ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      : output_filename_(test::OutputPath() + "mixing_test_output.pcm") {
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
37e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org  void SetUp() {
38e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org    transport_ = new LoopBackTransport(voe_network_);
39e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org  }
40e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org  void TearDown() {
41e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org    delete transport_;
42e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org  }
43912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Creates and mixes |num_remote_streams| which play a file "as microphone"
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // with |num_local_streams| which play a file "locally", using a constant
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // amplitude of |input_value|. The local streams manifest as "anonymous"
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // mixing participants, meaning they will be mixed regardless of the number
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // of participants. (A stream is a VoiceEngine "channel").
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  //
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The mixed output is verified to always fall between |max_output_value| and
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // |min_output_value|, after a startup phase.
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  //
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // |num_remote_streams_using_mono| of the remote streams use mono, with the
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // remainder using stereo.
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void RunMixingTest(int num_remote_streams,
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     int num_local_streams,
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     int num_remote_streams_using_mono,
588ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org                     bool real_audio,
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     int16_t input_value,
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     int16_t max_output_value,
61d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                     int16_t min_output_value,
62d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                     const CodecInst& codec_inst) {
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_LE(num_remote_streams_using_mono, num_remote_streams);
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
658ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    if (real_audio) {
668ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      input_filename_ = test::ResourcePath("voice_engine/audio_long16", "pcm");
678ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    } else {
688ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      input_filename_ = test::OutputPath() + "mixing_test_input.pcm";
698ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      GenerateInputFile(input_value);
708ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    }
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    std::vector<int> local_streams(num_local_streams);
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = 0; i < local_streams.size(); ++i) {
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      local_streams[i] = voe_base_->CreateChannel();
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_NE(-1, local_streams[i]);
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StartLocalStreams(local_streams);
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    TEST_LOG("Playing %d local streams.\n", num_local_streams);
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    std::vector<int> remote_streams(num_remote_streams);
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = 0; i < remote_streams.size(); ++i) {
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      remote_streams[i] = voe_base_->CreateChannel();
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_NE(-1, remote_streams[i]);
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
85d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    StartRemoteStreams(remote_streams, num_remote_streams_using_mono,
86d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                       codec_inst);
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    TEST_LOG("Playing %d remote streams.\n", num_remote_streams);
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
898ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    // Give it plenty of time to get started.
908ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    SleepMs(1000);
918ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Start recording the mixed output and wait.
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_file_->StartRecordingPlayout(-1 /* record meeting */,
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        output_filename_.c_str()));
958ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    SleepMs(kTestDurationMs);
9673d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    while (GetFileDurationMs(output_filename_.c_str()) < kTestDurationMs) {
9773d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org      SleepMs(200);
9873d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    }
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_file_->StopRecordingPlayout(-1));
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopLocalStreams(local_streams);
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    StopRemoteStreams(remote_streams);
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1048ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    if (!real_audio) {
1058ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      VerifyMixedOutput(max_output_value, min_output_value);
1068ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    }
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org private:
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Generate input file with constant values equal to |input_value|. The file
1118ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  // will be twice the duration of the test.
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void GenerateInputFile(int16_t input_value) {
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    FILE* input_file = fopen(input_filename_.c_str(), "wb");
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_TRUE(input_file != NULL);
115d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    for (int i = 0; i < kInSampleRateHz / 1000 * (kTestDurationMs * 2); i++) {
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      ASSERT_EQ(1u, fwrite(&input_value, sizeof(input_value), 1, input_file));
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_EQ(0, fclose(input_file));
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void VerifyMixedOutput(int16_t max_output_value, int16_t min_output_value) {
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Verify the mixed output.
123b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    FILE* output_file = fopen(output_filename_.c_str(), "rb");
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_TRUE(output_file != NULL);
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int16_t output_value = 0;
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int samples_read = 0;
127b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (fread(&output_value, sizeof(output_value), 1, output_file) == 1) {
128b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      samples_read++;
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      std::ostringstream trace_stream;
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      trace_stream << samples_read << " samples read";
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      SCOPED_TRACE(trace_stream.str());
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_LE(output_value, max_output_value);
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_GE(output_value, min_output_value);
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1358ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    // Ensure we've at least recorded half as much file as the duration of the
1368ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    // test. We have to use a relaxed tolerance here due to filesystem flakiness
1378ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org    // on the bots.
138d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    ASSERT_GE((samples_read * 1000.0) / kRecSampleRateHz, kTestDurationMs);
139b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Ensure we read the entire file.
140b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_NE(0, feof(output_file));
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ASSERT_EQ(0, fclose(output_file));
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Start up local streams ("anonymous" participants).
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void StartLocalStreams(const std::vector<int>& streams) {
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = 0; i < streams.size(); ++i) {
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->StartPlayout(streams[i]));
148b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_file_->StartPlayingFileLocally(streams[i],
149b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          input_filename_.c_str(), true));
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
151b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
153b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void StopLocalStreams(const std::vector<int>& streams) {
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = 0; i < streams.size(); ++i) {
155b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->StopPlayout(streams[i]));
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->DeleteChannel(streams[i]));
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Start up remote streams ("normal" participants).
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void StartRemoteStreams(const std::vector<int>& streams,
162d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                          int num_remote_streams_using_mono,
163d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                          const CodecInst& codec_inst) {
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int i = 0; i < num_remote_streams_using_mono; ++i) {
1658ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      // Add some delay between starting up the channels in order to give them
1668ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      // different energies in the "real audio" test and hopefully exercise
1678ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      // more code paths.
1688ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org      SleepMs(50);
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      StartRemoteStream(streams[i], codec_inst, 1234 + 2 * i);
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // The remainder of the streams will use stereo.
173d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    CodecInst codec_inst_stereo = codec_inst;
174d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    codec_inst_stereo.channels = 2;
175d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    codec_inst_stereo.pltype++;
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = num_remote_streams_using_mono; i < streams.size(); ++i) {
177d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org      StartRemoteStream(streams[i], codec_inst_stereo, 1234 + 2 * i);
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Start up a single remote stream.
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void StartRemoteStream(int stream, const CodecInst& codec_inst, int port) {
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_codec_->SetRecPayloadType(stream, codec_inst));
184e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org    EXPECT_EQ(0, voe_network_->RegisterExternalTransport(stream, *transport_));
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_base_->StartReceive(stream));
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_base_->StartPlayout(stream));
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_codec_->SetSendCodec(stream, codec_inst));
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_base_->StartSend(stream));
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    EXPECT_EQ(0, voe_file_->StartPlayingFileAsMicrophone(stream,
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        input_filename_.c_str(), true));
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void StopRemoteStreams(const std::vector<int>& streams) {
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (size_t i = 0; i < streams.size(); ++i) {
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->StopSend(streams[i]));
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->StopPlayout(streams[i]));
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->StopReceive(streams[i]));
198e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org      EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(streams[i]));
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      EXPECT_EQ(0, voe_base_->DeleteChannel(streams[i]));
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
20373d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org  int GetFileDurationMs(const char* file_name) {
20473d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    FILE* fid = fopen(file_name, "rb");
20573d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    EXPECT_FALSE(fid == NULL);
20673d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    fseek(fid, 0, SEEK_END);
20773d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    int size = ftell(fid);
20873d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    EXPECT_NE(-1, size);
20973d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    fclose(fid);
21073d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org    // Divided by 2 due to 2 bytes/sample.
211d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org    return size * 1000 / kRecSampleRateHz / 2;
21273d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org  }
21373d6d1fb0e78720c165359124934ab6eaf16cc8fminyue@webrtc.org
2148ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  std::string input_filename_;
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const std::string output_filename_;
216e4932183091c42119e819bac6c6426f906438fa4pwestin@webrtc.org  LoopBackTransport* transport_;
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org};
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2198ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org// This test has no verification, but exercises additional code paths in a
2208ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org// somewhat more realistic scenario using real audio. It can at least hunt for
2218ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org// asserts and crashes.
2228ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, MixManyChannelsForStress) {
223d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org  RunMixingTest(10, 0, 10, true, 0, 0, 0, kCodecL16);
224d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org}
225d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org
226d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.orgTEST_F(MixingTest, MixManyChannelsForStressOpus) {
227d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org  RunMixingTest(10, 0, 10, true, 0, 0, 0, kCodecOpus);
2288ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org}
2298ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// These tests assume a maximum of three mixed participants. We typically allow
231c62e75057ec511010e83c392a4bb16f3ee1b7414phoglund@webrtc.org// a +/- 10% range around the expected output level to account for distortion
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// from coding and processing in the loopback chain.
2338ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, FourChannelsWithOnlyThreeMixed) {
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = 1000;
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kInputValue * 3;
2368ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(4, 0, 4, false, kInputValue, 1.1 * kExpectedOutput,
237d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                0.9 * kExpectedOutput, kCodecL16);
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Ensure the mixing saturation protection is working. We can do this because
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// the mixing limiter is given some headroom, so the expected output is less
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// than full scale.
2438ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, VerifySaturationProtection) {
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = 20000;
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kLimiterHeadroom;
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // If this isn't satisfied, we're not testing anything.
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ASSERT_GT(kInputValue * 3, kInt16Max);
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ASSERT_LT(1.1 * kExpectedOutput, kInt16Max);
2498ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(3, 0, 3, false, kInputValue, 1.1 * kExpectedOutput,
250d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org               0.9 * kExpectedOutput, kCodecL16);
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2538ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, SaturationProtectionHasNoEffectOnOneChannel) {
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = kInt16Max;
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kInt16Max;
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // If this isn't satisfied, we're not testing anything.
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  ASSERT_GT(0.95 * kExpectedOutput, kLimiterHeadroom);
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Tighter constraints are required here to properly test this.
2598ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(1, 0, 1, false, kInputValue, kExpectedOutput,
260d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                0.95 * kExpectedOutput, kCodecL16);
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2638ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, VerifyAnonymousAndNormalParticipantMixing) {
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = 1000;
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kInputValue * 2;
2668ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(1, 1, 1, false, kInputValue, 1.1 * kExpectedOutput,
267d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                0.9 * kExpectedOutput, kCodecL16);
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2708ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, AnonymousParticipantsAreAlwaysMixed) {
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = 1000;
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kInputValue * 4;
2738ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(3, 1, 3, false, kInputValue, 1.1 * kExpectedOutput,
274d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                0.9 * kExpectedOutput, kCodecL16);
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2778ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.orgTEST_F(MixingTest, VerifyStereoAndMonoMixing) {
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kInputValue = 1000;
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const int16_t kExpectedOutput = kInputValue * 2;
2808ad10ec40b643e279d614d4f14d2b4d9accf863bandrew@webrtc.org  RunMixingTest(2, 0, 1, false, kInputValue, 1.1 * kExpectedOutput,
2814c204785dfdb05c66542df5c87b55b2ae5c0e428andrew@webrtc.org                // Lower than 0.9 due to observed flakiness on bots.
282d89fa97356bc1a276fd1319f3b57232f2e8cdc01minyue@webrtc.org                0.8 * kExpectedOutput, kCodecL16);
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
286