| 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 <numeric> | 14 #include <numeric> |
| 15 #include <string> | 15 #include <string> |
| 16 #include <vector> | 16 #include <vector> |
| 17 | 17 |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 #include "webrtc/base/arraysize.h" | 20 #include "webrtc/base/arraysize.h" |
| 21 #include "webrtc/base/criticalsection.h" | 21 #include "webrtc/base/criticalsection.h" |
| 22 #include "webrtc/base/format_macros.h" |
| 22 #include "webrtc/base/logging.h" | 23 #include "webrtc/base/logging.h" |
| 23 #include "webrtc/base/scoped_ptr.h" | 24 #include "webrtc/base/scoped_ptr.h" |
| 24 #include "webrtc/base/scoped_ref_ptr.h" | 25 #include "webrtc/base/scoped_ref_ptr.h" |
| 25 #include "webrtc/modules/audio_device/audio_device_impl.h" | 26 #include "webrtc/modules/audio_device/audio_device_impl.h" |
| 26 #include "webrtc/modules/audio_device/include/audio_device.h" | 27 #include "webrtc/modules/audio_device/include/audio_device.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/interface/clock.h" | 29 #include "webrtc/system_wrappers/interface/clock.h" |
| 29 #include "webrtc/system_wrappers/interface/event_wrapper.h" | 30 #include "webrtc/system_wrappers/interface/event_wrapper.h" |
| 30 #include "webrtc/system_wrappers/interface/sleep.h" | 31 #include "webrtc/system_wrappers/interface/sleep.h" |
| 31 #include "webrtc/test/testsupport/fileutils.h" | 32 #include "webrtc/test/testsupport/fileutils.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 45 #define PRINTD(...) fprintf(stderr, __VA_ARGS__); | 46 #define PRINTD(...) fprintf(stderr, __VA_ARGS__); |
| 46 #else | 47 #else |
| 47 #define PRINTD(...) ((void)0) | 48 #define PRINTD(...) ((void)0) |
| 48 #endif | 49 #endif |
| 49 #define PRINT(...) fprintf(stderr, __VA_ARGS__); | 50 #define PRINT(...) fprintf(stderr, __VA_ARGS__); |
| 50 | 51 |
| 51 namespace webrtc { | 52 namespace webrtc { |
| 52 | 53 |
| 53 // Number of callbacks (input or output) the tests waits for before we set | 54 // Number of callbacks (input or output) the tests waits for before we set |
| 54 // an event indicating that the test was OK. | 55 // an event indicating that the test was OK. |
| 55 static const int kNumCallbacks = 10; | 56 static const size_t kNumCallbacks = 10; |
| 56 // Max amount of time we wait for an event to be set while counting callbacks. | 57 // Max amount of time we wait for an event to be set while counting callbacks. |
| 57 static const int kTestTimeOutInMilliseconds = 10 * 1000; | 58 static const int kTestTimeOutInMilliseconds = 10 * 1000; |
| 58 // Number of bits per PCM audio sample. | 59 // Number of bits per PCM audio sample. |
| 59 static const int kBitsPerSample = 16; | 60 static const size_t kBitsPerSample = 16; |
| 60 // Number of bytes per PCM audio sample. | 61 // Number of bytes per PCM audio sample. |
| 61 static const int kBytesPerSample = kBitsPerSample / 8; | 62 static const size_t kBytesPerSample = kBitsPerSample / 8; |
| 62 // Average number of audio callbacks per second assuming 10ms packet size. | 63 // Average number of audio callbacks per second assuming 10ms packet size. |
| 63 static const int kNumCallbacksPerSecond = 100; | 64 static const size_t kNumCallbacksPerSecond = 100; |
| 64 // Play out a test file during this time (unit is in seconds). | 65 // Play out a test file during this time (unit is in seconds). |
| 65 static const int kFilePlayTimeInSec = 15; | 66 static const int kFilePlayTimeInSec = 15; |
| 66 // Run the full-duplex test during this time (unit is in seconds). | 67 // Run the full-duplex test during this time (unit is in seconds). |
| 67 // Note that first |kNumIgnoreFirstCallbacks| are ignored. | 68 // Note that first |kNumIgnoreFirstCallbacks| are ignored. |
| 68 static const int kFullDuplexTimeInSec = 10; | 69 static const int kFullDuplexTimeInSec = 10; |
| 69 // Wait for the callback sequence to stabilize by ignoring this amount of the | 70 // Wait for the callback sequence to stabilize by ignoring this amount of the |
| 70 // initial callbacks (avoids initial FIFO access). | 71 // initial callbacks (avoids initial FIFO access). |
| 71 // Only used in the RunPlayoutAndRecordingInFullDuplex test. | 72 // Only used in the RunPlayoutAndRecordingInFullDuplex test. |
| 72 static const int kNumIgnoreFirstCallbacks = 50; | 73 static const size_t kNumIgnoreFirstCallbacks = 50; |
| 73 // Sets the number of impulses per second in the latency test. | 74 // Sets the number of impulses per second in the latency test. |
| 74 // TODO(henrika): fine tune this setting for iOS. | 75 // TODO(henrika): fine tune this setting for iOS. |
| 75 static const int kImpulseFrequencyInHz = 1; | 76 static const int kImpulseFrequencyInHz = 1; |
| 76 // Length of round-trip latency measurements. Number of transmitted impulses | 77 // Length of round-trip latency measurements. Number of transmitted impulses |
| 77 // is kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1. | 78 // is kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1. |
| 78 // TODO(henrika): fine tune this setting for iOS. | 79 // TODO(henrika): fine tune this setting for iOS. |
| 79 static const int kMeasureLatencyTimeInSec = 5; | 80 static const int kMeasureLatencyTimeInSec = 5; |
| 80 // Utilized in round-trip latency measurements to avoid capturing noise samples. | 81 // Utilized in round-trip latency measurements to avoid capturing noise samples. |
| 81 // TODO(henrika): fine tune this setting for iOS. | 82 // TODO(henrika): fine tune this setting for iOS. |
| 82 static const int kImpulseThreshold = 50; | 83 static const int kImpulseThreshold = 50; |
| 83 static const char kTag[] = "[..........] "; | 84 static const char kTag[] = "[..........] "; |
| 84 | 85 |
| 85 enum TransportType { | 86 enum TransportType { |
| 86 kPlayout = 0x1, | 87 kPlayout = 0x1, |
| 87 kRecording = 0x2, | 88 kRecording = 0x2, |
| 88 }; | 89 }; |
| 89 | 90 |
| 90 // Interface for processing the audio stream. Real implementations can e.g. | 91 // Interface for processing the audio stream. Real implementations can e.g. |
| 91 // run audio in loopback, read audio from a file or perform latency | 92 // run audio in loopback, read audio from a file or perform latency |
| 92 // measurements. | 93 // measurements. |
| 93 class AudioStreamInterface { | 94 class AudioStreamInterface { |
| 94 public: | 95 public: |
| 95 virtual void Write(const void* source, int num_frames) = 0; | 96 virtual void Write(const void* source, size_t num_frames) = 0; |
| 96 virtual void Read(void* destination, int num_frames) = 0; | 97 virtual void Read(void* destination, size_t num_frames) = 0; |
| 97 | 98 |
| 98 protected: | 99 protected: |
| 99 virtual ~AudioStreamInterface() {} | 100 virtual ~AudioStreamInterface() {} |
| 100 }; | 101 }; |
| 101 | 102 |
| 102 // Reads audio samples from a PCM file where the file is stored in memory at | 103 // Reads audio samples from a PCM file where the file is stored in memory at |
| 103 // construction. | 104 // construction. |
| 104 class FileAudioStream : public AudioStreamInterface { | 105 class FileAudioStream : public AudioStreamInterface { |
| 105 public: | 106 public: |
| 106 FileAudioStream(int num_callbacks, | 107 FileAudioStream(size_t num_callbacks, |
| 107 const std::string& file_name, | 108 const std::string& file_name, |
| 108 int sample_rate) | 109 int sample_rate) |
| 109 : file_size_in_bytes_(0), sample_rate_(sample_rate), file_pos_(0) { | 110 : file_size_in_bytes_(0), sample_rate_(sample_rate), file_pos_(0) { |
| 110 file_size_in_bytes_ = test::GetFileSize(file_name); | 111 file_size_in_bytes_ = test::GetFileSize(file_name); |
| 111 sample_rate_ = sample_rate; | 112 sample_rate_ = sample_rate; |
| 112 EXPECT_GE(file_size_in_callbacks(), num_callbacks) | 113 EXPECT_GE(file_size_in_callbacks(), num_callbacks) |
| 113 << "Size of test file is not large enough to last during the test."; | 114 << "Size of test file is not large enough to last during the test."; |
| 114 const int num_16bit_samples = | 115 const size_t num_16bit_samples = |
| 115 test::GetFileSize(file_name) / kBytesPerSample; | 116 test::GetFileSize(file_name) / kBytesPerSample; |
| 116 file_.reset(new int16_t[num_16bit_samples]); | 117 file_.reset(new int16_t[num_16bit_samples]); |
| 117 FILE* audio_file = fopen(file_name.c_str(), "rb"); | 118 FILE* audio_file = fopen(file_name.c_str(), "rb"); |
| 118 EXPECT_NE(audio_file, nullptr); | 119 EXPECT_NE(audio_file, nullptr); |
| 119 int num_samples_read = | 120 size_t num_samples_read = |
| 120 fread(file_.get(), sizeof(int16_t), num_16bit_samples, audio_file); | 121 fread(file_.get(), sizeof(int16_t), num_16bit_samples, audio_file); |
| 121 EXPECT_EQ(num_samples_read, num_16bit_samples); | 122 EXPECT_EQ(num_samples_read, num_16bit_samples); |
| 122 fclose(audio_file); | 123 fclose(audio_file); |
| 123 } | 124 } |
| 124 | 125 |
| 125 // AudioStreamInterface::Write() is not implemented. | 126 // AudioStreamInterface::Write() is not implemented. |
| 126 void Write(const void* source, int num_frames) override {} | 127 void Write(const void* source, size_t num_frames) override {} |
| 127 | 128 |
| 128 // Read samples from file stored in memory (at construction) and copy | 129 // Read samples from file stored in memory (at construction) and copy |
| 129 // |num_frames| (<=> 10ms) to the |destination| byte buffer. | 130 // |num_frames| (<=> 10ms) to the |destination| byte buffer. |
| 130 void Read(void* destination, int num_frames) override { | 131 void Read(void* destination, size_t num_frames) override { |
| 131 memcpy(destination, static_cast<int16_t*>(&file_[file_pos_]), | 132 memcpy(destination, static_cast<int16_t*>(&file_[file_pos_]), |
| 132 num_frames * sizeof(int16_t)); | 133 num_frames * sizeof(int16_t)); |
| 133 file_pos_ += num_frames; | 134 file_pos_ += num_frames; |
| 134 } | 135 } |
| 135 | 136 |
| 136 int file_size_in_seconds() const { | 137 int file_size_in_seconds() const { |
| 137 return (file_size_in_bytes_ / (kBytesPerSample * sample_rate_)); | 138 return static_cast<int>( |
| 139 file_size_in_bytes_ / (kBytesPerSample * sample_rate_)); |
| 138 } | 140 } |
| 139 int file_size_in_callbacks() const { | 141 size_t file_size_in_callbacks() const { |
| 140 return file_size_in_seconds() * kNumCallbacksPerSecond; | 142 return file_size_in_seconds() * kNumCallbacksPerSecond; |
| 141 } | 143 } |
| 142 | 144 |
| 143 private: | 145 private: |
| 144 int file_size_in_bytes_; | 146 size_t file_size_in_bytes_; |
| 145 int sample_rate_; | 147 int sample_rate_; |
| 146 rtc::scoped_ptr<int16_t[]> file_; | 148 rtc::scoped_ptr<int16_t[]> file_; |
| 147 int file_pos_; | 149 size_t file_pos_; |
| 148 }; | 150 }; |
| 149 | 151 |
| 150 // Simple first in first out (FIFO) class that wraps a list of 16-bit audio | 152 // Simple first in first out (FIFO) class that wraps a list of 16-bit audio |
| 151 // buffers of fixed size and allows Write and Read operations. The idea is to | 153 // buffers of fixed size and allows Write and Read operations. The idea is to |
| 152 // store recorded audio buffers (using Write) and then read (using Read) these | 154 // store recorded audio buffers (using Write) and then read (using Read) these |
| 153 // stored buffers with as short delay as possible when the audio layer needs | 155 // stored buffers with as short delay as possible when the audio layer needs |
| 154 // data to play out. The number of buffers in the FIFO will stabilize under | 156 // data to play out. The number of buffers in the FIFO will stabilize under |
| 155 // normal conditions since there will be a balance between Write and Read calls. | 157 // normal conditions since there will be a balance between Write and Read calls. |
| 156 // The container is a std::list container and access is protected with a lock | 158 // The container is a std::list container and access is protected with a lock |
| 157 // since both sides (playout and recording) are driven by its own thread. | 159 // since both sides (playout and recording) are driven by its own thread. |
| 158 class FifoAudioStream : public AudioStreamInterface { | 160 class FifoAudioStream : public AudioStreamInterface { |
| 159 public: | 161 public: |
| 160 explicit FifoAudioStream(int frames_per_buffer) | 162 explicit FifoAudioStream(size_t frames_per_buffer) |
| 161 : frames_per_buffer_(frames_per_buffer), | 163 : frames_per_buffer_(frames_per_buffer), |
| 162 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), | 164 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), |
| 163 fifo_(new AudioBufferList), | 165 fifo_(new AudioBufferList), |
| 164 largest_size_(0), | 166 largest_size_(0), |
| 165 total_written_elements_(0), | 167 total_written_elements_(0), |
| 166 write_count_(0) { | 168 write_count_(0) { |
| 167 EXPECT_NE(fifo_.get(), nullptr); | 169 EXPECT_NE(fifo_.get(), nullptr); |
| 168 } | 170 } |
| 169 | 171 |
| 170 ~FifoAudioStream() { Flush(); } | 172 ~FifoAudioStream() { Flush(); } |
| 171 | 173 |
| 172 // Allocate new memory, copy |num_frames| samples from |source| into memory | 174 // Allocate new memory, copy |num_frames| samples from |source| into memory |
| 173 // and add pointer to the memory location to end of the list. | 175 // and add pointer to the memory location to end of the list. |
| 174 // Increases the size of the FIFO by one element. | 176 // Increases the size of the FIFO by one element. |
| 175 void Write(const void* source, int num_frames) override { | 177 void Write(const void* source, size_t num_frames) override { |
| 176 ASSERT_EQ(num_frames, frames_per_buffer_); | 178 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 177 PRINTD("+"); | 179 PRINTD("+"); |
| 178 if (write_count_++ < kNumIgnoreFirstCallbacks) { | 180 if (write_count_++ < kNumIgnoreFirstCallbacks) { |
| 179 return; | 181 return; |
| 180 } | 182 } |
| 181 int16_t* memory = new int16_t[frames_per_buffer_]; | 183 int16_t* memory = new int16_t[frames_per_buffer_]; |
| 182 memcpy(static_cast<int16_t*>(&memory[0]), source, bytes_per_buffer_); | 184 memcpy(static_cast<int16_t*>(&memory[0]), source, bytes_per_buffer_); |
| 183 rtc::CritScope lock(&lock_); | 185 rtc::CritScope lock(&lock_); |
| 184 fifo_->push_back(memory); | 186 fifo_->push_back(memory); |
| 185 const int size = fifo_->size(); | 187 const size_t size = fifo_->size(); |
| 186 if (size > largest_size_) { | 188 if (size > largest_size_) { |
| 187 largest_size_ = size; | 189 largest_size_ = size; |
| 188 PRINTD("(%d)", largest_size_); | 190 PRINTD("(%" PRIuS ")", largest_size_); |
| 189 } | 191 } |
| 190 total_written_elements_ += size; | 192 total_written_elements_ += size; |
| 191 } | 193 } |
| 192 | 194 |
| 193 // Read pointer to data buffer from front of list, copy |num_frames| of stored | 195 // Read pointer to data buffer from front of list, copy |num_frames| of stored |
| 194 // data into |destination| and delete the utilized memory allocation. | 196 // data into |destination| and delete the utilized memory allocation. |
| 195 // Decreases the size of the FIFO by one element. | 197 // Decreases the size of the FIFO by one element. |
| 196 void Read(void* destination, int num_frames) override { | 198 void Read(void* destination, size_t num_frames) override { |
| 197 ASSERT_EQ(num_frames, frames_per_buffer_); | 199 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 198 PRINTD("-"); | 200 PRINTD("-"); |
| 199 rtc::CritScope lock(&lock_); | 201 rtc::CritScope lock(&lock_); |
| 200 if (fifo_->empty()) { | 202 if (fifo_->empty()) { |
| 201 memset(destination, 0, bytes_per_buffer_); | 203 memset(destination, 0, bytes_per_buffer_); |
| 202 } else { | 204 } else { |
| 203 int16_t* memory = fifo_->front(); | 205 int16_t* memory = fifo_->front(); |
| 204 fifo_->pop_front(); | 206 fifo_->pop_front(); |
| 205 memcpy(destination, static_cast<int16_t*>(&memory[0]), bytes_per_buffer_); | 207 memcpy(destination, static_cast<int16_t*>(&memory[0]), bytes_per_buffer_); |
| 206 delete memory; | 208 delete memory; |
| 207 } | 209 } |
| 208 } | 210 } |
| 209 | 211 |
| 210 int size() const { return fifo_->size(); } | 212 size_t size() const { return fifo_->size(); } |
| 211 | 213 |
| 212 int largest_size() const { return largest_size_; } | 214 size_t largest_size() const { return largest_size_; } |
| 213 | 215 |
| 214 int average_size() const { | 216 size_t average_size() const { |
| 215 return (total_written_elements_ == 0) | 217 return (total_written_elements_ == 0) |
| 216 ? 0.0 | 218 ? 0.0 |
| 217 : 0.5 + | 219 : 0.5 + |
| 218 static_cast<float>(total_written_elements_) / | 220 static_cast<float>(total_written_elements_) / |
| 219 (write_count_ - kNumIgnoreFirstCallbacks); | 221 (write_count_ - kNumIgnoreFirstCallbacks); |
| 220 } | 222 } |
| 221 | 223 |
| 222 private: | 224 private: |
| 223 void Flush() { | 225 void Flush() { |
| 224 for (auto it = fifo_->begin(); it != fifo_->end(); ++it) { | 226 for (auto it = fifo_->begin(); it != fifo_->end(); ++it) { |
| 225 delete *it; | 227 delete *it; |
| 226 } | 228 } |
| 227 fifo_->clear(); | 229 fifo_->clear(); |
| 228 } | 230 } |
| 229 | 231 |
| 230 using AudioBufferList = std::list<int16_t*>; | 232 using AudioBufferList = std::list<int16_t*>; |
| 231 rtc::CriticalSection lock_; | 233 rtc::CriticalSection lock_; |
| 232 const int frames_per_buffer_; | 234 const size_t frames_per_buffer_; |
| 233 const int bytes_per_buffer_; | 235 const size_t bytes_per_buffer_; |
| 234 rtc::scoped_ptr<AudioBufferList> fifo_; | 236 rtc::scoped_ptr<AudioBufferList> fifo_; |
| 235 int largest_size_; | 237 size_t largest_size_; |
| 236 int total_written_elements_; | 238 size_t total_written_elements_; |
| 237 int write_count_; | 239 size_t write_count_; |
| 238 }; | 240 }; |
| 239 | 241 |
| 240 // Inserts periodic impulses and measures the latency between the time of | 242 // Inserts periodic impulses and measures the latency between the time of |
| 241 // transmission and time of receiving the same impulse. | 243 // transmission and time of receiving the same impulse. |
| 242 // Usage requires a special hardware called Audio Loopback Dongle. | 244 // Usage requires a special hardware called Audio Loopback Dongle. |
| 243 // See http://source.android.com/devices/audio/loopback.html for details. | 245 // See http://source.android.com/devices/audio/loopback.html for details. |
| 244 class LatencyMeasuringAudioStream : public AudioStreamInterface { | 246 class LatencyMeasuringAudioStream : public AudioStreamInterface { |
| 245 public: | 247 public: |
| 246 explicit LatencyMeasuringAudioStream(int frames_per_buffer) | 248 explicit LatencyMeasuringAudioStream(size_t frames_per_buffer) |
| 247 : clock_(Clock::GetRealTimeClock()), | 249 : clock_(Clock::GetRealTimeClock()), |
| 248 frames_per_buffer_(frames_per_buffer), | 250 frames_per_buffer_(frames_per_buffer), |
| 249 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), | 251 bytes_per_buffer_(frames_per_buffer_ * sizeof(int16_t)), |
| 250 play_count_(0), | 252 play_count_(0), |
| 251 rec_count_(0), | 253 rec_count_(0), |
| 252 pulse_time_(0) {} | 254 pulse_time_(0) {} |
| 253 | 255 |
| 254 // Insert periodic impulses in first two samples of |destination|. | 256 // Insert periodic impulses in first two samples of |destination|. |
| 255 void Read(void* destination, int num_frames) override { | 257 void Read(void* destination, size_t num_frames) override { |
| 256 ASSERT_EQ(num_frames, frames_per_buffer_); | 258 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 257 if (play_count_ == 0) { | 259 if (play_count_ == 0) { |
| 258 PRINT("["); | 260 PRINT("["); |
| 259 } | 261 } |
| 260 play_count_++; | 262 play_count_++; |
| 261 memset(destination, 0, bytes_per_buffer_); | 263 memset(destination, 0, bytes_per_buffer_); |
| 262 if (play_count_ % (kNumCallbacksPerSecond / kImpulseFrequencyInHz) == 0) { | 264 if (play_count_ % (kNumCallbacksPerSecond / kImpulseFrequencyInHz) == 0) { |
| 263 if (pulse_time_ == 0) { | 265 if (pulse_time_ == 0) { |
| 264 pulse_time_ = clock_->TimeInMilliseconds(); | 266 pulse_time_ = clock_->TimeInMilliseconds(); |
| 265 } | 267 } |
| 266 PRINT("."); | 268 PRINT("."); |
| 267 const int16_t impulse = std::numeric_limits<int16_t>::max(); | 269 const int16_t impulse = std::numeric_limits<int16_t>::max(); |
| 268 int16_t* ptr16 = static_cast<int16_t*>(destination); | 270 int16_t* ptr16 = static_cast<int16_t*>(destination); |
| 269 for (int i = 0; i < 2; ++i) { | 271 for (size_t i = 0; i < 2; ++i) { |
| 270 *ptr16++ = impulse; | 272 ptr16[i] = impulse; |
| 271 } | 273 } |
| 272 } | 274 } |
| 273 } | 275 } |
| 274 | 276 |
| 275 // Detect received impulses in |source|, derive time between transmission and | 277 // Detect received impulses in |source|, derive time between transmission and |
| 276 // detection and add the calculated delay to list of latencies. | 278 // detection and add the calculated delay to list of latencies. |
| 277 void Write(const void* source, int num_frames) override { | 279 void Write(const void* source, size_t num_frames) override { |
| 278 ASSERT_EQ(num_frames, frames_per_buffer_); | 280 ASSERT_EQ(num_frames, frames_per_buffer_); |
| 279 rec_count_++; | 281 rec_count_++; |
| 280 if (pulse_time_ == 0) { | 282 if (pulse_time_ == 0) { |
| 281 // Avoid detection of new impulse response until a new impulse has | 283 // Avoid detection of new impulse response until a new impulse has |
| 282 // been transmitted (sets |pulse_time_| to value larger than zero). | 284 // been transmitted (sets |pulse_time_| to value larger than zero). |
| 283 return; | 285 return; |
| 284 } | 286 } |
| 285 const int16_t* ptr16 = static_cast<const int16_t*>(source); | 287 const int16_t* ptr16 = static_cast<const int16_t*>(source); |
| 286 std::vector<int16_t> vec(ptr16, ptr16 + num_frames); | 288 std::vector<int16_t> vec(ptr16, ptr16 + num_frames); |
| 287 // Find max value in the audio buffer. | 289 // Find max value in the audio buffer. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 300 // 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 |
| 301 // 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 |
| 302 // is a value between 0 and 10ms. | 304 // is a value between 0 and 10ms. |
| 303 latencies_.push_back(now_time - pulse_time_ + extra_delay); | 305 latencies_.push_back(now_time - pulse_time_ + extra_delay); |
| 304 pulse_time_ = 0; | 306 pulse_time_ = 0; |
| 305 } else { | 307 } else { |
| 306 PRINTD("-"); | 308 PRINTD("-"); |
| 307 } | 309 } |
| 308 } | 310 } |
| 309 | 311 |
| 310 int num_latency_values() const { return latencies_.size(); } | 312 size_t num_latency_values() const { return latencies_.size(); } |
| 311 | 313 |
| 312 int min_latency() const { | 314 int min_latency() const { |
| 313 if (latencies_.empty()) | 315 if (latencies_.empty()) |
| 314 return 0; | 316 return 0; |
| 315 return *std::min_element(latencies_.begin(), latencies_.end()); | 317 return *std::min_element(latencies_.begin(), latencies_.end()); |
| 316 } | 318 } |
| 317 | 319 |
| 318 int max_latency() const { | 320 int max_latency() const { |
| 319 if (latencies_.empty()) | 321 if (latencies_.empty()) |
| 320 return 0; | 322 return 0; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 339 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(), |
| 340 max_latency(), average_latency()); | 342 max_latency(), average_latency()); |
| 341 } | 343 } |
| 342 | 344 |
| 343 int IndexToMilliseconds(double index) const { | 345 int IndexToMilliseconds(double index) const { |
| 344 return 10.0 * (index / frames_per_buffer_) + 0.5; | 346 return 10.0 * (index / frames_per_buffer_) + 0.5; |
| 345 } | 347 } |
| 346 | 348 |
| 347 private: | 349 private: |
| 348 Clock* clock_; | 350 Clock* clock_; |
| 349 const int frames_per_buffer_; | 351 const size_t frames_per_buffer_; |
| 350 const int bytes_per_buffer_; | 352 const size_t bytes_per_buffer_; |
| 351 int play_count_; | 353 size_t play_count_; |
| 352 int rec_count_; | 354 size_t rec_count_; |
| 353 int64_t pulse_time_; | 355 int64_t pulse_time_; |
| 354 std::vector<int> latencies_; | 356 std::vector<int> latencies_; |
| 355 }; | 357 }; |
| 356 // Mocks the AudioTransport object and proxies actions for the two callbacks | 358 // Mocks the AudioTransport object and proxies actions for the two callbacks |
| 357 // (RecordedDataIsAvailable and NeedMorePlayData) to different implementations | 359 // (RecordedDataIsAvailable and NeedMorePlayData) to different implementations |
| 358 // of AudioStreamInterface. | 360 // of AudioStreamInterface. |
| 359 class MockAudioTransport : public AudioTransport { | 361 class MockAudioTransport : public AudioTransport { |
| 360 public: | 362 public: |
| 361 explicit MockAudioTransport(int type) | 363 explicit MockAudioTransport(int type) |
| 362 : num_callbacks_(0), | 364 : num_callbacks_(0), |
| 363 type_(type), | 365 type_(type), |
| 364 play_count_(0), | 366 play_count_(0), |
| 365 rec_count_(0), | 367 rec_count_(0), |
| 366 audio_stream_(nullptr) {} | 368 audio_stream_(nullptr) {} |
| 367 | 369 |
| 368 virtual ~MockAudioTransport() {} | 370 virtual ~MockAudioTransport() {} |
| 369 | 371 |
| 370 MOCK_METHOD10(RecordedDataIsAvailable, | 372 MOCK_METHOD10(RecordedDataIsAvailable, |
| 371 int32_t(const void* audioSamples, | 373 int32_t(const void* audioSamples, |
| 372 const uint32_t nSamples, | 374 size_t uint32_t nSamples, |
| 373 const uint8_t nBytesPerSample, | 375 size_t uint8_t nBytesPerSample, |
| 374 const uint8_t nChannels, | 376 const uint8_t nChannels, |
| 375 const uint32_t samplesPerSec, | 377 const uint32_t samplesPerSec, |
| 376 const uint32_t totalDelayMS, | 378 const uint32_t totalDelayMS, |
| 377 const int32_t clockDrift, | 379 const int32_t clockDrift, |
| 378 const uint32_t currentMicLevel, | 380 const uint32_t currentMicLevel, |
| 379 const bool keyPressed, | 381 const bool keyPressed, |
| 380 uint32_t& newMicLevel)); | 382 uint32_t& newMicLevel)); |
| 381 MOCK_METHOD8(NeedMorePlayData, | 383 MOCK_METHOD8(NeedMorePlayData, |
| 382 int32_t(const uint32_t nSamples, | 384 int32_t(size_t uint32_t nSamples, |
| 383 const uint8_t nBytesPerSample, | 385 size_t uint8_t nBytesPerSample, |
| 384 const uint8_t nChannels, | 386 const uint8_t nChannels, |
| 385 const uint32_t samplesPerSec, | 387 const uint32_t samplesPerSec, |
| 386 void* audioSamples, | 388 void* audioSamples, |
| 387 uint32_t& nSamplesOut, | 389 size_t& nSamplesOut, |
| 388 int64_t* elapsed_time_ms, | 390 int64_t* elapsed_time_ms, |
| 389 int64_t* ntp_time_ms)); | 391 int64_t* ntp_time_ms)); |
| 390 | 392 |
| 391 // Set default actions of the mock object. We are delegating to fake | 393 // Set default actions of the mock object. We are delegating to fake |
| 392 // implementations (of AudioStreamInterface) here. | 394 // implementations (of AudioStreamInterface) here. |
| 393 void HandleCallbacks(EventWrapper* test_is_done, | 395 void HandleCallbacks(EventWrapper* test_is_done, |
| 394 AudioStreamInterface* audio_stream, | 396 AudioStreamInterface* audio_stream, |
| 395 int num_callbacks) { | 397 size_t num_callbacks) { |
| 396 test_is_done_ = test_is_done; | 398 test_is_done_ = test_is_done; |
| 397 audio_stream_ = audio_stream; | 399 audio_stream_ = audio_stream; |
| 398 num_callbacks_ = num_callbacks; | 400 num_callbacks_ = num_callbacks; |
| 399 if (play_mode()) { | 401 if (play_mode()) { |
| 400 ON_CALL(*this, NeedMorePlayData(_, _, _, _, _, _, _, _)) | 402 ON_CALL(*this, NeedMorePlayData(_, _, _, _, _, _, _, _)) |
| 401 .WillByDefault( | 403 .WillByDefault( |
| 402 Invoke(this, &MockAudioTransport::RealNeedMorePlayData)); | 404 Invoke(this, &MockAudioTransport::RealNeedMorePlayData)); |
| 403 } | 405 } |
| 404 if (rec_mode()) { | 406 if (rec_mode()) { |
| 405 ON_CALL(*this, RecordedDataIsAvailable(_, _, _, _, _, _, _, _, _, _)) | 407 ON_CALL(*this, RecordedDataIsAvailable(_, _, _, _, _, _, _, _, _, _)) |
| 406 .WillByDefault( | 408 .WillByDefault( |
| 407 Invoke(this, &MockAudioTransport::RealRecordedDataIsAvailable)); | 409 Invoke(this, &MockAudioTransport::RealRecordedDataIsAvailable)); |
| 408 } | 410 } |
| 409 } | 411 } |
| 410 | 412 |
| 411 int32_t RealRecordedDataIsAvailable(const void* audioSamples, | 413 int32_t RealRecordedDataIsAvailable(const void* audioSamples, |
| 412 const uint32_t nSamples, | 414 size_t uint32_t nSamples, |
| 413 const uint8_t nBytesPerSample, | 415 size_t uint8_t nBytesPerSample, |
| 414 const uint8_t nChannels, | 416 const uint8_t nChannels, |
| 415 const uint32_t samplesPerSec, | 417 const uint32_t samplesPerSec, |
| 416 const uint32_t totalDelayMS, | 418 const uint32_t totalDelayMS, |
| 417 const int32_t clockDrift, | 419 const int32_t clockDrift, |
| 418 const uint32_t currentMicLevel, | 420 const uint32_t currentMicLevel, |
| 419 const bool keyPressed, | 421 const bool keyPressed, |
| 420 uint32_t& newMicLevel) { | 422 uint32_t& newMicLevel) { |
| 421 EXPECT_TRUE(rec_mode()) << "No test is expecting these callbacks."; | 423 EXPECT_TRUE(rec_mode()) << "No test is expecting these callbacks."; |
| 422 rec_count_++; | 424 rec_count_++; |
| 423 // Process the recorded audio stream if an AudioStreamInterface | 425 // Process the recorded audio stream if an AudioStreamInterface |
| 424 // implementation exists. | 426 // implementation exists. |
| 425 if (audio_stream_) { | 427 if (audio_stream_) { |
| 426 audio_stream_->Write(audioSamples, nSamples); | 428 audio_stream_->Write(audioSamples, nSamples); |
| 427 } | 429 } |
| 428 if (ReceivedEnoughCallbacks()) { | 430 if (ReceivedEnoughCallbacks()) { |
| 429 test_is_done_->Set(); | 431 test_is_done_->Set(); |
| 430 } | 432 } |
| 431 return 0; | 433 return 0; |
| 432 } | 434 } |
| 433 | 435 |
| 434 int32_t RealNeedMorePlayData(const uint32_t nSamples, | 436 int32_t RealNeedMorePlayData(size_t uint32_t nSamples, |
| 435 const uint8_t nBytesPerSample, | 437 size_t uint8_t nBytesPerSample, |
| 436 const uint8_t nChannels, | 438 const uint8_t nChannels, |
| 437 const uint32_t samplesPerSec, | 439 const uint32_t samplesPerSec, |
| 438 void* audioSamples, | 440 void* audioSamples, |
| 439 uint32_t& nSamplesOut, | 441 size_t& nSamplesOut, |
| 440 int64_t* elapsed_time_ms, | 442 int64_t* elapsed_time_ms, |
| 441 int64_t* ntp_time_ms) { | 443 int64_t* ntp_time_ms) { |
| 442 EXPECT_TRUE(play_mode()) << "No test is expecting these callbacks."; | 444 EXPECT_TRUE(play_mode()) << "No test is expecting these callbacks."; |
| 443 play_count_++; | 445 play_count_++; |
| 444 nSamplesOut = nSamples; | 446 nSamplesOut = nSamples; |
| 445 // Read (possibly processed) audio stream samples to be played out if an | 447 // Read (possibly processed) audio stream samples to be played out if an |
| 446 // AudioStreamInterface implementation exists. | 448 // AudioStreamInterface implementation exists. |
| 447 if (audio_stream_) { | 449 if (audio_stream_) { |
| 448 audio_stream_->Read(audioSamples, nSamples); | 450 audio_stream_->Read(audioSamples, nSamples); |
| 449 } | 451 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 467 playout_done = true; | 469 playout_done = true; |
| 468 | 470 |
| 469 return recording_done && playout_done; | 471 return recording_done && playout_done; |
| 470 } | 472 } |
| 471 | 473 |
| 472 bool play_mode() const { return type_ & kPlayout; } | 474 bool play_mode() const { return type_ & kPlayout; } |
| 473 bool rec_mode() const { return type_ & kRecording; } | 475 bool rec_mode() const { return type_ & kRecording; } |
| 474 | 476 |
| 475 private: | 477 private: |
| 476 EventWrapper* test_is_done_; | 478 EventWrapper* test_is_done_; |
| 477 int num_callbacks_; | 479 size_t num_callbacks_; |
| 478 int type_; | 480 int type_; |
| 479 int play_count_; | 481 size_t play_count_; |
| 480 int rec_count_; | 482 size_t rec_count_; |
| 481 AudioStreamInterface* audio_stream_; | 483 AudioStreamInterface* audio_stream_; |
| 482 }; | 484 }; |
| 483 | 485 |
| 484 // AudioDeviceTest test fixture. | 486 // AudioDeviceTest test fixture. |
| 485 class AudioDeviceTest : public ::testing::Test { | 487 class AudioDeviceTest : public ::testing::Test { |
| 486 protected: | 488 protected: |
| 487 AudioDeviceTest() : test_is_done_(EventWrapper::Create()) { | 489 AudioDeviceTest() : test_is_done_(EventWrapper::Create()) { |
| 488 old_sev_ = rtc::LogMessage::GetLogToDebug(); | 490 old_sev_ = rtc::LogMessage::GetLogToDebug(); |
| 489 // Set suitable logging level here. Change to rtc::LS_INFO for more verbose | 491 // Set suitable logging level here. Change to rtc::LS_INFO for more verbose |
| 490 // output. See webrtc/base/logging.h for complete list of options. | 492 // output. See webrtc/base/logging.h for complete list of options. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 503 virtual ~AudioDeviceTest() { | 505 virtual ~AudioDeviceTest() { |
| 504 EXPECT_EQ(0, audio_device_->Terminate()); | 506 EXPECT_EQ(0, audio_device_->Terminate()); |
| 505 rtc::LogMessage::LogToDebug(old_sev_); | 507 rtc::LogMessage::LogToDebug(old_sev_); |
| 506 } | 508 } |
| 507 | 509 |
| 508 // TODO(henrika): don't use hardcoded values below. | 510 // TODO(henrika): don't use hardcoded values below. |
| 509 int playout_sample_rate() const { return playout_parameters_.sample_rate(); } | 511 int playout_sample_rate() const { return playout_parameters_.sample_rate(); } |
| 510 int record_sample_rate() const { return record_parameters_.sample_rate(); } | 512 int record_sample_rate() const { return record_parameters_.sample_rate(); } |
| 511 int playout_channels() const { return playout_parameters_.channels(); } | 513 int playout_channels() const { return playout_parameters_.channels(); } |
| 512 int record_channels() const { return record_parameters_.channels(); } | 514 int record_channels() const { return record_parameters_.channels(); } |
| 513 int playout_frames_per_10ms_buffer() const { | 515 size_t playout_frames_per_10ms_buffer() const { |
| 514 return playout_parameters_.frames_per_10ms_buffer(); | 516 return playout_parameters_.frames_per_10ms_buffer(); |
| 515 } | 517 } |
| 516 int record_frames_per_10ms_buffer() const { | 518 size_t record_frames_per_10ms_buffer() const { |
| 517 return record_parameters_.frames_per_10ms_buffer(); | 519 return record_parameters_.frames_per_10ms_buffer(); |
| 518 } | 520 } |
| 519 | 521 |
| 520 int total_delay_ms() const { | 522 int total_delay_ms() const { |
| 521 // TODO(henrika): improve this part. | 523 // TODO(henrika): improve this part. |
| 522 return 100; | 524 return 100; |
| 523 } | 525 } |
| 524 | 526 |
| 525 rtc::scoped_refptr<AudioDeviceModule> audio_device() const { | 527 rtc::scoped_refptr<AudioDeviceModule> audio_device() const { |
| 526 return audio_device_; | 528 return audio_device_; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 545 std::string GetFileName(int sample_rate) { | 547 std::string GetFileName(int sample_rate) { |
| 546 EXPECT_TRUE(sample_rate == 48000 || sample_rate == 44100 || | 548 EXPECT_TRUE(sample_rate == 48000 || sample_rate == 44100 || |
| 547 sample_rate == 16000); | 549 sample_rate == 16000); |
| 548 char fname[64]; | 550 char fname[64]; |
| 549 snprintf(fname, sizeof(fname), "audio_device/audio_short%d", | 551 snprintf(fname, sizeof(fname), "audio_device/audio_short%d", |
| 550 sample_rate / 1000); | 552 sample_rate / 1000); |
| 551 std::string file_name(webrtc::test::ResourcePath(fname, "pcm")); | 553 std::string file_name(webrtc::test::ResourcePath(fname, "pcm")); |
| 552 EXPECT_TRUE(test::FileExists(file_name)); | 554 EXPECT_TRUE(test::FileExists(file_name)); |
| 553 #ifdef ENABLE_DEBUG_PRINTF | 555 #ifdef ENABLE_DEBUG_PRINTF |
| 554 PRINTD("file name: %s\n", file_name.c_str()); | 556 PRINTD("file name: %s\n", file_name.c_str()); |
| 555 const int bytes = test::GetFileSize(file_name); | 557 const size_t bytes = test::GetFileSize(file_name); |
| 556 PRINTD("file size: %d [bytes]\n", bytes); | 558 PRINTD("file size: %" PRIuS " [bytes]\n", bytes); |
| 557 PRINTD("file size: %d [samples]\n", bytes / kBytesPerSample); | 559 PRINTD("file size: %" PRIuS " [samples]\n", bytes / kBytesPerSample); |
| 558 const int seconds = bytes / (sample_rate * kBytesPerSample); | 560 const int seconds = |
| 561 static_cast<int>(bytes / (sample_rate * kBytesPerSample)); |
| 559 PRINTD("file size: %d [secs]\n", seconds); | 562 PRINTD("file size: %d [secs]\n", seconds); |
| 560 PRINTD("file size: %d [callbacks]\n", seconds * kNumCallbacksPerSecond); | 563 PRINTD("file size: %" PRIuS " [callbacks]\n", |
| 564 seconds * kNumCallbacksPerSecond); |
| 561 #endif | 565 #endif |
| 562 return file_name; | 566 return file_name; |
| 563 } | 567 } |
| 564 | 568 |
| 565 void StartPlayout() { | 569 void StartPlayout() { |
| 566 EXPECT_FALSE(audio_device()->PlayoutIsInitialized()); | 570 EXPECT_FALSE(audio_device()->PlayoutIsInitialized()); |
| 567 EXPECT_FALSE(audio_device()->Playing()); | 571 EXPECT_FALSE(audio_device()->Playing()); |
| 568 EXPECT_EQ(0, audio_device()->InitPlayout()); | 572 EXPECT_EQ(0, audio_device()->InitPlayout()); |
| 569 EXPECT_TRUE(audio_device()->PlayoutIsInitialized()); | 573 EXPECT_TRUE(audio_device()->PlayoutIsInitialized()); |
| 570 EXPECT_EQ(0, audio_device()->StartPlayout()); | 574 EXPECT_EQ(0, audio_device()->StartPlayout()); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 std::max(kTestTimeOutInMilliseconds, 1000 * kMeasureLatencyTimeInSec)); | 783 std::max(kTestTimeOutInMilliseconds, 1000 * kMeasureLatencyTimeInSec)); |
| 780 StopPlayout(); | 784 StopPlayout(); |
| 781 StopRecording(); | 785 StopRecording(); |
| 782 // Verify that the correct number of transmitted impulses are detected. | 786 // Verify that the correct number of transmitted impulses are detected. |
| 783 EXPECT_EQ(latency_audio_stream->num_latency_values(), | 787 EXPECT_EQ(latency_audio_stream->num_latency_values(), |
| 784 kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1); | 788 kImpulseFrequencyInHz * kMeasureLatencyTimeInSec - 1); |
| 785 latency_audio_stream->PrintResults(); | 789 latency_audio_stream->PrintResults(); |
| 786 } | 790 } |
| 787 | 791 |
| 788 } // namespace webrtc | 792 } // namespace webrtc |
| OLD | NEW |