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 |