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

Side by Side Diff: content/browser/speech/speech_recognizer_impl_unittest.cc

Issue 2784433002: Ensures that audio tasks cannot run after AudioManager is deleted. (Closed)
Patch Set: rebase Created 3 years, 7 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
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 <stddef.h> 5 #include <stddef.h>
6 #include <stdint.h> 6 #include <stdint.h>
7 7
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/run_loop.h" 10 #include "base/run_loop.h"
11 #include "base/synchronization/waitable_event.h" 11 #include "base/synchronization/waitable_event.h"
12 #include "base/sys_byteorder.h" 12 #include "base/sys_byteorder.h"
13 #include "base/threading/thread.h" 13 #include "base/threading/thread.h"
14 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
15 #include "content/browser/speech/proto/google_streaming_api.pb.h" 15 #include "content/browser/speech/proto/google_streaming_api.pb.h"
16 #include "content/browser/speech/speech_recognition_engine.h" 16 #include "content/browser/speech/speech_recognition_engine.h"
17 #include "content/browser/speech/speech_recognizer_impl.h" 17 #include "content/browser/speech/speech_recognizer_impl.h"
18 #include "content/public/browser/speech_recognition_event_listener.h" 18 #include "content/public/browser/speech_recognition_event_listener.h"
19 #include "content/public/test/test_browser_thread_bundle.h" 19 #include "content/public/test/test_browser_thread_bundle.h"
20 #include "media/audio/audio_device_description.h" 20 #include "media/audio/audio_device_description.h"
21 #include "media/audio/audio_system_impl.h" 21 #include "media/audio/audio_system_impl.h"
22 #include "media/audio/fake_audio_input_stream.h" 22 #include "media/audio/fake_audio_input_stream.h"
23 #include "media/audio/fake_audio_output_stream.h" 23 #include "media/audio/fake_audio_output_stream.h"
24 #include "media/audio/mock_audio_manager.h" 24 #include "media/audio/mock_audio_manager.h"
25 #include "media/audio/test_audio_input_controller_factory.h" 25 #include "media/audio/test_audio_input_controller_factory.h"
26 #include "media/audio/test_audio_thread.h"
26 #include "media/base/audio_bus.h" 27 #include "media/base/audio_bus.h"
27 #include "media/base/test_helpers.h" 28 #include "media/base/test_helpers.h"
28 #include "net/base/net_errors.h" 29 #include "net/base/net_errors.h"
29 #include "net/url_request/test_url_fetcher_factory.h" 30 #include "net/url_request/test_url_fetcher_factory.h"
30 #include "net/url_request/url_request_status.h" 31 #include "net/url_request/url_request_status.h"
31 #include "testing/gtest/include/gtest/gtest.h" 32 #include "testing/gtest/include/gtest/gtest.h"
32 33
33 using media::AudioInputController; 34 using media::AudioInputController;
34 using media::AudioInputStream; 35 using media::AudioInputStream;
35 using media::AudioOutputStream; 36 using media::AudioOutputStream;
36 using media::AudioParameters; 37 using media::AudioParameters;
37 using media::TestAudioInputController; 38 using media::TestAudioInputController;
38 using media::TestAudioInputControllerFactory; 39 using media::TestAudioInputControllerFactory;
39 40
40 namespace content { 41 namespace content {
41 42
42 class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, 43 class SpeechRecognizerImplTest : public SpeechRecognitionEventListener,
43 public testing::Test { 44 public testing::Test {
44 public: 45 public:
45 SpeechRecognizerImplTest() 46 SpeechRecognizerImplTest()
46 : audio_thread_("SpeechAudioThread"), 47 : recognition_started_(false),
47 recognition_started_(false),
48 recognition_ended_(false), 48 recognition_ended_(false),
49 result_received_(false), 49 result_received_(false),
50 audio_started_(false), 50 audio_started_(false),
51 audio_ended_(false), 51 audio_ended_(false),
52 sound_started_(false), 52 sound_started_(false),
53 sound_ended_(false), 53 sound_ended_(false),
54 error_(SPEECH_RECOGNITION_ERROR_NONE), 54 error_(SPEECH_RECOGNITION_ERROR_NONE),
55 volume_(-1.0f) { 55 volume_(-1.0f) {
56 // SpeechRecognizer takes ownership of sr_engine. 56 // SpeechRecognizer takes ownership of sr_engine.
57 SpeechRecognitionEngine* sr_engine = 57 SpeechRecognitionEngine* sr_engine =
58 new SpeechRecognitionEngine(NULL /* URLRequestContextGetter */); 58 new SpeechRecognitionEngine(NULL /* URLRequestContextGetter */);
59 SpeechRecognitionEngine::Config config; 59 SpeechRecognitionEngine::Config config;
60 config.audio_num_bits_per_sample = 60 config.audio_num_bits_per_sample =
61 SpeechRecognizerImpl::kNumBitsPerAudioSample; 61 SpeechRecognizerImpl::kNumBitsPerAudioSample;
62 config.audio_sample_rate = SpeechRecognizerImpl::kAudioSampleRate; 62 config.audio_sample_rate = SpeechRecognizerImpl::kAudioSampleRate;
63 config.filter_profanities = false; 63 config.filter_profanities = false;
64 sr_engine->SetConfig(config); 64 sr_engine->SetConfig(config);
65 65
66 const int kTestingSessionId = 1; 66 const int kTestingSessionId = 1;
67 67
68 audio_thread_.StartAndWaitForTesting(); 68 audio_manager_.reset(new media::MockAudioManager(
69 audio_manager_.reset( 69 base::MakeUnique<media::TestAudioThread>(true)));
70 new media::MockAudioManager(audio_thread_.task_runner()));
71 audio_manager_->SetInputStreamParameters( 70 audio_manager_->SetInputStreamParameters(
72 media::AudioParameters::UnavailableDeviceParams()); 71 media::AudioParameters::UnavailableDeviceParams());
73 audio_system_ = media::AudioSystemImpl::Create(audio_manager_.get()); 72 audio_system_ = media::AudioSystemImpl::Create(audio_manager_.get());
74 recognizer_ = new SpeechRecognizerImpl( 73 recognizer_ = new SpeechRecognizerImpl(
75 this, audio_system_.get(), audio_manager_.get(), kTestingSessionId, 74 this, audio_system_.get(), audio_manager_.get(), kTestingSessionId,
76 false, false, sr_engine); 75 false, false, sr_engine);
77 76
78 int audio_packet_length_bytes = 77 int audio_packet_length_bytes =
79 (SpeechRecognizerImpl::kAudioSampleRate * 78 (SpeechRecognizerImpl::kAudioSampleRate *
80 SpeechRecognitionEngine::kAudioPacketIntervalMs * 79 SpeechRecognitionEngine::kAudioPacketIntervalMs *
81 ChannelLayoutToChannelCount(SpeechRecognizerImpl::kChannelLayout) * 80 ChannelLayoutToChannelCount(SpeechRecognizerImpl::kChannelLayout) *
82 SpeechRecognizerImpl::kNumBitsPerAudioSample) / (8 * 1000); 81 SpeechRecognizerImpl::kNumBitsPerAudioSample) / (8 * 1000);
83 audio_packet_.resize(audio_packet_length_bytes); 82 audio_packet_.resize(audio_packet_length_bytes);
84 83
85 const int channels = 84 const int channels =
86 ChannelLayoutToChannelCount(SpeechRecognizerImpl::kChannelLayout); 85 ChannelLayoutToChannelCount(SpeechRecognizerImpl::kChannelLayout);
87 bytes_per_sample_ = SpeechRecognizerImpl::kNumBitsPerAudioSample / 8; 86 bytes_per_sample_ = SpeechRecognizerImpl::kNumBitsPerAudioSample / 8;
88 const int frames = audio_packet_length_bytes / channels / bytes_per_sample_; 87 const int frames = audio_packet_length_bytes / channels / bytes_per_sample_;
89 audio_bus_ = media::AudioBus::Create(channels, frames); 88 audio_bus_ = media::AudioBus::Create(channels, frames);
90 audio_bus_->Zero(); 89 audio_bus_->Zero();
91 } 90 }
92 91
93 ~SpeechRecognizerImplTest() override { 92 ~SpeechRecognizerImplTest() override { audio_manager_->Shutdown(); }
94 // Deleting |audio_manager_| on audio thread.
95 audio_system_.reset();
96 audio_manager_.reset();
97 audio_thread_.Stop();
98 }
99 93
100 void CheckEventsConsistency() { 94 void CheckEventsConsistency() {
101 // Note: "!x || y" == "x implies y". 95 // Note: "!x || y" == "x implies y".
102 EXPECT_TRUE(!recognition_ended_ || recognition_started_); 96 EXPECT_TRUE(!recognition_ended_ || recognition_started_);
103 EXPECT_TRUE(!audio_ended_ || audio_started_); 97 EXPECT_TRUE(!audio_ended_ || audio_started_);
104 EXPECT_TRUE(!sound_ended_ || sound_started_); 98 EXPECT_TRUE(!sound_ended_ || sound_started_);
105 EXPECT_TRUE(!audio_started_ || recognition_started_); 99 EXPECT_TRUE(!audio_started_ || recognition_started_);
106 EXPECT_TRUE(!sound_started_ || audio_started_); 100 EXPECT_TRUE(!sound_started_ || audio_started_);
107 EXPECT_TRUE(!audio_ended_ || (sound_ended_ || !sound_started_)); 101 EXPECT_TRUE(!audio_ended_ || (sound_ended_ || !sound_started_));
108 EXPECT_TRUE(!recognition_ended_ || (audio_ended_ || !audio_started_)); 102 EXPECT_TRUE(!recognition_ended_ || (audio_ended_ || !audio_started_));
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 } 195 }
202 196
203 void OnData(media::AudioBus* data) { 197 void OnData(media::AudioBus* data) {
204 auto* writer = 198 auto* writer =
205 static_cast<AudioInputController::SyncWriter*>(recognizer_.get()); 199 static_cast<AudioInputController::SyncWriter*>(recognizer_.get());
206 writer->Write(data, 0.0, false, 0); 200 writer->Write(data, 0.0, false, 0);
207 } 201 }
208 202
209 void WaitForAudioThreadToPostDeviceInfo() { 203 void WaitForAudioThreadToPostDeviceInfo() {
210 media::WaitableMessageLoopEvent event; 204 media::WaitableMessageLoopEvent event;
211 audio_thread_.task_runner()->PostTaskAndReply( 205 audio_manager_->GetTaskRunner()->PostTaskAndReply(
212 FROM_HERE, base::Bind(&base::DoNothing), event.GetClosure()); 206 FROM_HERE, base::Bind(&base::DoNothing), event.GetClosure());
213 // Runs the loop and waits for the |audio_thread_| to call event's closure, 207 // Runs the loop and waits for the audio thread to call event's closure,
214 // which means AudioSystem reply containing device parameters is already 208 // which means AudioSystem reply containing device parameters is already
215 // queued on the main thread. 209 // queued on the main thread.
216 event.RunAndWait(); 210 event.RunAndWait();
217 } 211 }
218 212
219 protected: 213 protected:
220 TestBrowserThreadBundle thread_bundle_; 214 TestBrowserThreadBundle thread_bundle_;
221 scoped_refptr<SpeechRecognizerImpl> recognizer_; 215 scoped_refptr<SpeechRecognizerImpl> recognizer_;
222 base::Thread audio_thread_; 216 std::unique_ptr<media::MockAudioManager> audio_manager_;
223 media::MockAudioManager::UniquePtr audio_manager_;
224 std::unique_ptr<media::AudioSystem> audio_system_; 217 std::unique_ptr<media::AudioSystem> audio_system_;
225 bool recognition_started_; 218 bool recognition_started_;
226 bool recognition_ended_; 219 bool recognition_ended_;
227 bool result_received_; 220 bool result_received_;
228 bool audio_started_; 221 bool audio_started_;
229 bool audio_ended_; 222 bool audio_ended_;
230 bool sound_started_; 223 bool sound_started_;
231 bool sound_ended_; 224 bool sound_ended_;
232 SpeechRecognitionErrorCode error_; 225 SpeechRecognitionErrorCode error_;
233 net::TestURLFetcherFactory url_fetcher_factory_; 226 net::TestURLFetcherFactory url_fetcher_factory_;
(...skipping 20 matching lines...) Expand all
254 CheckFinalEventsConsistency(); 247 CheckFinalEventsConsistency();
255 } 248 }
256 249
257 TEST_F(SpeechRecognizerImplTest, StopBeforeDeviceInfoReceived) { 250 TEST_F(SpeechRecognizerImplTest, StopBeforeDeviceInfoReceived) {
258 // Check for callbacks when stopping record before reply is received from 251 // Check for callbacks when stopping record before reply is received from
259 // AudioSystem. 252 // AudioSystem.
260 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, 253 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
261 base::WaitableEvent::InitialState::NOT_SIGNALED); 254 base::WaitableEvent::InitialState::NOT_SIGNALED);
262 255
263 // Block audio thread. 256 // Block audio thread.
264 audio_thread_.task_runner()->PostTask( 257 audio_manager_->GetTaskRunner()->PostTask(
265 FROM_HERE, 258 FROM_HERE,
266 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event))); 259 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event)));
267 260
268 recognizer_->StartRecognition( 261 recognizer_->StartRecognition(
269 media::AudioDeviceDescription::kDefaultDeviceId); 262 media::AudioDeviceDescription::kDefaultDeviceId);
270 recognizer_->StopAudioCapture(); 263 recognizer_->StopAudioCapture();
271 base::RunLoop().RunUntilIdle(); 264 base::RunLoop().RunUntilIdle();
272 265
273 // Release audio thread and receive a callback from it. 266 // Release audio thread and receive a callback from it.
274 event.Signal(); 267 event.Signal();
275 WaitForAudioThreadToPostDeviceInfo(); 268 WaitForAudioThreadToPostDeviceInfo();
276 base::RunLoop().RunUntilIdle(); 269 base::RunLoop().RunUntilIdle();
277 270
278 EXPECT_TRUE(recognition_started_); 271 EXPECT_TRUE(recognition_started_);
279 EXPECT_FALSE(audio_started_); 272 EXPECT_FALSE(audio_started_);
280 EXPECT_FALSE(result_received_); 273 EXPECT_FALSE(result_received_);
281 EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); 274 EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
282 CheckFinalEventsConsistency(); 275 CheckFinalEventsConsistency();
283 } 276 }
284 277
285 TEST_F(SpeechRecognizerImplTest, CancelBeforeDeviceInfoReceived) { 278 TEST_F(SpeechRecognizerImplTest, CancelBeforeDeviceInfoReceived) {
286 // Check for callbacks when stopping record before reply is received from 279 // Check for callbacks when stopping record before reply is received from
287 // AudioSystem. 280 // AudioSystem.
288 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, 281 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
289 base::WaitableEvent::InitialState::NOT_SIGNALED); 282 base::WaitableEvent::InitialState::NOT_SIGNALED);
290 283
291 // Block audio thread. 284 // Block audio thread.
292 audio_thread_.task_runner()->PostTask( 285 audio_manager_->GetTaskRunner()->PostTask(
293 FROM_HERE, 286 FROM_HERE,
294 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event))); 287 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event)));
295 288
296 recognizer_->StartRecognition( 289 recognizer_->StartRecognition(
297 media::AudioDeviceDescription::kDefaultDeviceId); 290 media::AudioDeviceDescription::kDefaultDeviceId);
298 recognizer_->AbortRecognition(); 291 recognizer_->AbortRecognition();
299 base::RunLoop().RunUntilIdle(); 292 base::RunLoop().RunUntilIdle();
300 293
301 // Release audio thread and receive a callback from it. 294 // Release audio thread and receive a callback from it.
302 event.Signal(); 295 event.Signal();
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 643
651 EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); 644 EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_);
652 EXPECT_FALSE(audio_ended_); 645 EXPECT_FALSE(audio_ended_);
653 EXPECT_FALSE(recognition_ended_); 646 EXPECT_FALSE(recognition_ended_);
654 recognizer_->AbortRecognition(); 647 recognizer_->AbortRecognition();
655 base::RunLoop().RunUntilIdle(); 648 base::RunLoop().RunUntilIdle();
656 CheckFinalEventsConsistency(); 649 CheckFinalEventsConsistency();
657 } 650 }
658 651
659 } // namespace content 652 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/speech/speech_recognition_browsertest.cc ('k') | content/public/browser/content_browser_client.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698