| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <limits> | 12 #include <limits> |
| 13 #include <list> | 13 #include <list> |
| 14 #include <memory> | 14 #include <memory> |
| 15 #include <numeric> | 15 #include <numeric> |
| 16 #include <string> | 16 #include <string> |
| 17 #include <vector> | 17 #include <vector> |
| 18 | 18 |
| 19 #include "webrtc/base/arraysize.h" | 19 #include "webrtc/base/arraysize.h" |
| 20 #include "webrtc/base/criticalsection.h" | 20 #include "webrtc/base/criticalsection.h" |
| 21 #include "webrtc/base/format_macros.h" | 21 #include "webrtc/base/format_macros.h" |
| 22 #include "webrtc/base/logging.h" | 22 #include "webrtc/base/logging.h" |
| 23 #include "webrtc/base/scoped_ref_ptr.h" | 23 #include "webrtc/base/scoped_ref_ptr.h" |
| 24 #include "webrtc/base/timeutils.h" |
| 24 #include "webrtc/modules/audio_device/audio_device_impl.h" | 25 #include "webrtc/modules/audio_device/audio_device_impl.h" |
| 25 #include "webrtc/modules/audio_device/include/audio_device.h" | 26 #include "webrtc/modules/audio_device/include/audio_device.h" |
| 26 #include "webrtc/modules/audio_device/include/mock_audio_transport.h" | 27 #include "webrtc/modules/audio_device/include/mock_audio_transport.h" |
| 27 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" | 28 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" |
| 28 #include "webrtc/system_wrappers/include/clock.h" | |
| 29 #include "webrtc/system_wrappers/include/event_wrapper.h" | 29 #include "webrtc/system_wrappers/include/event_wrapper.h" |
| 30 #include "webrtc/system_wrappers/include/sleep.h" | 30 #include "webrtc/system_wrappers/include/sleep.h" |
| 31 #include "webrtc/test/gmock.h" | 31 #include "webrtc/test/gmock.h" |
| 32 #include "webrtc/test/gtest.h" | 32 #include "webrtc/test/gtest.h" |
| 33 #include "webrtc/test/testsupport/fileutils.h" | 33 #include "webrtc/test/testsupport/fileutils.h" |
| 34 | 34 |
| 35 using std::cout; | 35 using std::cout; |
| 36 using std::endl; | 36 using std::endl; |
| 37 using ::testing::_; | 37 using ::testing::_; |
| 38 using ::testing::AtLeast; | 38 using ::testing::AtLeast; |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 size_t write_count_; | 240 size_t write_count_; |
| 241 }; | 241 }; |
| 242 | 242 |
| 243 // Inserts periodic impulses and measures the latency between the time of | 243 // Inserts periodic impulses and measures the latency between the time of |
| 244 // transmission and time of receiving the same impulse. | 244 // transmission and time of receiving the same impulse. |
| 245 // Usage requires a special hardware called Audio Loopback Dongle. | 245 // Usage requires a special hardware called Audio Loopback Dongle. |
| 246 // See http://source.android.com/devices/audio/loopback.html for details. | 246 // See http://source.android.com/devices/audio/loopback.html for details. |
| 247 class LatencyMeasuringAudioStream : public AudioStreamInterface { | 247 class LatencyMeasuringAudioStream : public AudioStreamInterface { |
| 248 public: | 248 public: |
| 249 explicit LatencyMeasuringAudioStream(size_t frames_per_buffer) | 249 explicit LatencyMeasuringAudioStream(size_t frames_per_buffer) |
| 250 : clock_(Clock::GetRealTimeClock()), | 250 : frames_per_buffer_(frames_per_buffer), |
| 251 frames_per_buffer_(frames_per_buffer), | |
| 252 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), | 251 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), |
| 253 play_count_(0), | 252 play_count_(0), |
| 254 rec_count_(0), | 253 rec_count_(0), |
| 255 pulse_time_(0) {} | 254 pulse_time_(0) {} |
| 256 | 255 |
| 257 // Insert periodic impulses in first two samples of |destination|. | 256 // Insert periodic impulses in first two samples of |destination|. |
| 258 void Read(void* destination, size_t num_frames) override { | 257 void Read(void* destination, size_t num_frames) override { |
| 259 ASSERT_EQ(num_frames, frames_per_buffer_); | 258 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 260 if (play_count_ == 0) { | 259 if (play_count_ == 0) { |
| 261 PRINT("["); | 260 PRINT("["); |
| 262 } | 261 } |
| 263 play_count_++; | 262 play_count_++; |
| 264 memset(destination, 0, bytes_per_buffer_); | 263 memset(destination, 0, bytes_per_buffer_); |
| 265 if (play_count_ % (kNumCallbacksPerSecond / kImpulseFrequencyInHz) == 0) { | 264 if (play_count_ % (kNumCallbacksPerSecond / kImpulseFrequencyInHz) == 0) { |
| 266 if (pulse_time_ == 0) { | 265 if (pulse_time_ == 0) { |
| 267 pulse_time_ = clock_->TimeInMilliseconds(); | 266 pulse_time_ = rtc::TimeMillis(); |
| 268 } | 267 } |
| 269 PRINT("."); | 268 PRINT("."); |
| 270 const int16_t impulse = std::numeric_limits<int16_t>::max(); | 269 const int16_t impulse = std::numeric_limits<int16_t>::max(); |
| 271 int16_t* ptr16 = static_cast<int16_t*>(destination); | 270 int16_t* ptr16 = static_cast<int16_t*>(destination); |
| 272 for (size_t i = 0; i < 2; ++i) { | 271 for (size_t i = 0; i < 2; ++i) { |
| 273 ptr16[i] = impulse; | 272 ptr16[i] = impulse; |
| 274 } | 273 } |
| 275 } | 274 } |
| 276 } | 275 } |
| 277 | 276 |
| 278 // Detect received impulses in |source|, derive time between transmission and | 277 // Detect received impulses in |source|, derive time between transmission and |
| 279 // detection and add the calculated delay to list of latencies. | 278 // detection and add the calculated delay to list of latencies. |
| 280 void Write(const void* source, size_t num_frames) override { | 279 void Write(const void* source, size_t num_frames) override { |
| 281 ASSERT_EQ(num_frames, frames_per_buffer_); | 280 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 282 rec_count_++; | 281 rec_count_++; |
| 283 if (pulse_time_ == 0) { | 282 if (pulse_time_ == 0) { |
| 284 // Avoid detection of new impulse response until a new impulse has | 283 // Avoid detection of new impulse response until a new impulse has |
| 285 // been transmitted (sets |pulse_time_| to value larger than zero). | 284 // been transmitted (sets |pulse_time_| to value larger than zero). |
| 286 return; | 285 return; |
| 287 } | 286 } |
| 288 const int16_t* ptr16 = static_cast<const int16_t*>(source); | 287 const int16_t* ptr16 = static_cast<const int16_t*>(source); |
| 289 std::vector<int16_t> vec(ptr16, ptr16 + num_frames); | 288 std::vector<int16_t> vec(ptr16, ptr16 + num_frames); |
| 290 // Find max value in the audio buffer. | 289 // Find max value in the audio buffer. |
| 291 int max = *std::max_element(vec.begin(), vec.end()); | 290 int max = *std::max_element(vec.begin(), vec.end()); |
| 292 // Find index (element position in vector) of the max element. | 291 // Find index (element position in vector) of the max element. |
| 293 int index_of_max = | 292 int index_of_max = |
| 294 std::distance(vec.begin(), std::find(vec.begin(), vec.end(), max)); | 293 std::distance(vec.begin(), std::find(vec.begin(), vec.end(), max)); |
| 295 if (max > kImpulseThreshold) { | 294 if (max > kImpulseThreshold) { |
| 296 PRINTD("(%d,%d)", max, index_of_max); | 295 PRINTD("(%d,%d)", max, index_of_max); |
| 297 int64_t now_time = clock_->TimeInMilliseconds(); | 296 int64_t now_time = rtc::TimeMillis(); |
| 298 int extra_delay = IndexToMilliseconds(static_cast<double>(index_of_max)); | 297 int extra_delay = IndexToMilliseconds(static_cast<double>(index_of_max)); |
| 299 PRINTD("[%d]", static_cast<int>(now_time - pulse_time_)); | 298 PRINTD("[%d]", static_cast<int>(now_time - pulse_time_)); |
| 300 PRINTD("[%d]", extra_delay); | 299 PRINTD("[%d]", extra_delay); |
| 301 // Total latency is the difference between transmit time and detection | 300 // Total latency is the difference between transmit time and detection |
| 302 // tome plus the extra delay within the buffer in which we detected the | 301 // tome plus the extra delay within the buffer in which we detected the |
| 303 // received impulse. It is transmitted at sample 0 but can be received | 302 // received impulse. It is transmitted at sample 0 but can be received |
| 304 // at sample N where N > 0. The term |extra_delay| accounts for N and it | 303 // at sample N where N > 0. The term |extra_delay| accounts for N and it |
| 305 // is a value between 0 and 10ms. | 304 // is a value between 0 and 10ms. |
| 306 latencies_.push_back(now_time - pulse_time_ + extra_delay); | 305 latencies_.push_back(now_time - pulse_time_ + extra_delay); |
| 307 pulse_time_ = 0; | 306 pulse_time_ = 0; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 PRINT("\n"); | 340 PRINT("\n"); |
| 342 PRINT("%s[min, max, avg]=[%d, %d, %d] ms\n", kTag, min_latency(), | 341 PRINT("%s[min, max, avg]=[%d, %d, %d] ms\n", kTag, min_latency(), |
| 343 max_latency(), average_latency()); | 342 max_latency(), average_latency()); |
| 344 } | 343 } |
| 345 | 344 |
| 346 int IndexToMilliseconds(double index) const { | 345 int IndexToMilliseconds(double index) const { |
| 347 return 10.0 * (index / frames_per_buffer_) + 0.5; | 346 return 10.0 * (index / frames_per_buffer_) + 0.5; |
| 348 } | 347 } |
| 349 | 348 |
| 350 private: | 349 private: |
| 351 Clock* clock_; | |
| 352 const size_t frames_per_buffer_; | 350 const size_t frames_per_buffer_; |
| 353 const size_t bytes_per_buffer_; | 351 const size_t bytes_per_buffer_; |
| 354 size_t play_count_; | 352 size_t play_count_; |
| 355 size_t rec_count_; | 353 size_t rec_count_; |
| 356 int64_t pulse_time_; | 354 int64_t pulse_time_; |
| 357 std::vector<int> latencies_; | 355 std::vector<int> latencies_; |
| 358 }; | 356 }; |
| 359 // Mocks the AudioTransport object and proxies actions for the two callbacks | 357 // Mocks the AudioTransport object and proxies actions for the two callbacks |
| 360 // (RecordedDataIsAvailable and NeedMorePlayData) to different implementations | 358 // (RecordedDataIsAvailable and NeedMorePlayData) to different implementations |
| 361 // of AudioStreamInterface. | 359 // of AudioStreamInterface. |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 815 StopPlayout(); | 813 StopPlayout(); |
| 816 StopRecording(); | 814 StopRecording(); |
| 817 // Verify that the correct number of transmitted impulses are detected. | 815 // Verify that the correct number of transmitted impulses are detected. |
| 818 EXPECT_EQ(latency_audio_stream->num_latency_values(), | 816 EXPECT_EQ(latency_audio_stream->num_latency_values(), |
| 819 static_cast<size_t>( | 817 static_cast<size_t>( |
| 820 kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1)); | 818 kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1)); |
| 821 latency_audio_stream->PrintResults(); | 819 latency_audio_stream->PrintResults(); |
| 822 } | 820 } |
| 823 | 821 |
| 824 } // namespace webrtc | 822 } // namespace webrtc |
| OLD | NEW |