| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "base/android/build_info.h" | 5 #include "base/android/build_info.h" |
| 6 #include "base/basictypes.h" | |
| 7 #include "base/bind.h" | 6 #include "base/bind.h" |
| 8 #include "base/files/file_util.h" | 7 #include "base/files/file_util.h" |
| 9 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
| 11 #include "base/path_service.h" | 10 #include "base/path_service.h" |
| 12 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 13 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
| 14 #include "base/synchronization/lock.h" | 13 #include "base/synchronization/lock.h" |
| 15 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 16 #include "base/test/test_timeouts.h" | 15 #include "base/test/test_timeouts.h" |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 << (params.effects() & AudioParameters::ECHO_CANCELLER); | 145 << (params.effects() & AudioParameters::ECHO_CANCELLER); |
| 147 return os; | 146 return os; |
| 148 } | 147 } |
| 149 | 148 |
| 150 // Gmock implementation of AudioInputStream::AudioInputCallback. | 149 // Gmock implementation of AudioInputStream::AudioInputCallback. |
| 151 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback { | 150 class MockAudioInputCallback : public AudioInputStream::AudioInputCallback { |
| 152 public: | 151 public: |
| 153 MOCK_METHOD4(OnData, | 152 MOCK_METHOD4(OnData, |
| 154 void(AudioInputStream* stream, | 153 void(AudioInputStream* stream, |
| 155 const AudioBus* src, | 154 const AudioBus* src, |
| 156 uint32 hardware_delay_bytes, | 155 uint32_t hardware_delay_bytes, |
| 157 double volume)); | 156 double volume)); |
| 158 MOCK_METHOD1(OnError, void(AudioInputStream* stream)); | 157 MOCK_METHOD1(OnError, void(AudioInputStream* stream)); |
| 159 }; | 158 }; |
| 160 | 159 |
| 161 // Implements AudioOutputStream::AudioSourceCallback and provides audio data | 160 // Implements AudioOutputStream::AudioSourceCallback and provides audio data |
| 162 // by reading from a data file. | 161 // by reading from a data file. |
| 163 class FileAudioSource : public AudioOutputStream::AudioSourceCallback { | 162 class FileAudioSource : public AudioOutputStream::AudioSourceCallback { |
| 164 public: | 163 public: |
| 165 explicit FileAudioSource(base::WaitableEvent* event, const std::string& name) | 164 explicit FileAudioSource(base::WaitableEvent* event, const std::string& name) |
| 166 : event_(event), pos_(0) { | 165 : event_(event), pos_(0) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); | 240 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); |
| 242 file_path = file_path.AppendASCII(file_name.c_str()); | 241 file_path = file_path.AppendASCII(file_name.c_str()); |
| 243 binary_file_ = base::OpenFile(file_path, "wb"); | 242 binary_file_ = base::OpenFile(file_path, "wb"); |
| 244 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file."; | 243 DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file."; |
| 245 DVLOG(0) << "Writing to file: " << file_path.value().c_str(); | 244 DVLOG(0) << "Writing to file: " << file_path.value().c_str(); |
| 246 } | 245 } |
| 247 | 246 |
| 248 ~FileAudioSink() override { | 247 ~FileAudioSink() override { |
| 249 int bytes_written = 0; | 248 int bytes_written = 0; |
| 250 while (bytes_written < buffer_->forward_capacity()) { | 249 while (bytes_written < buffer_->forward_capacity()) { |
| 251 const uint8* chunk; | 250 const uint8_t* chunk; |
| 252 int chunk_size; | 251 int chunk_size; |
| 253 | 252 |
| 254 // Stop writing if no more data is available. | 253 // Stop writing if no more data is available. |
| 255 if (!buffer_->GetCurrentChunk(&chunk, &chunk_size)) | 254 if (!buffer_->GetCurrentChunk(&chunk, &chunk_size)) |
| 256 break; | 255 break; |
| 257 | 256 |
| 258 // Write recorded data chunk to the file and prepare for next chunk. | 257 // Write recorded data chunk to the file and prepare for next chunk. |
| 259 // TODO(henrika): use file_util:: instead. | 258 // TODO(henrika): use file_util:: instead. |
| 260 fwrite(chunk, 1, chunk_size, binary_file_); | 259 fwrite(chunk, 1, chunk_size, binary_file_); |
| 261 buffer_->Seek(chunk_size); | 260 buffer_->Seek(chunk_size); |
| 262 bytes_written += chunk_size; | 261 bytes_written += chunk_size; |
| 263 } | 262 } |
| 264 base::CloseFile(binary_file_); | 263 base::CloseFile(binary_file_); |
| 265 } | 264 } |
| 266 | 265 |
| 267 // AudioInputStream::AudioInputCallback implementation. | 266 // AudioInputStream::AudioInputCallback implementation. |
| 268 void OnData(AudioInputStream* stream, | 267 void OnData(AudioInputStream* stream, |
| 269 const AudioBus* src, | 268 const AudioBus* src, |
| 270 uint32 hardware_delay_bytes, | 269 uint32_t hardware_delay_bytes, |
| 271 double volume) override { | 270 double volume) override { |
| 272 const int num_samples = src->frames() * src->channels(); | 271 const int num_samples = src->frames() * src->channels(); |
| 273 scoped_ptr<int16> interleaved(new int16[num_samples]); | 272 scoped_ptr<int16_t> interleaved(new int16_t[num_samples]); |
| 274 const int bytes_per_sample = sizeof(*interleaved); | 273 const int bytes_per_sample = sizeof(*interleaved); |
| 275 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get()); | 274 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get()); |
| 276 | 275 |
| 277 // Store data data in a temporary buffer to avoid making blocking | 276 // Store data data in a temporary buffer to avoid making blocking |
| 278 // fwrite() calls in the audio callback. The complete buffer will be | 277 // fwrite() calls in the audio callback. The complete buffer will be |
| 279 // written to file in the destructor. | 278 // written to file in the destructor. |
| 280 const int size = bytes_per_sample * num_samples; | 279 const int size = bytes_per_sample * num_samples; |
| 281 if (!buffer_->Append((const uint8*)interleaved.get(), size)) | 280 if (!buffer_->Append((const uint8_t*)interleaved.get(), size)) |
| 282 event_->Signal(); | 281 event_->Signal(); |
| 283 } | 282 } |
| 284 | 283 |
| 285 void OnError(AudioInputStream* stream) override {} | 284 void OnError(AudioInputStream* stream) override {} |
| 286 | 285 |
| 287 private: | 286 private: |
| 288 base::WaitableEvent* event_; | 287 base::WaitableEvent* event_; |
| 289 AudioParameters params_; | 288 AudioParameters params_; |
| 290 scoped_ptr<media::SeekableBuffer> buffer_; | 289 scoped_ptr<media::SeekableBuffer> buffer_; |
| 291 FILE* binary_file_; | 290 FILE* binary_file_; |
| 292 | 291 |
| 293 DISALLOW_COPY_AND_ASSIGN(FileAudioSink); | 292 DISALLOW_COPY_AND_ASSIGN(FileAudioSink); |
| 294 }; | 293 }; |
| 295 | 294 |
| 296 // Implements AudioInputCallback and AudioSourceCallback to support full | 295 // Implements AudioInputCallback and AudioSourceCallback to support full |
| 297 // duplex audio where captured samples are played out in loopback after | 296 // duplex audio where captured samples are played out in loopback after |
| 298 // reading from a temporary FIFO storage. | 297 // reading from a temporary FIFO storage. |
| 299 class FullDuplexAudioSinkSource | 298 class FullDuplexAudioSinkSource |
| 300 : public AudioInputStream::AudioInputCallback, | 299 : public AudioInputStream::AudioInputCallback, |
| 301 public AudioOutputStream::AudioSourceCallback { | 300 public AudioOutputStream::AudioSourceCallback { |
| 302 public: | 301 public: |
| 303 explicit FullDuplexAudioSinkSource(const AudioParameters& params) | 302 explicit FullDuplexAudioSinkSource(const AudioParameters& params) |
| 304 : params_(params), | 303 : params_(params), |
| 305 previous_time_(base::TimeTicks::Now()), | 304 previous_time_(base::TimeTicks::Now()), |
| 306 started_(false) { | 305 started_(false) { |
| 307 // Start with a reasonably small FIFO size. It will be increased | 306 // Start with a reasonably small FIFO size. It will be increased |
| 308 // dynamically during the test if required. | 307 // dynamically during the test if required. |
| 309 fifo_.reset(new media::SeekableBuffer(0, 2 * params.GetBytesPerBuffer())); | 308 fifo_.reset(new media::SeekableBuffer(0, 2 * params.GetBytesPerBuffer())); |
| 310 buffer_.reset(new uint8[params_.GetBytesPerBuffer()]); | 309 buffer_.reset(new uint8_t[params_.GetBytesPerBuffer()]); |
| 311 } | 310 } |
| 312 | 311 |
| 313 ~FullDuplexAudioSinkSource() override {} | 312 ~FullDuplexAudioSinkSource() override {} |
| 314 | 313 |
| 315 // AudioInputStream::AudioInputCallback implementation | 314 // AudioInputStream::AudioInputCallback implementation |
| 316 void OnData(AudioInputStream* stream, | 315 void OnData(AudioInputStream* stream, |
| 317 const AudioBus* src, | 316 const AudioBus* src, |
| 318 uint32 hardware_delay_bytes, | 317 uint32_t hardware_delay_bytes, |
| 319 double volume) override { | 318 double volume) override { |
| 320 const base::TimeTicks now_time = base::TimeTicks::Now(); | 319 const base::TimeTicks now_time = base::TimeTicks::Now(); |
| 321 const int diff = (now_time - previous_time_).InMilliseconds(); | 320 const int diff = (now_time - previous_time_).InMilliseconds(); |
| 322 | 321 |
| 323 EXPECT_EQ(params_.bits_per_sample(), 16); | 322 EXPECT_EQ(params_.bits_per_sample(), 16); |
| 324 const int num_samples = src->frames() * src->channels(); | 323 const int num_samples = src->frames() * src->channels(); |
| 325 scoped_ptr<int16> interleaved(new int16[num_samples]); | 324 scoped_ptr<int16_t> interleaved(new int16_t[num_samples]); |
| 326 const int bytes_per_sample = sizeof(*interleaved); | 325 const int bytes_per_sample = sizeof(*interleaved); |
| 327 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get()); | 326 src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get()); |
| 328 const int size = bytes_per_sample * num_samples; | 327 const int size = bytes_per_sample * num_samples; |
| 329 | 328 |
| 330 base::AutoLock lock(lock_); | 329 base::AutoLock lock(lock_); |
| 331 if (diff > 1000) { | 330 if (diff > 1000) { |
| 332 started_ = true; | 331 started_ = true; |
| 333 previous_time_ = now_time; | 332 previous_time_ = now_time; |
| 334 | 333 |
| 335 // Log out the extra delay added by the FIFO. This is a best effort | 334 // Log out the extra delay added by the FIFO. This is a best effort |
| 336 // estimate. We might be +- 10ms off here. | 335 // estimate. We might be +- 10ms off here. |
| 337 int extra_fifo_delay = | 336 int extra_fifo_delay = |
| 338 static_cast<int>(BytesToMilliseconds(fifo_->forward_bytes() + size)); | 337 static_cast<int>(BytesToMilliseconds(fifo_->forward_bytes() + size)); |
| 339 DVLOG(1) << extra_fifo_delay; | 338 DVLOG(1) << extra_fifo_delay; |
| 340 } | 339 } |
| 341 | 340 |
| 342 // We add an initial delay of ~1 second before loopback starts to ensure | 341 // We add an initial delay of ~1 second before loopback starts to ensure |
| 343 // a stable callback sequence and to avoid initial bursts which might add | 342 // a stable callback sequence and to avoid initial bursts which might add |
| 344 // to the extra FIFO delay. | 343 // to the extra FIFO delay. |
| 345 if (!started_) | 344 if (!started_) |
| 346 return; | 345 return; |
| 347 | 346 |
| 348 // Append new data to the FIFO and extend the size if the max capacity | 347 // Append new data to the FIFO and extend the size if the max capacity |
| 349 // was exceeded. Flush the FIFO when extended just in case. | 348 // was exceeded. Flush the FIFO when extended just in case. |
| 350 if (!fifo_->Append((const uint8*)interleaved.get(), size)) { | 349 if (!fifo_->Append((const uint8_t*)interleaved.get(), size)) { |
| 351 fifo_->set_forward_capacity(2 * fifo_->forward_capacity()); | 350 fifo_->set_forward_capacity(2 * fifo_->forward_capacity()); |
| 352 fifo_->Clear(); | 351 fifo_->Clear(); |
| 353 } | 352 } |
| 354 } | 353 } |
| 355 | 354 |
| 356 void OnError(AudioInputStream* stream) override {} | 355 void OnError(AudioInputStream* stream) override {} |
| 357 | 356 |
| 358 // AudioOutputStream::AudioSourceCallback implementation | 357 // AudioOutputStream::AudioSourceCallback implementation |
| 359 int OnMoreData(AudioBus* dest, | 358 int OnMoreData(AudioBus* dest, |
| 360 uint32_t total_bytes_delay, | 359 uint32_t total_bytes_delay, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 const int frames = bytes / params_.GetBytesPerFrame(); | 394 const int frames = bytes / params_.GetBytesPerFrame(); |
| 396 return (base::TimeDelta::FromMicroseconds( | 395 return (base::TimeDelta::FromMicroseconds( |
| 397 frames * base::Time::kMicrosecondsPerSecond / | 396 frames * base::Time::kMicrosecondsPerSecond / |
| 398 static_cast<double>(params_.sample_rate()))).InMillisecondsF(); | 397 static_cast<double>(params_.sample_rate()))).InMillisecondsF(); |
| 399 } | 398 } |
| 400 | 399 |
| 401 AudioParameters params_; | 400 AudioParameters params_; |
| 402 base::TimeTicks previous_time_; | 401 base::TimeTicks previous_time_; |
| 403 base::Lock lock_; | 402 base::Lock lock_; |
| 404 scoped_ptr<media::SeekableBuffer> fifo_; | 403 scoped_ptr<media::SeekableBuffer> fifo_; |
| 405 scoped_ptr<uint8[]> buffer_; | 404 scoped_ptr<uint8_t[]> buffer_; |
| 406 bool started_; | 405 bool started_; |
| 407 | 406 |
| 408 DISALLOW_COPY_AND_ASSIGN(FullDuplexAudioSinkSource); | 407 DISALLOW_COPY_AND_ASSIGN(FullDuplexAudioSinkSource); |
| 409 }; | 408 }; |
| 410 | 409 |
| 411 // Test fixture class for tests which only exercise the output path. | 410 // Test fixture class for tests which only exercise the output path. |
| 412 class AudioAndroidOutputTest : public testing::Test { | 411 class AudioAndroidOutputTest : public testing::Test { |
| 413 public: | 412 public: |
| 414 AudioAndroidOutputTest() | 413 AudioAndroidOutputTest() |
| 415 : loop_(new base::MessageLoopForUI()), | 414 : loop_(new base::MessageLoopForUI()), |
| (...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 951 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20)); | 950 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20)); |
| 952 printf("\n"); | 951 printf("\n"); |
| 953 StopAndCloseAudioOutputStreamOnAudioThread(); | 952 StopAndCloseAudioOutputStreamOnAudioThread(); |
| 954 StopAndCloseAudioInputStreamOnAudioThread(); | 953 StopAndCloseAudioInputStreamOnAudioThread(); |
| 955 } | 954 } |
| 956 | 955 |
| 957 INSTANTIATE_TEST_CASE_P(AudioAndroidInputTest, AudioAndroidInputTest, | 956 INSTANTIATE_TEST_CASE_P(AudioAndroidInputTest, AudioAndroidInputTest, |
| 958 testing::ValuesIn(RunAudioRecordInputPathTests())); | 957 testing::ValuesIn(RunAudioRecordInputPathTests())); |
| 959 | 958 |
| 960 } // namespace media | 959 } // namespace media |
| OLD | NEW |