c34a3e4abfee0db85a64c75c0336c145dc3c768a
[platform/framework/web/crosswalk.git] / src / content / browser / speech / speech_recognition_browsertest.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <list>
6
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/speech/google_streaming_remote_engine.h"
12 #include "content/browser/speech/speech_recognition_manager_impl.h"
13 #include "content/browser/speech/speech_recognizer_impl.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/test/browser_test_utils.h"
18 #include "content/public/test/content_browser_test.h"
19 #include "content/public/test/content_browser_test_utils.h"
20 #include "content/public/test/test_utils.h"
21 #include "content/shell/browser/shell.h"
22 #include "content/test/mock_google_streaming_server.h"
23 #include "media/audio/mock_audio_manager.h"
24 #include "media/audio/test_audio_input_controller_factory.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 using base::RunLoop;
28
29 namespace content {
30
31 class SpeechRecognitionBrowserTest :
32     public ContentBrowserTest,
33     public MockGoogleStreamingServer::Delegate,
34     public media::TestAudioInputControllerDelegate {
35  public:
36   enum StreamingServerState {
37     kIdle,
38     kTestAudioControllerOpened,
39     kClientConnected,
40     kClientAudioUpload,
41     kClientAudioUploadComplete,
42     kTestAudioControllerClosed,
43     kClientDisconnected
44   };
45
46   // MockGoogleStreamingServerDelegate methods.
47   virtual void OnClientConnected() OVERRIDE {
48     ASSERT_EQ(kTestAudioControllerOpened, streaming_server_state_);
49     streaming_server_state_ = kClientConnected;
50   }
51
52   virtual void OnClientAudioUpload() OVERRIDE {
53     if (streaming_server_state_ == kClientConnected)
54       streaming_server_state_ = kClientAudioUpload;
55   }
56
57   virtual void OnClientAudioUploadComplete() OVERRIDE {
58     ASSERT_EQ(kTestAudioControllerClosed, streaming_server_state_);
59     streaming_server_state_ = kClientAudioUploadComplete;
60   }
61
62   virtual void OnClientDisconnected() OVERRIDE {
63     ASSERT_EQ(kClientAudioUploadComplete, streaming_server_state_);
64     streaming_server_state_ = kClientDisconnected;
65   }
66
67   // media::TestAudioInputControllerDelegate methods.
68   virtual void TestAudioControllerOpened(
69       media::TestAudioInputController* controller) OVERRIDE {
70     ASSERT_EQ(kIdle, streaming_server_state_);
71     streaming_server_state_ = kTestAudioControllerOpened;
72     const int capture_packet_interval_ms =
73         (1000 * controller->audio_parameters().frames_per_buffer()) /
74         controller->audio_parameters().sample_rate();
75     ASSERT_EQ(GoogleStreamingRemoteEngine::kAudioPacketIntervalMs,
76         capture_packet_interval_ms);
77     FeedAudioController(500 /* ms */, /*noise=*/ false);
78     FeedAudioController(1000 /* ms */, /*noise=*/ true);
79     FeedAudioController(1000 /* ms */, /*noise=*/ false);
80   }
81
82   virtual void TestAudioControllerClosed(
83       media::TestAudioInputController* controller) OVERRIDE {
84     ASSERT_EQ(kClientAudioUpload, streaming_server_state_);
85     streaming_server_state_ = kTestAudioControllerClosed;
86     mock_streaming_server_->MockGoogleStreamingServer::SimulateResult(
87         GetGoodSpeechResult());
88   }
89
90   // Helper methods used by test fixtures.
91   GURL GetTestUrlFromFragment(const std::string fragment) {
92     return GURL(GetTestUrl("speech", "web_speech_recognition.html").spec() +
93         "#" + fragment);
94   }
95
96   std::string GetPageFragment() {
97     return shell()->web_contents()->GetURL().ref();
98   }
99
100   const StreamingServerState &streaming_server_state() {
101     return streaming_server_state_;
102   }
103
104  protected:
105   // ContentBrowserTest methods.
106   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
107     test_audio_input_controller_factory_.set_delegate(this);
108     media::AudioInputController::set_factory_for_testing(
109         &test_audio_input_controller_factory_);
110     mock_streaming_server_.reset(new MockGoogleStreamingServer(this));
111     streaming_server_state_ = kIdle;
112   }
113
114   virtual void SetUpOnMainThread() OVERRIDE {
115     ASSERT_TRUE(SpeechRecognitionManagerImpl::GetInstance());
116     SpeechRecognizerImpl::SetAudioManagerForTesting(
117         new media::MockAudioManager(BrowserThread::GetMessageLoopProxyForThread(
118             BrowserThread::IO)));
119   }
120
121   virtual void TearDownOnMainThread() OVERRIDE {
122     SpeechRecognizerImpl::SetAudioManagerForTesting(NULL);
123   }
124
125   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
126     test_audio_input_controller_factory_.set_delegate(NULL);
127     mock_streaming_server_.reset();
128   }
129
130  private:
131   static void FeedSingleBufferToAudioController(
132       scoped_refptr<media::TestAudioInputController> controller,
133       size_t buffer_size,
134       bool fill_with_noise) {
135     DCHECK(controller.get());
136     const media::AudioParameters& audio_params = controller->audio_parameters();
137     scoped_ptr<uint8[]> audio_buffer(new uint8[buffer_size]);
138     if (fill_with_noise) {
139       for (size_t i = 0; i < buffer_size; ++i)
140         audio_buffer[i] = static_cast<uint8>(127 * sin(i * 3.14F /
141             (16 * buffer_size)));
142     } else {
143       memset(audio_buffer.get(), 0, buffer_size);
144     }
145
146     scoped_ptr<media::AudioBus> audio_bus =
147         media::AudioBus::Create(audio_params);
148     audio_bus->FromInterleaved(&audio_buffer.get()[0],
149                                audio_bus->frames(),
150                                audio_params.bits_per_sample() / 8);
151     controller->event_handler()->OnData(controller.get(), audio_bus.get());
152   }
153
154   void FeedAudioController(int duration_ms, bool feed_with_noise) {
155     media::TestAudioInputController* controller =
156         test_audio_input_controller_factory_.controller();
157     ASSERT_TRUE(controller);
158     const media::AudioParameters& audio_params = controller->audio_parameters();
159     const size_t buffer_size = audio_params.GetBytesPerBuffer();
160     const int ms_per_buffer = audio_params.frames_per_buffer() * 1000 /
161                               audio_params.sample_rate();
162     // We can only simulate durations that are integer multiples of the
163     // buffer size. In this regard see
164     // SpeechRecognitionEngine::GetDesiredAudioChunkDurationMs().
165     ASSERT_EQ(0, duration_ms % ms_per_buffer);
166
167     const int n_buffers = duration_ms / ms_per_buffer;
168     for (int i = 0; i < n_buffers; ++i) {
169       base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
170           &FeedSingleBufferToAudioController,
171           scoped_refptr<media::TestAudioInputController>(controller),
172           buffer_size,
173           feed_with_noise));
174     }
175   }
176
177   SpeechRecognitionResult GetGoodSpeechResult() {
178     SpeechRecognitionResult result;
179     result.hypotheses.push_back(SpeechRecognitionHypothesis(
180         base::UTF8ToUTF16("Pictures of the moon"), 1.0F));
181     return result;
182   }
183
184   StreamingServerState streaming_server_state_;
185   scoped_ptr<MockGoogleStreamingServer> mock_streaming_server_;
186   media::TestAudioInputControllerFactory test_audio_input_controller_factory_;
187 };
188
189 // Simply loads the test page and checks if it was able to create a Speech
190 // Recognition object in JavaScript, to make sure the Web Speech API is enabled.
191 // http://crbug.com/396414
192 #if defined(OS_WIN) || defined(OS_MACOSX)
193 #define MAYBE_Precheck DISABLED_Precheck
194 #else
195 #define MAYBE_Precheck Precheck
196 #endif
197 IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, MAYBE_Precheck) {
198   NavigateToURLBlockUntilNavigationsComplete(
199       shell(), GetTestUrlFromFragment("precheck"), 2);
200
201   EXPECT_EQ(kIdle, streaming_server_state());
202   EXPECT_EQ("success", GetPageFragment());
203 }
204
205 IN_PROC_BROWSER_TEST_F(SpeechRecognitionBrowserTest, OneShotRecognition) {
206   NavigateToURLBlockUntilNavigationsComplete(
207       shell(), GetTestUrlFromFragment("oneshot"), 2);
208
209   EXPECT_EQ(kClientDisconnected, streaming_server_state());
210   EXPECT_EQ("goodresult1", GetPageFragment());
211 }
212
213 }  // namespace content