OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/audio/audio_debug_recording_helper.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/files/file_path.h" |
| 9 #include "base/logging.h" |
| 10 #include "base/memory/ptr_util.h" |
| 11 #include "base/run_loop.h" |
| 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/test/test_message_loop.h" |
| 14 #include "media/base/audio_bus.h" |
| 15 #include "media/base/audio_sample_types.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 using testing::_; |
| 20 using testing::Return; |
| 21 |
| 22 #if defined(OS_WIN) |
| 23 #define IntToStringType base::IntToString16 |
| 24 #else |
| 25 #define IntToStringType base::IntToString |
| 26 #endif |
| 27 |
| 28 namespace media { |
| 29 |
| 30 namespace { |
| 31 |
| 32 // The filename extension the mock should return in GetFileNameExtension(). |
| 33 const base::FilePath::CharType kFileNameExtension[] = FILE_PATH_LITERAL("wav"); |
| 34 |
| 35 } // namespace |
| 36 |
| 37 // Mock class for the audio file writer that the helper wraps. |
| 38 class MockAudioFileWriter : public AudioFileWriter { |
| 39 public: |
| 40 MockAudioFileWriter(const AudioParameters& params) |
| 41 : params_(params), reference_data_(nullptr) {} |
| 42 ~MockAudioFileWriter() override {} |
| 43 |
| 44 MOCK_METHOD1(Start, void(const base::FilePath&)); |
| 45 MOCK_METHOD0(Stop, void()); |
| 46 |
| 47 // Functions with move-only types as arguments can't be mocked directly, so |
| 48 // we pass on to DoWrite(). Also, we can verify the data this way. |
| 49 MOCK_METHOD1(DoWrite, void(AudioBus*)); |
| 50 void Write(std::unique_ptr<AudioBus> data) override { |
| 51 CHECK(reference_data_); |
| 52 EXPECT_EQ(reference_data_->channels(), data->channels()); |
| 53 EXPECT_EQ(reference_data_->frames(), data->frames()); |
| 54 for (int i = 0; i < data->channels(); ++i) { |
| 55 float* data_ptr = data->channel(i); |
| 56 float* ref_data_ptr = reference_data_->channel(i); |
| 57 for (int j = 0; j < data->frames(); ++j, ++data_ptr, ++ref_data_ptr) |
| 58 EXPECT_EQ(*ref_data_ptr, *data_ptr); |
| 59 } |
| 60 DoWrite(data.get()); |
| 61 } |
| 62 |
| 63 MOCK_METHOD0(WillWrite, bool()); |
| 64 MOCK_METHOD0(GetFileNameExtension, const base::FilePath::CharType*()); |
| 65 |
| 66 // Set reference data to compare against. Must be called before Write() is |
| 67 // called. |
| 68 void SetReferenceData(AudioBus* reference_data) { |
| 69 EXPECT_EQ(params_.channels(), reference_data->channels()); |
| 70 EXPECT_EQ(params_.frames_per_buffer(), reference_data->frames()); |
| 71 reference_data_ = reference_data; |
| 72 } |
| 73 |
| 74 private: |
| 75 const AudioParameters params_; |
| 76 AudioBus* reference_data_; |
| 77 }; |
| 78 |
| 79 // The test fixture. |
| 80 class AudioDebugRecordingHelperTest : public ::testing::Test { |
| 81 public: |
| 82 AudioDebugRecordingHelperTest() |
| 83 : file_path_(base::FilePath::FromUTF8Unsafe("file_path")), |
| 84 mock_audio_file_writer_(nullptr) {} |
| 85 |
| 86 ~AudioDebugRecordingHelperTest() override {} |
| 87 |
| 88 // Creates the mock writer, passed as a callback to the helper and called by |
| 89 // the helper. After the mock writer is returned, we always expect |
| 90 // GetFileNameExtension() and Start() to be called on it by the helper. |
| 91 std::unique_ptr<AudioFileWriter> CreateMockAudioFileWriter( |
| 92 const AudioParameters& params) { |
| 93 CHECK(!mock_audio_file_writer_); |
| 94 MockAudioFileWriter* writer = new MockAudioFileWriter(params); |
| 95 EXPECT_CALL(*writer, GetFileNameExtension()) |
| 96 .WillOnce(Return(kFileNameExtension)); |
| 97 base::FilePath expected_file_path = |
| 98 file_path_.AddExtension(kFileNameExtension); |
| 99 EXPECT_CALL(*writer, Start(expected_file_path)); |
| 100 mock_audio_file_writer_ = writer; |
| 101 return base::WrapUnique<AudioFileWriter>(writer); |
| 102 } |
| 103 |
| 104 // Helper function that creates a recording helper. |
| 105 std::unique_ptr<AudioDebugRecordingHelper> CreateRecordingHelper( |
| 106 const AudioParameters& params, |
| 107 base::OnceClosure on_destruction_closure) { |
| 108 return base::MakeUnique<AudioDebugRecordingHelper>( |
| 109 params, base::BindRepeating( |
| 110 &AudioDebugRecordingHelperTest::CreateMockAudioFileWriter, |
| 111 base::Unretained(this)), |
| 112 message_loop_.task_runner(), std::move(on_destruction_closure)); |
| 113 } |
| 114 |
| 115 // Helper function that unsets the mock writer pointer after disabling. |
| 116 void DisableDebugRecording(AudioDebugRecordingHelper* recording_helper) { |
| 117 recording_helper->DisableDebugRecording(); |
| 118 mock_audio_file_writer_ = nullptr; |
| 119 } |
| 120 |
| 121 MOCK_METHOD0(OnAudioDebugRecordingHelperDestruction, void()); |
| 122 |
| 123 protected: |
| 124 base::FilePath file_path_; |
| 125 |
| 126 // Pointer to the mock writer that the helper wraps. Set in |
| 127 // CreateMockAudioFileWriter() and unset in DisableDebugRecording(). |
| 128 MockAudioFileWriter* mock_audio_file_writer_; |
| 129 |
| 130 base::TestMessageLoop message_loop_; |
| 131 |
| 132 private: |
| 133 DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingHelperTest); |
| 134 }; |
| 135 |
| 136 // Creates a helper with an on destrcution closure, and verifies that it's |
| 137 // run. |
| 138 TEST_F(AudioDebugRecordingHelperTest, TestDestructionClosure) { |
| 139 const AudioParameters params; |
| 140 std::unique_ptr<AudioDebugRecordingHelper> recording_helper = |
| 141 CreateRecordingHelper( |
| 142 params, base::BindOnce(&AudioDebugRecordingHelperTest:: |
| 143 OnAudioDebugRecordingHelperDestruction, |
| 144 base::Unretained(this))); |
| 145 |
| 146 EXPECT_CALL(*this, OnAudioDebugRecordingHelperDestruction()); |
| 147 } |
| 148 |
| 149 // Verifies that disable can be called without being enabled. |
| 150 TEST_F(AudioDebugRecordingHelperTest, OnlyDisable) { |
| 151 const AudioParameters params; |
| 152 std::unique_ptr<AudioDebugRecordingHelper> recording_helper = |
| 153 CreateRecordingHelper(params, base::OnceClosure()); |
| 154 |
| 155 recording_helper->DisableDebugRecording(); |
| 156 } |
| 157 |
| 158 TEST_F(AudioDebugRecordingHelperTest, EnableDisable) { |
| 159 const AudioParameters params; |
| 160 std::unique_ptr<AudioDebugRecordingHelper> recording_helper = |
| 161 CreateRecordingHelper(params, base::OnceClosure()); |
| 162 |
| 163 recording_helper->EnableDebugRecording(file_path_); |
| 164 EXPECT_CALL(*mock_audio_file_writer_, Stop()); |
| 165 DisableDebugRecording(recording_helper.get()); |
| 166 |
| 167 recording_helper->EnableDebugRecording(file_path_); |
| 168 EXPECT_CALL(*mock_audio_file_writer_, Stop()); |
| 169 DisableDebugRecording(recording_helper.get()); |
| 170 } |
| 171 |
| 172 TEST_F(AudioDebugRecordingHelperTest, OnData) { |
| 173 // Only channel layout and frames per buffer is used in the file writer and |
| 174 // AudioBus, the other parameters are ignored. |
| 175 const int number_of_frames = 100; |
| 176 const AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, |
| 177 ChannelLayout::CHANNEL_LAYOUT_STEREO, 0, 0, |
| 178 number_of_frames); |
| 179 |
| 180 // Setup some data. |
| 181 const int number_of_samples = number_of_frames * params.channels(); |
| 182 const float step = std::numeric_limits<int16_t>::max() / number_of_frames; |
| 183 std::unique_ptr<float[]> source_data(new float[number_of_samples]); |
| 184 for (float i = 0; i < number_of_samples; ++i) |
| 185 source_data[i] = i * step; |
| 186 std::unique_ptr<AudioBus> audio_bus = AudioBus::Create(params); |
| 187 audio_bus->FromInterleaved<Float32SampleTypeTraits>(source_data.get(), |
| 188 number_of_frames); |
| 189 |
| 190 std::unique_ptr<AudioDebugRecordingHelper> recording_helper = |
| 191 CreateRecordingHelper(params, base::OnceClosure()); |
| 192 |
| 193 // Should not do anything. |
| 194 recording_helper->OnData(audio_bus.get()); |
| 195 |
| 196 recording_helper->EnableDebugRecording(file_path_); |
| 197 mock_audio_file_writer_->SetReferenceData(audio_bus.get()); |
| 198 |
| 199 EXPECT_CALL(*mock_audio_file_writer_, DoWrite(_)); |
| 200 recording_helper->OnData(audio_bus.get()); |
| 201 base::RunLoop().RunUntilIdle(); |
| 202 |
| 203 EXPECT_CALL(*mock_audio_file_writer_, Stop()); |
| 204 DisableDebugRecording(recording_helper.get()); |
| 205 |
| 206 // Make sure we clear the loop before enabling again. |
| 207 base::RunLoop().RunUntilIdle(); |
| 208 |
| 209 // Enable again, this time with two OnData() calls, one OnData() call |
| 210 // without running the message loop until after disabling, and one call after |
| 211 // disabling. |
| 212 recording_helper->EnableDebugRecording(file_path_); |
| 213 mock_audio_file_writer_->SetReferenceData(audio_bus.get()); |
| 214 |
| 215 EXPECT_CALL(*mock_audio_file_writer_, DoWrite(_)).Times(2); |
| 216 recording_helper->OnData(audio_bus.get()); |
| 217 recording_helper->OnData(audio_bus.get()); |
| 218 base::RunLoop().RunUntilIdle(); |
| 219 |
| 220 // This call should not yield a DoWrite() call on the mock, since the message |
| 221 // loop isn't run until after disabling. WillWrite() is expected since |
| 222 // recording is enabled. |
| 223 recording_helper->OnData(audio_bus.get()); |
| 224 |
| 225 EXPECT_CALL(*mock_audio_file_writer_, Stop()); |
| 226 DisableDebugRecording(recording_helper.get()); |
| 227 |
| 228 // This call should not yield a DoWrite() call on the mock either. |
| 229 recording_helper->OnData(audio_bus.get()); |
| 230 base::RunLoop().RunUntilIdle(); |
| 231 } |
| 232 |
| 233 } // namespace media |
OLD | NEW |