<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/singleton.h"
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "base/task.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
#include "chrome/browser/extensions/extension_tts_api_controller.h"
#include "chrome/browser/extensions/extension_tts_api_platform.h"

using base::DoubleToString;

namespace {
const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded.";
const int kSpeechCheckDelayIntervalMs = 100;
};

class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl {
 public:
  virtual bool PlatformImplAvailable() {
    return true;
  }

  virtual bool Speak(
      int utterance_id,
      const std::string& utterance,
      const std::string& lang,
      const UtteranceContinuousParameters& params);

  virtual bool StopSpeaking();

  virtual bool SendsEvent(TtsEventType event_type);

  // Get the single instance of this class.
  static ExtensionTtsPlatformImplChromeOs* GetInstance();

 private:
  ExtensionTtsPlatformImplChromeOs()
      : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
  virtual ~ExtensionTtsPlatformImplChromeOs() {}

  void PollUntilSpeechFinishes(int utterance_id);

  void AppendSpeakOption(std::string key,
                         std::string value,
                         std::string* options);

  int utterance_id_;
  int utterance_length_;
  ScopedRunnableMethodFactory<ExtensionTtsPlatformImplChromeOs> method_factory_;

  friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>;

  DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs);
};

// static
ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
  return ExtensionTtsPlatformImplChromeOs::GetInstance();
}

bool ExtensionTtsPlatformImplChromeOs::Speak(
    int utterance_id,
    const std::string& utterance,
    const std::string& lang,
    const UtteranceContinuousParameters& params) {
  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
  if (!cros_library->EnsureLoaded()) {
    set_error(kCrosLibraryNotLoadedError);
    return false;
  }

  utterance_id_ = utterance_id;
  utterance_length_ = utterance.size();

  std::string options;

  if (!lang.empty()) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyLocale,
        lang,
        &options);
  }

  if (params.rate >= 0.0) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyRate,
        DoubleToString(1.5 + params.rate * 2.5),
        &options);
  }

  if (params.pitch >= 0.0) {
    // The TTS service allows a range of 0 to 2 for speech pitch.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyPitch,
        DoubleToString(params.pitch),
        &options);
  }

  if (params.volume >= 0.0) {
    // The TTS service allows a range of 0 to 5 for speech volume.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyVolume,
        DoubleToString(params.volume * 5),
        &options);
  }

  if (!options.empty()) {
    cros_library->GetSpeechSynthesisLibrary()->SetSpeakProperties(
        options.c_str());
  }

  bool result =
      cros_library->GetSpeechSynthesisLibrary()->Speak(utterance.c_str());

  if (result) {
    ExtensionTtsController* controller = ExtensionTtsController::GetInstance();
    controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, std::string());
    PollUntilSpeechFinishes(utterance_id_);
  }

  return result;
}

bool ExtensionTtsPlatformImplChromeOs::StopSpeaking() {
  if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()->
        StopSpeaking();
  }

  set_error(kCrosLibraryNotLoadedError);
  return false;
}

bool ExtensionTtsPlatformImplChromeOs::SendsEvent(TtsEventType event_type) {
  return (event_type == TTS_EVENT_START ||
          event_type == TTS_EVENT_END ||
          event_type == TTS_EVENT_ERROR);
}

void ExtensionTtsPlatformImplChromeOs::PollUntilSpeechFinishes(
    int utterance_id) {
  if (utterance_id != utterance_id_) {
    // This utterance must have been interrupted or cancelled.
    return;
  }

  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
  ExtensionTtsController* controller = ExtensionTtsController::GetInstance();

  if (!cros_library->EnsureLoaded()) {
    controller->OnTtsEvent(
        utterance_id_, TTS_EVENT_ERROR, 0, kCrosLibraryNotLoadedError);
    return;
  }

  if (!cros_library->GetSpeechSynthesisLibrary()->IsSpeaking()) {
    controller->OnTtsEvent(
        utterance_id_, TTS_EVENT_END, utterance_length_, std::string());
    return;
  }

  MessageLoop::current()->PostDelayedTask(
      FROM_HERE, method_factory_.NewRunnableMethod(
          &ExtensionTtsPlatformImplChromeOs::PollUntilSpeechFinishes,
          utterance_id),
      kSpeechCheckDelayIntervalMs);
}

void ExtensionTtsPlatformImplChromeOs::AppendSpeakOption(
    std::string key,
    std::string value,
    std::string* options) {
  *options +=
      key +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyEquals +
      value +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyDelimiter;
}

// static
ExtensionTtsPlatformImplChromeOs*
ExtensionTtsPlatformImplChromeOs::GetInstance() {
  return Singleton<ExtensionTtsPlatformImplChromeOs>::get();
}
<commit_msg>Fix the speech rate and volume on Chrome OS; after switching the scale of these parameters in the TTS API, the conversion to Chrome OS values was done incorrectly and this fixes it.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/singleton.h"
#include "base/message_loop.h"
#include "base/string_number_conversions.h"
#include "base/task.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/speech_synthesis_library.h"
#include "chrome/browser/extensions/extension_tts_api_controller.h"
#include "chrome/browser/extensions/extension_tts_api_platform.h"

using base::DoubleToString;

namespace {
const char kCrosLibraryNotLoadedError[] = "Cros shared library not loaded.";
const int kSpeechCheckDelayIntervalMs = 100;
};

class ExtensionTtsPlatformImplChromeOs : public ExtensionTtsPlatformImpl {
 public:
  virtual bool PlatformImplAvailable() {
    return true;
  }

  virtual bool Speak(
      int utterance_id,
      const std::string& utterance,
      const std::string& lang,
      const UtteranceContinuousParameters& params);

  virtual bool StopSpeaking();

  virtual bool SendsEvent(TtsEventType event_type);

  // Get the single instance of this class.
  static ExtensionTtsPlatformImplChromeOs* GetInstance();

 private:
  ExtensionTtsPlatformImplChromeOs()
      : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
  virtual ~ExtensionTtsPlatformImplChromeOs() {}

  void PollUntilSpeechFinishes(int utterance_id);

  void AppendSpeakOption(std::string key,
                         std::string value,
                         std::string* options);

  int utterance_id_;
  int utterance_length_;
  ScopedRunnableMethodFactory<ExtensionTtsPlatformImplChromeOs> method_factory_;

  friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplChromeOs>;

  DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplChromeOs);
};

// static
ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() {
  return ExtensionTtsPlatformImplChromeOs::GetInstance();
}

bool ExtensionTtsPlatformImplChromeOs::Speak(
    int utterance_id,
    const std::string& utterance,
    const std::string& lang,
    const UtteranceContinuousParameters& params) {
  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
  if (!cros_library->EnsureLoaded()) {
    set_error(kCrosLibraryNotLoadedError);
    return false;
  }

  utterance_id_ = utterance_id;
  utterance_length_ = utterance.size();

  std::string options;

  if (!lang.empty()) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyLocale,
        lang,
        &options);
  }

  if (params.rate >= 0.0) {
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyRate,
        DoubleToString(params.rate),
        &options);
  }

  if (params.pitch >= 0.0) {
    // The TTS service allows a range of 0 to 2 for speech pitch.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyPitch,
        DoubleToString(params.pitch),
        &options);
  }

  if (params.volume >= 0.0) {
    // The Chrome OS TTS service allows a range of 0 to 5 for speech volume,
    // but 5 clips, so map to a range of 0...4.
    AppendSpeakOption(
        chromeos::SpeechSynthesisLibrary::kSpeechPropertyVolume,
        DoubleToString(params.volume * 4),
        &options);
  }

  if (!options.empty()) {
    cros_library->GetSpeechSynthesisLibrary()->SetSpeakProperties(
        options.c_str());
  }

  bool result =
      cros_library->GetSpeechSynthesisLibrary()->Speak(utterance.c_str());

  if (result) {
    ExtensionTtsController* controller = ExtensionTtsController::GetInstance();
    controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, std::string());
    PollUntilSpeechFinishes(utterance_id_);
  }

  return result;
}

bool ExtensionTtsPlatformImplChromeOs::StopSpeaking() {
  if (chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    return chromeos::CrosLibrary::Get()->GetSpeechSynthesisLibrary()->
        StopSpeaking();
  }

  set_error(kCrosLibraryNotLoadedError);
  return false;
}

bool ExtensionTtsPlatformImplChromeOs::SendsEvent(TtsEventType event_type) {
  return (event_type == TTS_EVENT_START ||
          event_type == TTS_EVENT_END ||
          event_type == TTS_EVENT_ERROR);
}

void ExtensionTtsPlatformImplChromeOs::PollUntilSpeechFinishes(
    int utterance_id) {
  if (utterance_id != utterance_id_) {
    // This utterance must have been interrupted or cancelled.
    return;
  }

  chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
  ExtensionTtsController* controller = ExtensionTtsController::GetInstance();

  if (!cros_library->EnsureLoaded()) {
    controller->OnTtsEvent(
        utterance_id_, TTS_EVENT_ERROR, 0, kCrosLibraryNotLoadedError);
    return;
  }

  if (!cros_library->GetSpeechSynthesisLibrary()->IsSpeaking()) {
    controller->OnTtsEvent(
        utterance_id_, TTS_EVENT_END, utterance_length_, std::string());
    return;
  }

  MessageLoop::current()->PostDelayedTask(
      FROM_HERE, method_factory_.NewRunnableMethod(
          &ExtensionTtsPlatformImplChromeOs::PollUntilSpeechFinishes,
          utterance_id),
      kSpeechCheckDelayIntervalMs);
}

void ExtensionTtsPlatformImplChromeOs::AppendSpeakOption(
    std::string key,
    std::string value,
    std::string* options) {
  *options +=
      key +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyEquals +
      value +
      chromeos::SpeechSynthesisLibrary::kSpeechPropertyDelimiter;
}

// static
ExtensionTtsPlatformImplChromeOs*
ExtensionTtsPlatformImplChromeOs::GetInstance() {
  return Singleton<ExtensionTtsPlatformImplChromeOs>::get();
}

{'fraction_non_alphanumeric': 0.10080363382250175, 'fraction_numerical': 0.004105520614954577, 'mean_word_length': 4.446717411988582, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4623295', 'n_tokens_mistral': 3603, 'n_tokens_neox': 3450, 'n_words': 672}