Chromium Code Reviews| Index: content/browser/speech/speech_recognizer_impl_unittest.cc |
| diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc |
| index 80b94bc95cb772e8a9aa0e18dfdf8a92c4592e3d..e2a2f2472e4efc70a01b55be38d3486938b956c3 100644 |
| --- a/content/browser/speech/speech_recognizer_impl_unittest.cc |
| +++ b/content/browser/speech/speech_recognizer_impl_unittest.cc |
| @@ -8,7 +8,9 @@ |
| #include <vector> |
| #include "base/run_loop.h" |
| +#include "base/synchronization/waitable_event.h" |
| #include "base/sys_byteorder.h" |
| +#include "base/threading/thread.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "content/browser/speech/proto/google_streaming_api.pb.h" |
| #include "content/browser/speech/speech_recognition_engine.h" |
| @@ -16,11 +18,13 @@ |
| #include "content/public/browser/speech_recognition_event_listener.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "media/audio/audio_device_description.h" |
| +#include "media/audio/audio_system_impl.h" |
| #include "media/audio/fake_audio_input_stream.h" |
| #include "media/audio/fake_audio_output_stream.h" |
| #include "media/audio/mock_audio_manager.h" |
| #include "media/audio/test_audio_input_controller_factory.h" |
| #include "media/base/audio_bus.h" |
| +#include "media/base/test_helpers.h" |
| #include "net/base/net_errors.h" |
| #include "net/url_request/test_url_fetcher_factory.h" |
| #include "net/url_request/url_request_status.h" |
| @@ -39,7 +43,8 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, |
| public testing::Test { |
| public: |
| SpeechRecognizerImplTest() |
| - : recognition_started_(false), |
| + : audio_thread_("AudioThread"), |
|
tommi (sloooow) - chröme
2017/02/05 20:14:54
nit: SpeechAudioThread? Nice improvement to reall
o1ka
2017/02/06 12:06:08
Done.
|
| + recognition_started_(false), |
| recognition_ended_(false), |
| result_received_(false), |
| audio_started_(false), |
| @@ -59,11 +64,15 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, |
| sr_engine->SetConfig(config); |
| const int kTestingSessionId = 1; |
| - recognizer_ = new SpeechRecognizerImpl( |
| - this, kTestingSessionId, false, false, sr_engine); |
| + |
| + audio_thread_.StartAndWaitForTesting(); |
| audio_manager_.reset( |
| - new media::MockAudioManager(base::ThreadTaskRunnerHandle::Get().get())); |
| - recognizer_->SetAudioManagerForTesting(audio_manager_.get()); |
| + new media::MockAudioManager(audio_thread_.task_runner())); |
| + audio_manager_->SetInputStreamParameters( |
| + media::AudioParameters::UnavailableDeviceParams()); |
| + audio_system_ = media::AudioSystemImpl::Create(audio_manager_.get()); |
| + recognizer_ = new SpeechRecognizerImpl( |
| + this, audio_system_.get(), kTestingSessionId, false, false, sr_engine); |
| int audio_packet_length_bytes = |
| (SpeechRecognizerImpl::kAudioSampleRate * |
| @@ -80,6 +89,12 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, |
| audio_bus_->Zero(); |
| } |
| + ~SpeechRecognizerImplTest() override { |
| + // Deleting |audio_manager_| on audio thread. |
| + audio_manager_.reset(); |
| + audio_thread_.Stop(); |
| + } |
| + |
| void CheckEventsConsistency() { |
| // Note: "!x || y" == "x implies y". |
| EXPECT_TRUE(!recognition_ended_ || recognition_started_); |
| @@ -189,10 +204,22 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, |
| writer->Write(data, 0.0, false, 0); |
| } |
| + void WaitForAudioThreadToPostDeviceInfo() { |
| + media::WaitableMessageLoopEvent event; |
| + audio_thread_.task_runner()->PostTaskAndReply( |
| + FROM_HERE, base::Bind(&base::DoNothing), event.GetClosure()); |
| + // Runs the loop and waits for the |audio_thread_| to call event's closure, |
| + // which means AudioSystem reply containing device parameters is already |
| + // queued on the main thread. |
| + event.RunAndWait(); |
| + } |
| + |
| protected: |
| TestBrowserThreadBundle thread_bundle_; |
| scoped_refptr<SpeechRecognizerImpl> recognizer_; |
| - media::ScopedAudioManagerPtr audio_manager_; |
| + base::Thread audio_thread_; |
| + media::MockAudioManager::UniquePtr audio_manager_; |
| + std::unique_ptr<media::AudioSystem> audio_system_; |
| bool recognition_started_; |
| bool recognition_ended_; |
| bool result_received_; |
| @@ -210,10 +237,82 @@ class SpeechRecognizerImplTest : public SpeechRecognitionEventListener, |
| float noise_volume_; |
| }; |
| +TEST_F(SpeechRecognizerImplTest, StartNoInputDevices) { |
| + // Check for callbacks when stopping record before any audio gets recorded. |
| + audio_manager_->SetHasInputDevices(false); |
| + recognizer_->StartRecognition( |
| + media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| + // recognizer_->StopAudioCapture(); |
|
tommi (sloooow) - chröme
2017/02/05 20:14:54
remove?
o1ka
2017/02/06 12:06:08
Done.
|
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_TRUE(recognition_started_); |
| + EXPECT_FALSE(audio_started_); |
| + EXPECT_FALSE(result_received_); |
| + EXPECT_EQ(SPEECH_RECOGNITION_ERROR_AUDIO_CAPTURE, error_); |
| + CheckFinalEventsConsistency(); |
| +} |
| + |
| +TEST_F(SpeechRecognizerImplTest, StopBeforeDeviceInfoReceived) { |
| + // Check for callbacks when stopping record before reply is received from |
| + // AudioSystem. |
| + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| + base::WaitableEvent::InitialState::NOT_SIGNALED); |
| + |
| + // Block audio thread. |
| + audio_thread_.task_runner()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event))); |
| + |
| + recognizer_->StartRecognition( |
| + media::AudioDeviceDescription::kDefaultDeviceId); |
| + recognizer_->StopAudioCapture(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Release audio thread and receive a callback from it. |
| + event.Signal(); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + EXPECT_TRUE(recognition_started_); |
| + EXPECT_FALSE(audio_started_); |
| + EXPECT_FALSE(result_received_); |
| + EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
| + CheckFinalEventsConsistency(); |
| +} |
| + |
| +TEST_F(SpeechRecognizerImplTest, CancelBeforeDeviceInfoReceived) { |
| + // Check for callbacks when stopping record before reply is received from |
| + // AudioSystem. |
| + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| + base::WaitableEvent::InitialState::NOT_SIGNALED); |
| + |
| + // Block audio thread. |
| + audio_thread_.task_runner()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&base::WaitableEvent::Wait, base::Unretained(&event))); |
| + |
| + recognizer_->StartRecognition( |
| + media::AudioDeviceDescription::kDefaultDeviceId); |
| + recognizer_->AbortRecognition(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Release audio thread and receive a callback from it. |
| + event.Signal(); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + EXPECT_TRUE(recognition_started_); |
| + EXPECT_FALSE(audio_started_); |
| + EXPECT_FALSE(result_received_); |
| + EXPECT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
| + CheckFinalEventsConsistency(); |
| +} |
| + |
| TEST_F(SpeechRecognizerImplTest, StopNoData) { |
| // Check for callbacks when stopping record before any audio gets recorded. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| recognizer_->StopAudioCapture(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(recognition_started_); |
| @@ -228,6 +327,7 @@ TEST_F(SpeechRecognizerImplTest, CancelNoData) { |
| // recorded. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| recognizer_->AbortRecognition(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(recognition_started_); |
| @@ -242,6 +342,7 @@ TEST_F(SpeechRecognizerImplTest, StopWithData) { |
| // network callback to arrive before completion. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -304,6 +405,7 @@ TEST_F(SpeechRecognizerImplTest, CancelWithData) { |
| // Start recording, give some data and then cancel. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -325,6 +427,7 @@ TEST_F(SpeechRecognizerImplTest, ConnectionError) { |
| // with a connection error and verify that the recognizer bubbles the error up |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -361,6 +464,7 @@ TEST_F(SpeechRecognizerImplTest, ServerError) { |
| // with a 500 error and verify that the recognizer bubbles the error up |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -395,6 +499,7 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorNoData) { |
| // Check if things tear down properly if AudioInputController threw an error. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -414,6 +519,7 @@ TEST_F(SpeechRecognizerImplTest, AudioControllerErrorWithData) { |
| // after giving some audio data. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -435,6 +541,7 @@ TEST_F(SpeechRecognizerImplTest, NoSpeechCallbackIssued) { |
| // This should trigger the no-speech detector and issue a callback. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -461,6 +568,7 @@ TEST_F(SpeechRecognizerImplTest, NoSpeechCallbackNotIssued) { |
| // triggered. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |
| @@ -498,6 +606,7 @@ TEST_F(SpeechRecognizerImplTest, SetInputVolumeCallback) { |
| // samples and proper volume for the loud audio. |
| recognizer_->StartRecognition( |
| media::AudioDeviceDescription::kDefaultDeviceId); |
| + WaitForAudioThreadToPostDeviceInfo(); |
| base::RunLoop().RunUntilIdle(); |
| TestAudioInputController* controller = |
| audio_input_controller_factory_.controller(); |