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(); |