| 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..2240fddc035dd9bd799068c5007a94d4b7213fdc 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_("SpeechAudioThread"),
|
| + 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,81 @@ 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();
|
| + 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 +326,7 @@ TEST_F(SpeechRecognizerImplTest, CancelNoData) {
|
| // recorded.
|
| recognizer_->StartRecognition(
|
| media::AudioDeviceDescription::kDefaultDeviceId);
|
| + WaitForAudioThreadToPostDeviceInfo();
|
| recognizer_->AbortRecognition();
|
| base::RunLoop().RunUntilIdle();
|
| EXPECT_TRUE(recognition_started_);
|
| @@ -242,6 +341,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 +404,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 +426,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 +463,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 +498,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 +518,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 +540,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 +567,7 @@ TEST_F(SpeechRecognizerImplTest, NoSpeechCallbackNotIssued) {
|
| // triggered.
|
| recognizer_->StartRecognition(
|
| media::AudioDeviceDescription::kDefaultDeviceId);
|
| + WaitForAudioThreadToPostDeviceInfo();
|
| base::RunLoop().RunUntilIdle();
|
| TestAudioInputController* controller =
|
| audio_input_controller_factory_.controller();
|
| @@ -498,6 +605,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();
|
|
|