| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdint.h> | 5 #include <stdint.h> |
| 6 | 6 |
| 7 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
| 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/synchronization/waitable_event.h" |
| 8 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
| 9 #include "content/browser/renderer_host/media/audio_input_debug_writer.h" | 11 #include "content/browser/renderer_host/media/audio_input_debug_writer.h" |
| 10 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 11 #include "content/public/test/test_browser_thread_bundle.h" | 13 #include "content/public/test/test_browser_thread_bundle.h" |
| 12 #include "media/base/audio_bus.h" | 14 #include "media/base/audio_bus.h" |
| 13 #include "media/base/test_helpers.h" | 15 #include "media/base/test_helpers.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 17 |
| 16 namespace content { | 18 namespace content { |
| 17 | 19 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 34 } // namespace | 36 } // namespace |
| 35 | 37 |
| 36 // <channel layout, sample rate, frames per buffer, number of buffer writes | 38 // <channel layout, sample rate, frames per buffer, number of buffer writes |
| 37 typedef std::tr1::tuple<media::ChannelLayout, int, int, int> | 39 typedef std::tr1::tuple<media::ChannelLayout, int, int, int> |
| 38 AudioInputDebugWriterTestData; | 40 AudioInputDebugWriterTestData; |
| 39 | 41 |
| 40 class AudioInputDebugWriterTest | 42 class AudioInputDebugWriterTest |
| 41 : public testing::TestWithParam<AudioInputDebugWriterTestData> { | 43 : public testing::TestWithParam<AudioInputDebugWriterTestData> { |
| 42 public: | 44 public: |
| 43 AudioInputDebugWriterTest() | 45 AudioInputDebugWriterTest() |
| 44 : params_(media::AudioParameters::Format::AUDIO_PCM_LINEAR, | 46 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD), |
| 47 params_(media::AudioParameters::Format::AUDIO_PCM_LINEAR, |
| 45 std::tr1::get<0>(GetParam()), | 48 std::tr1::get<0>(GetParam()), |
| 46 std::tr1::get<1>(GetParam()), | 49 std::tr1::get<1>(GetParam()), |
| 47 kBytesPerSample * 8, | 50 kBytesPerSample * 8, |
| 48 std::tr1::get<2>(GetParam())), | 51 std::tr1::get<2>(GetParam())), |
| 49 writes_(std::tr1::get<3>(GetParam())), | 52 writes_(std::tr1::get<3>(GetParam())), |
| 50 source_samples_(params_.frames_per_buffer() * params_.channels() * | 53 source_samples_(params_.frames_per_buffer() * params_.channels() * |
| 51 writes_), | 54 writes_), |
| 52 source_interleaved_(source_samples_ ? new int16_t[source_samples_] | 55 source_interleaved_(source_samples_ ? new int16_t[source_samples_] |
| 53 : nullptr) { | 56 : nullptr) { |
| 54 InitSourceInterleaved(source_interleaved_.get(), source_samples_); | 57 InitSourceInterleaved(source_interleaved_.get(), source_samples_); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 EXPECT_EQ(static_cast<int>(file.GetLength() - kWavHeaderSize), read); | 148 EXPECT_EQ(static_cast<int>(file.GetLength() - kWavHeaderSize), read); |
| 146 | 149 |
| 147 VerifyDataRecording(source_interleaved_.get(), result_interleaved.get(), | 150 VerifyDataRecording(source_interleaved_.get(), result_interleaved.get(), |
| 148 source_samples_); | 151 source_samples_); |
| 149 } | 152 } |
| 150 } | 153 } |
| 151 | 154 |
| 152 void TestDoneOnFileThread(const base::Closure& callback) { | 155 void TestDoneOnFileThread(const base::Closure& callback) { |
| 153 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | 156 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 154 | 157 |
| 155 // |writer| must be destroyed on FILE thread. | |
| 156 input_debug_writer_.reset(nullptr); | |
| 157 callback.Run(); | 158 callback.Run(); |
| 158 } | 159 } |
| 159 | 160 |
| 160 void DoDebugRecording(base::File file) { | 161 void DoDebugRecording() { |
| 161 if (!file.IsValid()) | |
| 162 return; | |
| 163 | |
| 164 input_debug_writer_.reset( | |
| 165 new AudioInputDebugWriter(std::move(file), params_)); | |
| 166 // Write tasks are posted to BrowserThread::FILE. | 162 // Write tasks are posted to BrowserThread::FILE. |
| 167 for (int i = 0; i < writes_; ++i) { | 163 for (int i = 0; i < writes_; ++i) { |
| 168 std::unique_ptr<media::AudioBus> bus = media::AudioBus::Create( | 164 std::unique_ptr<media::AudioBus> bus = media::AudioBus::Create( |
| 169 params_.channels(), params_.frames_per_buffer()); | 165 params_.channels(), params_.frames_per_buffer()); |
| 170 | 166 |
| 171 bus->FromInterleaved( | 167 bus->FromInterleaved( |
| 172 source_interleaved_.get() + | 168 source_interleaved_.get() + |
| 173 i * params_.channels() * params_.frames_per_buffer(), | 169 i * params_.channels() * params_.frames_per_buffer(), |
| 174 params_.frames_per_buffer(), kBytesPerSample); | 170 params_.frames_per_buffer(), kBytesPerSample); |
| 175 | 171 |
| 176 input_debug_writer_->Write(std::move(bus)); | 172 input_debug_writer_->Write(std::move(bus)); |
| 177 } | 173 } |
| 174 } |
| 178 | 175 |
| 176 void WaitForRecordingCompletion() { |
| 179 media::WaitableMessageLoopEvent event; | 177 media::WaitableMessageLoopEvent event; |
| 180 | 178 |
| 181 // Post a task to BrowserThread::FILE indicating that all the writes are | 179 // Post a task to BrowserThread::FILE indicating that all the writes are |
| 182 // done. | 180 // done. |
| 183 BrowserThread::PostTask( | 181 BrowserThread::PostTask( |
| 184 BrowserThread::FILE, FROM_HERE, | 182 BrowserThread::FILE, FROM_HERE, |
| 185 base::Bind(&AudioInputDebugWriterTest::TestDoneOnFileThread, | 183 base::Bind(&AudioInputDebugWriterTest::TestDoneOnFileThread, |
| 186 base::Unretained(this), event.GetClosure())); | 184 base::Unretained(this), event.GetClosure())); |
| 187 | 185 |
| 188 // Wait for TestDoneOnFileThread() to call event's closure. | 186 // Wait for TestDoneOnFileThread() to call event's closure. |
| 189 event.RunAndWait(); | 187 event.RunAndWait(); |
| 190 } | 188 } |
| 191 | 189 |
| 190 void RecordAndVerifyOnce() { |
| 191 base::FilePath file_path; |
| 192 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); |
| 193 |
| 194 input_debug_writer_->Start(file_path); |
| 195 |
| 196 DoDebugRecording(); |
| 197 |
| 198 input_debug_writer_->Stop(); |
| 199 |
| 200 WaitForRecordingCompletion(); |
| 201 |
| 202 VerifyRecording(file_path); |
| 203 |
| 204 if (::testing::Test::HasFailure()) { |
| 205 LOG(ERROR) << "Test failed; keeping recording(s) at [" |
| 206 << file_path.value().c_str() << "]."; |
| 207 } else { |
| 208 EXPECT_TRUE(base::DeleteFile(file_path, false)); |
| 209 } |
| 210 } |
| 211 |
| 192 protected: | 212 protected: |
| 193 TestBrowserThreadBundle thread_bundle_; | 213 TestBrowserThreadBundle thread_bundle_; |
| 194 | 214 |
| 195 // Writer under test. | 215 // Writer under test. |
| 196 std::unique_ptr<AudioInputDebugWriter> input_debug_writer_; | 216 std::unique_ptr<AudioInputDebugWriter> input_debug_writer_; |
| 197 | 217 |
| 198 // AudioBus parameters. | 218 // AudioBus parameters. |
| 199 media::AudioParameters params_; | 219 media::AudioParameters params_; |
| 200 | 220 |
| 201 // Number of times to write AudioBus to the file. | 221 // Number of times to write AudioBus to the file. |
| 202 int writes_; | 222 int writes_; |
| 203 | 223 |
| 204 // Number of samples in the source data. | 224 // Number of samples in the source data. |
| 205 int source_samples_; | 225 int source_samples_; |
| 206 | 226 |
| 207 // Source data. | 227 // Source data. |
| 208 std::unique_ptr<int16_t[]> source_interleaved_; | 228 std::unique_ptr<int16_t[]> source_interleaved_; |
| 209 | 229 |
| 210 private: | 230 private: |
| 211 DISALLOW_COPY_AND_ASSIGN(AudioInputDebugWriterTest); | 231 DISALLOW_COPY_AND_ASSIGN(AudioInputDebugWriterTest); |
| 212 }; | 232 }; |
| 213 | 233 |
| 234 class AudioInputDebugWriterBehavioralTest : public AudioInputDebugWriterTest {}; |
| 235 |
| 214 TEST_P(AudioInputDebugWriterTest, WaveRecordingTest) { | 236 TEST_P(AudioInputDebugWriterTest, WaveRecordingTest) { |
| 237 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 238 |
| 239 RecordAndVerifyOnce(); |
| 240 } |
| 241 |
| 242 TEST_P(AudioInputDebugWriterBehavioralTest, |
| 243 DeletedBeforeRecordingFinishedOnFileThread) { |
| 244 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 245 |
| 215 base::FilePath file_path; | 246 base::FilePath file_path; |
| 216 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); | 247 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); |
| 217 | 248 |
| 218 base::File file(file_path, | 249 base::WaitableEvent* wait_for_deletion = |
| 219 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); | 250 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL, |
| 220 EXPECT_TRUE(file.IsValid()); | 251 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 221 | 252 |
| 222 DoDebugRecording(std::move(file)); | 253 BrowserThread::PostTask( |
| 254 BrowserThread::FILE, FROM_HERE, |
| 255 base::Bind(&base::WaitableEvent::Wait, base::Owned(wait_for_deletion))); |
| 256 |
| 257 input_debug_writer_->Start(file_path); |
| 258 |
| 259 DoDebugRecording(); |
| 260 |
| 261 input_debug_writer_.reset(); |
| 262 wait_for_deletion->Signal(); |
| 263 |
| 264 WaitForRecordingCompletion(); |
| 223 | 265 |
| 224 VerifyRecording(file_path); | 266 VerifyRecording(file_path); |
| 225 | 267 |
| 226 if (::testing::Test::HasFailure()) { | 268 if (::testing::Test::HasFailure()) { |
| 227 LOG(ERROR) << "Test failed; keeping recording(s) at [" | 269 LOG(ERROR) << "Test failed; keeping recording(s) at [" |
| 228 << file_path.value().c_str() << "]."; | 270 << file_path.value().c_str() << "]."; |
| 229 } else { | 271 } else { |
| 230 EXPECT_TRUE(base::DeleteFile(file_path, false)); | 272 EXPECT_TRUE(base::DeleteFile(file_path, false)); |
| 231 } | 273 } |
| 232 } | 274 } |
| 233 | 275 |
| 276 TEST_P(AudioInputDebugWriterBehavioralTest, FileCreationError) { |
| 277 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 278 base::FilePath file_path; // Empty file name. |
| 279 input_debug_writer_->Start(file_path); |
| 280 DoDebugRecording(); |
| 281 } |
| 282 |
| 283 TEST_P(AudioInputDebugWriterBehavioralTest, StartStopStartStop) { |
| 284 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 285 RecordAndVerifyOnce(); |
| 286 RecordAndVerifyOnce(); |
| 287 } |
| 288 |
| 289 TEST_P(AudioInputDebugWriterBehavioralTest, DestroyNotStarted) { |
| 290 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 291 input_debug_writer_.reset(); |
| 292 } |
| 293 |
| 294 TEST_P(AudioInputDebugWriterBehavioralTest, DestroyStarted) { |
| 295 input_debug_writer_.reset(new AudioInputDebugWriter(params_)); |
| 296 base::FilePath file_path; |
| 297 EXPECT_TRUE(base::CreateTemporaryFile(&file_path)); |
| 298 input_debug_writer_->Start(file_path); |
| 299 input_debug_writer_.reset(); |
| 300 } |
| 301 |
| 234 INSTANTIATE_TEST_CASE_P( | 302 INSTANTIATE_TEST_CASE_P( |
| 235 AudioInputDebugWriterTest, | 303 AudioInputDebugWriterTest, |
| 236 AudioInputDebugWriterTest, | 304 AudioInputDebugWriterTest, |
| 237 // Using 10ms sframes per buffer everywhere. | 305 // Using 10ms frames per buffer everywhere. |
| 238 testing::Values( | 306 testing::Values( |
| 239 // No writes. | 307 // No writes. |
| 240 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, | 308 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, |
| 241 44100, | 309 44100, |
| 242 44100 / 100, | 310 44100 / 100, |
| 243 0), | 311 0), |
| 244 // 1 write of mono. | 312 // 1 write of mono. |
| 245 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, | 313 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, |
| 246 44100, | 314 44100, |
| 247 44100 / 100, | 315 44100 / 100, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 260 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, | 328 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, |
| 261 44100, | 329 44100, |
| 262 44100 / 100, | 330 44100 / 100, |
| 263 100), | 331 100), |
| 264 // 15 seconds of stereo, higher rate. | 332 // 15 seconds of stereo, higher rate. |
| 265 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, | 333 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_STEREO, |
| 266 48000, | 334 48000, |
| 267 48000 / 100, | 335 48000 / 100, |
| 268 1500))); | 336 1500))); |
| 269 | 337 |
| 338 INSTANTIATE_TEST_CASE_P( |
| 339 AudioInputDebugWriterBehavioralTest, |
| 340 AudioInputDebugWriterBehavioralTest, |
| 341 // Using 10ms frames per buffer everywhere. |
| 342 testing::Values( |
| 343 // No writes. |
| 344 std::tr1::make_tuple(media::ChannelLayout::CHANNEL_LAYOUT_MONO, |
| 345 44100, |
| 346 44100 / 100, |
| 347 100))); |
| 348 |
| 270 } // namespace content | 349 } // namespace content |
| OLD | NEW |