| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |