// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/speech/cobalt_speech_recognizer.h"

#include "base/bind.h"
#include "cobalt/base/tokens.h"
#if defined(ENABLE_FAKE_MICROPHONE)
#include "cobalt/speech/microphone_fake.h"
#include "cobalt/speech/url_fetcher_fake.h"
#endif  // defined(ENABLE_FAKE_MICROPHONE)
#include "cobalt/speech/microphone_manager.h"
#include "cobalt/speech/speech_recognition_error.h"
#if defined(SB_USE_SB_MICROPHONE)
#include "cobalt/speech/microphone_starboard.h"
#endif  // defined(SB_USE_SB_MICROPHONE)
#include "net/url_request/url_fetcher.h"

namespace cobalt {
namespace speech {

namespace {
const int kSampleRate = 16000;
const float kAudioPacketDurationInSeconds = 0.1f;

scoped_ptr<net::URLFetcher> CreateURLFetcher(
    const GURL& url, net::URLFetcher::RequestType request_type,
    net::URLFetcherDelegate* delegate) {
  return make_scoped_ptr<net::URLFetcher>(
      net::URLFetcher::Create(url, request_type, delegate));
}

scoped_ptr<Microphone> CreateMicrophone(int buffer_size_bytes) {
#if defined(SB_USE_SB_MICROPHONE)
  return make_scoped_ptr<Microphone>(
      new MicrophoneStarboard(kSampleRate, buffer_size_bytes));
#else
  UNREFERENCED_PARAMETER(buffer_size_bytes);
  return scoped_ptr<Microphone>();
#endif  // defined(SB_USE_SB_MICROPHONE)
}

#if defined(SB_USE_SB_MICROPHONE)
#if defined(ENABLE_FAKE_MICROPHONE)
scoped_ptr<net::URLFetcher> CreateFakeURLFetcher(
    const GURL& url, net::URLFetcher::RequestType request_type,
    net::URLFetcherDelegate* delegate) {
  return make_scoped_ptr<net::URLFetcher>(
      new URLFetcherFake(url, request_type, delegate));
}

scoped_ptr<Microphone> CreateFakeMicrophone(const Microphone::Options& options,
                                            int /*buffer_size_bytes*/) {
  return make_scoped_ptr<Microphone>(new MicrophoneFake(options));
}
#endif  // defined(ENABLE_FAKE_MICROPHONE)
#endif  // defined(SB_USE_SB_MICROPHONE)
}  // namespace

CobaltSpeechRecognizer::CobaltSpeechRecognizer(
    network::NetworkModule* network_module,
    const Microphone::Options& microphone_options,
    const EventCallback& event_callback)
    : SpeechRecognizer(event_callback), endpointer_delegate_(kSampleRate) {
  UNREFERENCED_PARAMETER(microphone_options);

  GoogleSpeechService::URLFetcherCreator url_fetcher_creator =
      base::Bind(&CreateURLFetcher);
  MicrophoneManager::MicrophoneCreator microphone_creator =
      base::Bind(&CreateMicrophone);

#if defined(SB_USE_SB_MICROPHONE)
#if defined(ENABLE_FAKE_MICROPHONE)
  if (microphone_options.enable_fake_microphone) {
    // If fake microphone is enabled, fake URL fetchers should be enabled as
    // well.
    url_fetcher_creator = base::Bind(&CreateFakeURLFetcher);
    microphone_creator = base::Bind(&CreateFakeMicrophone, microphone_options);
  }
#endif  // defined(ENABLE_FAKE_MICROPHONE)
#endif  // defined(SB_USE_SB_MICROPHONE)

  service_.reset(new GoogleSpeechService(
      network_module,
      base::Bind(&CobaltSpeechRecognizer::OnRecognizerEvent,
                 base::Unretained(this)),
      url_fetcher_creator));
  microphone_manager_.reset(new MicrophoneManager(
      base::Bind(&CobaltSpeechRecognizer::OnDataReceived,
                 base::Unretained(this)),
      base::Bind(&CobaltSpeechRecognizer::OnDataCompletion,
                 base::Unretained(this)),
      base::Bind(&CobaltSpeechRecognizer::OnMicError, base::Unretained(this)),
      microphone_creator));
}

CobaltSpeechRecognizer::~CobaltSpeechRecognizer() {}

void CobaltSpeechRecognizer::Start(const SpeechRecognitionConfig& config) {
  service_->Start(config, kSampleRate);
  microphone_manager_->Open();
  endpointer_delegate_.Start();
}

void CobaltSpeechRecognizer::Stop() {
  endpointer_delegate_.Stop();
  microphone_manager_->Close();
  service_->Stop();
  RunEventCallback(new dom::Event(base::Tokens::soundend()));
}

void CobaltSpeechRecognizer::OnDataReceived(
    scoped_ptr<ShellAudioBus> audio_bus) {
  if (endpointer_delegate_.IsFirstTimeSoundStarted(*audio_bus)) {
    RunEventCallback(new dom::Event(base::Tokens::soundstart()));
  }
  service_->RecognizeAudio(audio_bus.Pass(), false);
}

void CobaltSpeechRecognizer::OnDataCompletion() {
  // The encoder requires a non-empty final buffer, so encoding a packet of
  // silence at the end in case encoder had no data already.
  size_t dummy_frames =
      static_cast<size_t>(kSampleRate * kAudioPacketDurationInSeconds);
  scoped_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus(
      1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kInterleaved));
  dummy_audio_bus->ZeroAllFrames();
  service_->RecognizeAudio(dummy_audio_bus.Pass(), true);
}

void CobaltSpeechRecognizer::OnRecognizerEvent(
    const scoped_refptr<dom::Event>& event) {
  RunEventCallback(event);
}

void CobaltSpeechRecognizer::OnMicError(
    MicrophoneManager::MicrophoneError error,
    const std::string& error_message) {
  // An error is occured in Mic, so stop the energy endpointer and recognizer.

  SpeechRecognitionErrorCode speech_error_code =
      kSpeechRecognitionErrorCodeAborted;
  switch (error) {
    case MicrophoneManager::MicrophoneError::kAborted:
      speech_error_code = kSpeechRecognitionErrorCodeAborted;
      break;
    case MicrophoneManager::MicrophoneError::kAudioCapture:
      speech_error_code = kSpeechRecognitionErrorCodeAudioCapture;
      break;
  }
  scoped_refptr<dom::Event> event(
      new SpeechRecognitionError(speech_error_code, error_message));
  endpointer_delegate_.Stop();
  service_->Stop();
  RunEventCallback(event);
}

}  // namespace speech
}  // namespace cobalt
