Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Side by Side Diff: content/renderer/media/speech_recognition_audio_sink_unittest.cc

Issue 651873002: Best effort approach on repeated synchronization lag (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Change DVLOG(1) to DLOG(ERROR) Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/renderer/media/speech_recognition_audio_sink.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/renderer/media/speech_recognition_audio_sink.h" 5 #include "content/renderer/media/speech_recognition_audio_sink.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "content/renderer/media/media_stream_audio_source.h" 9 #include "content/renderer/media/media_stream_audio_source.h"
10 #include "content/renderer/media/mock_media_constraint_factory.h" 10 #include "content/renderer/media/mock_media_constraint_factory.h"
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // Since buffer is used sequentially, we can reset the buffer indices here. 102 // Since buffer is used sequentially, we can reset the buffer indices here.
103 buffer_->start = buffer_->length = 0; 103 buffer_->start = buffer_->length = 0;
104 return length; 104 return length;
105 } 105 }
106 106
107 // This fake class is the consumer used to verify behaviour of the producer. 107 // This fake class is the consumer used to verify behaviour of the producer.
108 // The |Initialize()| method shows what the consumer should be responsible for 108 // The |Initialize()| method shows what the consumer should be responsible for
109 // in the production code (minus the mocks). 109 // in the production code (minus the mocks).
110 class FakeSpeechRecognizer { 110 class FakeSpeechRecognizer {
111 public: 111 public:
112 FakeSpeechRecognizer() : is_responsive_(true) { } 112 FakeSpeechRecognizer() : is_responsive_(true) {}
113 113
114 void Initialize( 114 void Initialize(
115 const blink::WebMediaStreamTrack& track, 115 const blink::WebMediaStreamTrack& track,
116 const media::AudioParameters& sink_params, 116 const media::AudioParameters& sink_params,
117 base::SharedMemoryHandle* foreign_memory_handle) { 117 base::SharedMemoryHandle* foreign_memory_handle) {
118 // Shared memory is allocated, mapped and shared. 118 // Shared memory is allocated, mapped and shared.
119 const uint32 kSharedMemorySize = 119 const uint32 kSharedMemorySize =
120 sizeof(media::AudioInputBufferParameters) + 120 sizeof(media::AudioInputBufferParameters) +
121 media::AudioBus::CalculateMemorySize(sink_params); 121 media::AudioBus::CalculateMemorySize(sink_params);
122 shared_memory_.reset(new base::SharedMemory()); 122 shared_memory_.reset(new base::SharedMemory());
123 ASSERT_TRUE(shared_memory_->CreateAndMapAnonymous(kSharedMemorySize)); 123 ASSERT_TRUE(shared_memory_->CreateAndMapAnonymous(kSharedMemorySize));
124 memset(shared_memory_->memory(), 0, kSharedMemorySize); 124 memset(shared_memory_->memory(), 0, kSharedMemorySize);
125 ASSERT_TRUE(shared_memory_->ShareToProcess(base::GetCurrentProcessHandle(), 125 ASSERT_TRUE(shared_memory_->ShareToProcess(base::GetCurrentProcessHandle(),
126 foreign_memory_handle)); 126 foreign_memory_handle));
127 127
128 // Wrap the shared memory for the audio bus. 128 // Wrap the shared memory for the audio bus.
129 media::AudioInputBuffer* buffer = 129 media::AudioInputBuffer* buffer =
130 static_cast<media::AudioInputBuffer*>(shared_memory_->memory()); 130 static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
131
131 audio_track_bus_ = media::AudioBus::WrapMemory(sink_params, buffer->audio); 132 audio_track_bus_ = media::AudioBus::WrapMemory(sink_params, buffer->audio);
132 audio_track_bus_->Zero(); 133 audio_track_bus_->Zero();
133 134
134 // Reference to the counter used to synchronize. 135 // Reference to the counter used to synchronize.
135 buffer_index_ = &(buffer->params.size); 136 buffer->params.size = 0U;
136 *buffer_index_ = 0U;
137 137
138 // Create a shared buffer for the |MockSyncSocket|s. 138 // Create a shared buffer for the |MockSyncSocket|s.
139 shared_buffer_.reset(new MockSyncSocket::SharedBuffer()); 139 shared_buffer_.reset(new MockSyncSocket::SharedBuffer());
140 140
141 // Local socket will receive signals from the producer. 141 // Local socket will receive signals from the producer.
142 local_socket_.reset(new MockSyncSocket(shared_buffer_.get())); 142 receiving_socket_.reset(new MockSyncSocket(shared_buffer_.get()));
143 143
144 // We automatically trigger a Receive when data is sent over the socket. 144 // We automatically trigger a Receive when data is sent over the socket.
145 foreign_socket_ = new MockSyncSocket( 145 sending_socket_ = new MockSyncSocket(
146 shared_buffer_.get(), 146 shared_buffer_.get(),
147 base::Bind(&FakeSpeechRecognizer::EmulateReceiveThreadLoopIteration, 147 base::Bind(&FakeSpeechRecognizer::EmulateReceiveThreadLoopIteration,
148 base::Unretained(this))); 148 base::Unretained(this)));
149 149
150 // This is usually done to pair the sockets. Here it's not effective. 150 // This is usually done to pair the sockets. Here it's not effective.
151 base::SyncSocket::CreatePair(local_socket_.get(), foreign_socket_); 151 base::SyncSocket::CreatePair(receiving_socket_.get(), sending_socket_);
152 } 152 }
153 153
154 // Emulates a single iteraton of a thread receiving on the socket. 154 // Emulates a single iteraton of a thread receiving on the socket.
155 // This would normally be done on a receiving thread's task on the browser. 155 // This would normally be done on a receiving thread's task on the browser.
156 void EmulateReceiveThreadLoopIteration() { 156 void EmulateReceiveThreadLoopIteration() {
157 // When not responsive do nothing as if the process is busy.
158 if (!is_responsive_) 157 if (!is_responsive_)
159 return; 158 return;
160 159
161 local_socket_->Receive(buffer_index_, sizeof(*buffer_index_)); 160 const int kSize = sizeof(media::AudioInputBufferParameters().size);
161 receiving_socket_->Receive(&(GetAudioInputBuffer()->params.size), kSize);
162
162 // Notify the producer that the audio buffer has been consumed. 163 // Notify the producer that the audio buffer has been consumed.
163 ++(*buffer_index_); 164 GetAudioInputBuffer()->params.size++;
164 } 165 }
165 166
166 // Used to simulate an unresponsive behaviour of the consumer. 167 // Used to simulate an unresponsive behaviour of the consumer.
167 void SimulateResponsiveness(bool is_responsive) { 168 void SimulateResponsiveness(bool is_responsive) {
168 is_responsive_ = is_responsive; 169 is_responsive_ = is_responsive;
169 } 170 }
170 171
171 MockSyncSocket* foreign_socket() { return foreign_socket_; } 172 media::AudioInputBuffer * GetAudioInputBuffer() const {
173 return static_cast<media::AudioInputBuffer*>(shared_memory_->memory());
174 }
175
176 MockSyncSocket* sending_socket() { return sending_socket_; }
172 media::AudioBus* audio_bus() const { return audio_track_bus_.get(); } 177 media::AudioBus* audio_bus() const { return audio_track_bus_.get(); }
173 uint32 buffer_index() { return *buffer_index_; } 178
174 179
175 private: 180 private:
176 bool is_responsive_; 181 bool is_responsive_;
177 182
178 // Shared memory for the audio and synchronization. 183 // Shared memory for the audio and synchronization.
179 scoped_ptr<base::SharedMemory> shared_memory_; 184 scoped_ptr<base::SharedMemory> shared_memory_;
180 185
181 // Fake sockets and their shared buffer. 186 // Fake sockets and their shared buffer.
182 scoped_ptr<MockSyncSocket::SharedBuffer> shared_buffer_; 187 scoped_ptr<MockSyncSocket::SharedBuffer> shared_buffer_;
183 scoped_ptr<MockSyncSocket> local_socket_; 188 scoped_ptr<MockSyncSocket> receiving_socket_;
184 MockSyncSocket* foreign_socket_; 189 MockSyncSocket* sending_socket_;
185 190
186 // Audio bus wrapping the shared memory from the renderer. 191 // Audio bus wrapping the shared memory from the renderer.
187 scoped_ptr<media::AudioBus> audio_track_bus_; 192 scoped_ptr<media::AudioBus> audio_track_bus_;
188 193
189 // Used for synchronization of sent/received buffers.
190 uint32* buffer_index_;
191
192 DISALLOW_COPY_AND_ASSIGN(FakeSpeechRecognizer); 194 DISALLOW_COPY_AND_ASSIGN(FakeSpeechRecognizer);
193 }; 195 };
194 196
195 } // namespace 197 } // namespace
196 198
197 namespace content { 199 namespace content {
198 200
199 class SpeechRecognitionAudioSinkTest : public testing::Test { 201 class SpeechRecognitionAudioSinkTest : public testing::Test {
200 public: 202 public:
201 SpeechRecognitionAudioSinkTest() {} 203 SpeechRecognitionAudioSinkTest() {}
(...skipping 30 matching lines...) Expand all
232 native_track_ = 234 native_track_ =
233 static_cast<WebRtcLocalAudioTrack*>(blink_track.extraData()); 235 static_cast<WebRtcLocalAudioTrack*>(blink_track.extraData());
234 native_track_->OnSetFormat(source_params_); 236 native_track_->OnSetFormat(source_params_);
235 237
236 // Create and initialize the consumer. 238 // Create and initialize the consumer.
237 recognizer_.reset(new FakeSpeechRecognizer()); 239 recognizer_.reset(new FakeSpeechRecognizer());
238 base::SharedMemoryHandle foreign_memory_handle; 240 base::SharedMemoryHandle foreign_memory_handle;
239 recognizer_->Initialize(blink_track, sink_params_, &foreign_memory_handle); 241 recognizer_->Initialize(blink_track, sink_params_, &foreign_memory_handle);
240 242
241 // Create the producer. 243 // Create the producer.
242 scoped_ptr<base::SyncSocket> foreign_socket(recognizer_->foreign_socket()); 244 scoped_ptr<base::SyncSocket> sending_socket(recognizer_->sending_socket());
243 speech_audio_sink_.reset(new SpeechRecognitionAudioSink( 245 speech_audio_sink_.reset(new SpeechRecognitionAudioSink(
244 blink_track, sink_params_, foreign_memory_handle, 246 blink_track, sink_params_, foreign_memory_handle,
245 foreign_socket.Pass(), 247 sending_socket.Pass(),
246 base::Bind(&SpeechRecognitionAudioSinkTest::StoppedCallback, 248 base::Bind(&SpeechRecognitionAudioSinkTest::StoppedCallback,
247 base::Unretained(this)))); 249 base::Unretained(this))));
248 250
249 // Return number of buffers needed to trigger resampling and consumption. 251 // Return number of buffers needed to trigger resampling and consumption.
250 return static_cast<uint32>(std::ceil( 252 return static_cast<uint32>(std::ceil(
251 static_cast<double>(output_frames_per_buffer * input_sample_rate) / 253 static_cast<double>(output_frames_per_buffer * input_sample_rate) /
252 (input_frames_per_buffer * output_sample_rate))); 254 (input_frames_per_buffer * output_sample_rate)));
253 } 255 }
254 256
255 // Mock callback expected to be called when the track is stopped. 257 // Mock callback expected to be called when the track is stopped.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 // Emulates an audio capture device capturing data from the source. 290 // Emulates an audio capture device capturing data from the source.
289 inline void CaptureAudio(const uint32 buffers) { 291 inline void CaptureAudio(const uint32 buffers) {
290 for (uint32 i = 0; i < buffers; ++i) 292 for (uint32 i = 0; i < buffers; ++i)
291 native_track()->Capture(source_data(), 293 native_track()->Capture(source_data(),
292 base::TimeDelta::FromMilliseconds(0), 1, false, 294 base::TimeDelta::FromMilliseconds(0), 1, false,
293 false); 295 false);
294 } 296 }
295 297
296 // Used to simulate a problem with sockets. 298 // Used to simulate a problem with sockets.
297 void SetFailureModeOnForeignSocket(bool in_failure_mode) { 299 void SetFailureModeOnForeignSocket(bool in_failure_mode) {
298 recognizer()->foreign_socket()->SetFailureMode(in_failure_mode); 300 recognizer()->sending_socket()->SetFailureMode(in_failure_mode);
299 } 301 }
300 302
301 // Helper method for verifying captured audio data has been consumed. 303 // Helper method for verifying captured audio data has been consumed.
302 inline void AssertConsumedBuffers(const uint32 buffer_index) { 304 inline void AssertConsumedBuffers(const uint32 buffer_index) {
303 ASSERT_EQ(buffer_index, recognizer_->buffer_index()); 305 ASSERT_EQ(buffer_index, recognizer()->GetAudioInputBuffer()->params.size);
304 } 306 }
305 307
306 // Helper method for providing audio data to producer and verifying it was 308 // Helper method for providing audio data to producer and verifying it was
307 // consumed on the recognizer. 309 // consumed on the recognizer.
308 inline void CaptureAudioAndAssertConsumedBuffers(const uint32 buffers, 310 inline void CaptureAudioAndAssertConsumedBuffers(const uint32 buffers,
309 const uint32 buffer_index) { 311 const uint32 buffer_index) {
310 CaptureAudio(buffers); 312 CaptureAudio(buffers);
311 AssertConsumedBuffers(buffer_index); 313 AssertConsumedBuffers(buffer_index);
312 } 314 }
313 315
314 // Helper method to capture and assert consumption at different sample rates 316 // Helper method to capture and assert consumption at different sample rates
315 // and audio buffer sizes. 317 // and audio buffer sizes.
316 inline void AssertConsumptionForAudioParameters( 318 inline void AssertConsumptionForAudioParameters(
317 const int input_sample_rate, 319 const int input_sample_rate,
318 const int input_frames_per_buffer, 320 const int input_frames_per_buffer,
319 const int output_sample_rate, 321 const int output_sample_rate,
320 const int output_frames_per_buffer, 322 const int output_frames_per_buffer,
321 const uint32 consumptions) { 323 const uint32 consumptions) {
322 const uint32 kBuffersPerNotification = Initialize(input_sample_rate, 324 const uint32 kBuffersPerNotification = Initialize(input_sample_rate,
323 input_frames_per_buffer, 325 input_frames_per_buffer,
324 output_sample_rate, 326 output_sample_rate,
325 output_frames_per_buffer); 327 output_frames_per_buffer);
326 AssertConsumedBuffers(0U); 328 AssertConsumedBuffers(0U);
327 329
328 for (uint32 i = 1U; i <= consumptions; ++i) { 330 for (uint32 i = 1U; i <= consumptions; ++i) {
329 CaptureAudio(kBuffersPerNotification); 331 CaptureAudio(kBuffersPerNotification);
330 ASSERT_EQ(i, recognizer_->buffer_index()) 332 ASSERT_EQ(i, recognizer()->GetAudioInputBuffer()->params.size)
331 << "Tested at rates: " 333 << "Tested at rates: "
332 << "In(" << input_sample_rate << ", " << input_frames_per_buffer 334 << "In(" << input_sample_rate << ", " << input_frames_per_buffer
333 << ") " 335 << ") "
334 << "Out(" << output_sample_rate << ", " << output_frames_per_buffer 336 << "Out(" << output_sample_rate << ", " << output_frames_per_buffer
335 << ")"; 337 << ")";
336 } 338 }
337 } 339 }
338 340
339 int16* source_data() { return source_data_.get(); } 341 int16* source_data() { return source_data_.get(); }
340 342
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600); 469 const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
468 // Start with no problems on the socket. 470 // Start with no problems on the socket.
469 AssertConsumedBuffers(0U); 471 AssertConsumedBuffers(0U);
470 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U); 472 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
471 473
472 // A failure occurs (socket cannot send). 474 // A failure occurs (socket cannot send).
473 SetFailureModeOnForeignSocket(true); 475 SetFailureModeOnForeignSocket(true);
474 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U); 476 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
475 } 477 }
476 478
479 // A very unlikely scenario in which the peer is not synchronizing for a long
480 // time (e.g. 300 ms) which results in dropping cached buffers and restarting.
481 // We check that the FIFO overflow does not occur and that the producer is able
482 // to resume.
483 TEST_F(SpeechRecognitionAudioSinkTest, RepeatedSycnhronizationLag) {
484 const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
485
486 // Start with no synchronization problems.
487 AssertConsumedBuffers(0U);
488 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
489
490 // Consumer gets out of sync.
491 recognizer()->SimulateResponsiveness(false);
492 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
493 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
494 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
495
496 // Consumer recovers.
497 recognizer()->SimulateResponsiveness(true);
498 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 2U);
499 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 3U);
500 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 4U);
501 }
502
477 // Checks that an OnStoppedCallback is issued when the track is stopped. 503 // Checks that an OnStoppedCallback is issued when the track is stopped.
478 TEST_F(SpeechRecognitionAudioSinkTest, OnReadyStateChangedOccured) { 504 TEST_F(SpeechRecognitionAudioSinkTest, OnReadyStateChangedOccured) {
479 const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600); 505 const uint32 kBuffersPerNotification = Initialize(44100, 441, 16000, 1600);
480 AssertConsumedBuffers(0U); 506 AssertConsumedBuffers(0U);
481 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U); 507 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
482 EXPECT_CALL(*this, StoppedCallback()).Times(1); 508 EXPECT_CALL(*this, StoppedCallback()).Times(1);
483 509
484 native_track()->Stop(); 510 native_track()->Stop();
485 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U); 511 CaptureAudioAndAssertConsumedBuffers(kBuffersPerNotification, 1U);
486 } 512 }
487 513
488 } // namespace content 514 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/speech_recognition_audio_sink.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698