| Index: content/renderer/speech_recognition_dispatcher.cc
|
| diff --git a/content/renderer/speech_recognition_dispatcher.cc b/content/renderer/speech_recognition_dispatcher.cc
|
| index 178abf4610c286c751047ff46ec252089f2946bb..d176acc25fdfb3ccf81925785ffdd4d1edb97426 100644
|
| --- a/content/renderer/speech_recognition_dispatcher.cc
|
| +++ b/content/renderer/speech_recognition_dispatcher.cc
|
| @@ -7,7 +7,9 @@
|
| #include "base/basictypes.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "content/common/speech_recognition_messages.h"
|
| +#include "content/renderer/media/media_stream_audio_source.h"
|
| #include "content/renderer/render_view_impl.h"
|
| +#include "content/renderer/speech_recognition_audio_source_provider.h"
|
| #include "third_party/WebKit/public/platform/WebString.h"
|
| #include "third_party/WebKit/public/platform/WebVector.h"
|
| #include "third_party/WebKit/public/web/WebSpeechGrammar.h"
|
| @@ -29,6 +31,9 @@ SpeechRecognitionDispatcher::SpeechRecognitionDispatcher(
|
| RenderViewImpl* render_view)
|
| : RenderViewObserver(render_view),
|
| recognizer_client_(NULL),
|
| + audio_track_set_(false),
|
| + is_allowed_audio_track_(false),
|
| + render_loop_(base::MessageLoopProxy::current()),
|
| next_id_(1) {
|
| }
|
|
|
| @@ -36,6 +41,7 @@ SpeechRecognitionDispatcher::~SpeechRecognitionDispatcher() {
|
| }
|
|
|
| void SpeechRecognitionDispatcher::AbortAllRecognitions() {
|
| + audio_source_provider_.reset();
|
| Send(new SpeechRecognitionHostMsg_AbortAllRequests(
|
| routing_id()));
|
| }
|
| @@ -53,11 +59,39 @@ bool SpeechRecognitionDispatcher::OnMessageReceived(
|
| IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_Ended, OnRecognitionEnded)
|
| IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_ResultRetrieved,
|
| OnResultsRetrieved)
|
| + IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioTrackReady,
|
| + OnAudioTrackReady)
|
| + IPC_MESSAGE_HANDLER(SpeechRecognitionMsg_AudioChunkProcessed,
|
| + OnAudioChunkProcessed)
|
| IPC_MESSAGE_UNHANDLED(handled = false)
|
| IPC_END_MESSAGE_MAP()
|
| return handled;
|
| }
|
|
|
| +void SpeechRecognitionDispatcher::attach(
|
| + const blink::WebSpeechRecognitionHandle& handle,
|
| + const blink::WebMediaStreamTrack& audio_track,
|
| + blink::WebSpeechRecognizerClient* recognizer_client) {
|
| +
|
| + // Check if track is from an allowed source (microphone only for now)
|
| + // TODO(burnik): externalize the policy of allowed track types from dispatcher
|
| + DCHECK(audio_track.source().type() == blink::WebMediaStreamSource::TypeAudio);
|
| + MediaStreamAudioSource* native_source =
|
| + static_cast <MediaStreamAudioSource*>(audio_track.source().extraData());
|
| + StreamDeviceInfo device_info = native_source->device_info();
|
| + is_allowed_audio_track_ = (device_info.device.type ==
|
| + content::MEDIA_DEVICE_AUDIO_CAPTURE);
|
| +
|
| + audio_track_ = audio_track;
|
| + audio_track_set_ = true;
|
| +}
|
| +
|
| +void SpeechRecognitionDispatcher::detach(
|
| + const blink::WebSpeechRecognitionHandle& handle,
|
| + blink::WebSpeechRecognizerClient* recognizer_client) {
|
| + audio_track_set_ = false;
|
| +}
|
| +
|
| void SpeechRecognitionDispatcher::start(
|
| const WebSpeechRecognitionHandle& handle,
|
| const WebSpeechRecognitionParams& params,
|
| @@ -65,6 +99,17 @@ void SpeechRecognitionDispatcher::start(
|
| DCHECK(!recognizer_client_ || recognizer_client_ == recognizer_client);
|
| recognizer_client_ = recognizer_client;
|
|
|
| + // destroy any previous instance not to starve it waiting on chunk ACKs
|
| + audio_source_provider_.reset();
|
| +
|
| + if (audio_track_set_ && !is_allowed_audio_track_) {
|
| + // notify user that the track used is not supported
|
| + recognizer_client_->didReceiveError(
|
| + handle,
|
| + WebString("Provided audioTrack is not supported. Ignoring track."),
|
| + WebSpeechRecognizerClient::NotAllowedError);
|
| + }
|
| +
|
| SpeechRecognitionHostMsg_StartRequest_Params msg_params;
|
| for (size_t i = 0; i < params.grammars().size(); ++i) {
|
| const WebSpeechGrammar& grammar = params.grammars()[i];
|
| @@ -78,6 +123,8 @@ void SpeechRecognitionDispatcher::start(
|
| msg_params.origin_url = params.origin().toString().utf8();
|
| msg_params.render_view_id = routing_id();
|
| msg_params.request_id = GetOrCreateIDForHandle(handle);
|
| + // fall back to default input when the track is not allowed
|
| + msg_params.using_audio_track = (audio_track_set_ && is_allowed_audio_track_);
|
| // The handle mapping will be removed in |OnRecognitionEnd|.
|
| Send(new SpeechRecognitionHostMsg_StartRequest(msg_params));
|
| }
|
| @@ -85,6 +132,7 @@ void SpeechRecognitionDispatcher::start(
|
| void SpeechRecognitionDispatcher::stop(
|
| const WebSpeechRecognitionHandle& handle,
|
| WebSpeechRecognizerClient* recognizer_client) {
|
| + audio_source_provider_.reset();
|
| // Ignore a |stop| issued without a matching |start|.
|
| if (recognizer_client_ != recognizer_client || !HandleExists(handle))
|
| return;
|
| @@ -95,6 +143,7 @@ void SpeechRecognitionDispatcher::stop(
|
| void SpeechRecognitionDispatcher::abort(
|
| const WebSpeechRecognitionHandle& handle,
|
| WebSpeechRecognizerClient* recognizer_client) {
|
| + audio_source_provider_.reset();
|
| // Ignore an |abort| issued without a matching |start|.
|
| if (recognizer_client_ != recognizer_client || !HandleExists(handle))
|
| return;
|
| @@ -154,6 +203,7 @@ void SpeechRecognitionDispatcher::OnErrorOccurred(
|
| recognizer_client_->didReceiveNoMatch(GetHandleFromID(request_id),
|
| WebSpeechRecognitionResult());
|
| } else {
|
| + audio_source_provider_.reset();
|
| recognizer_client_->didReceiveError(
|
| GetHandleFromID(request_id),
|
| WebString(), // TODO(primiano): message?
|
| @@ -174,6 +224,7 @@ void SpeechRecognitionDispatcher::OnRecognitionEnded(int request_id) {
|
| // didEnd may call back synchronously to start a new recognition session,
|
| // and we don't want to delete the handle from the map after that happens.
|
| handle_map_.erase(request_id);
|
| + audio_source_provider_.reset();
|
| recognizer_client_->didEnd(handle);
|
| }
|
| }
|
| @@ -211,6 +262,75 @@ void SpeechRecognitionDispatcher::OnResultsRetrieved(
|
| GetHandleFromID(request_id), final, provisional);
|
| }
|
|
|
| +void SpeechRecognitionDispatcher::OnAudioError(int request_id){
|
| + // Browser gets notified on render thread
|
| + if (!render_loop_->BelongsToCurrentThread()) {
|
| + render_loop_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SpeechRecognitionDispatcher::OnAudioError,
|
| + base::Unretained(this), request_id));
|
| + return;
|
| + }
|
| + audio_source_provider_.reset();
|
| +}
|
| +
|
| +void SpeechRecognitionDispatcher::OnAudioTrackReady(
|
| + int request_id,
|
| + const media::AudioParameters& params,
|
| + base::SharedMemoryHandle handle,
|
| + uint32 length) {
|
| +
|
| + // TODO(burnik): Log and DCHECK(!audio_source_provider_).
|
| + if (audio_track_.isNull()) {
|
| + audio_source_provider_.reset();
|
| + return;
|
| + }
|
| +
|
| + audio_source_provider_.reset(
|
| + new SpeechRecognitionAudioSourceProvider(
|
| + audio_track_, params, handle, length,
|
| + base::Bind(&SpeechRecognitionDispatcher::OnAudioData,
|
| + base::Unretained(this), request_id),
|
| + base::Bind(&SpeechRecognitionDispatcher::OnAudioError,
|
| + base::Unretained(this), request_id)));
|
| +}
|
| +
|
| +void SpeechRecognitionDispatcher::OnAudioChunkProcessed(
|
| + int request_id) {
|
| +
|
| + // TODO(burnik): Log and DCHECK(!audio_source_provider_).
|
| + if (audio_track_.isNull())
|
| + return;
|
| +
|
| + // discard any message to a destroyed instance
|
| + if(!audio_source_provider_.get())
|
| + return;
|
| +
|
| + audio_source_provider_->NotifyAudioBusConsumed();
|
| +}
|
| +
|
| +
|
| +// TODO(burnik): Consider using sync_socket
|
| +void SpeechRecognitionDispatcher::OnAudioData(int request_id) {
|
| + // Browser gets notified on render thread
|
| + if (!render_loop_->BelongsToCurrentThread()) {
|
| + render_loop_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&SpeechRecognitionDispatcher::OnAudioData,
|
| + base::Unretained(this), request_id));
|
| + return;
|
| + }
|
| + // If the handle isn't found in the array, which might happen if the
|
| + // recognition has been ended by the browser, delete the
|
| + // |audio_source_provider_|.
|
| + HandleMap::iterator iter = handle_map_.find(request_id);
|
| + if (iter == handle_map_.end()) {
|
| + audio_source_provider_.reset();
|
| + return;
|
| + }
|
| +
|
| + Send(new SpeechRecognitionHostMsg_OnAudioTrackData(routing_id(), request_id));
|
| +}
|
|
|
| int SpeechRecognitionDispatcher::GetOrCreateIDForHandle(
|
| const WebSpeechRecognitionHandle& handle) {
|
|
|