| // Copyright 2017 The Cobalt Authors. 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 "starboard/shared/speechd/speechd_internal.h" | 
 |  | 
 | #if defined(ADDRESS_SANITIZER) | 
 | // By default, Leak Sanitizer and Address Sanitizer is expected to exist | 
 | // together. However, this is not true for all platforms. | 
 | // HAS_LEAK_SANTIZIER=0 explicitly removes the Leak Sanitizer from code. | 
 | #ifndef HAS_LEAK_SANITIZER | 
 | #define HAS_LEAK_SANITIZER 1 | 
 | #endif  // HAS_LEAK_SANITIZER | 
 | #endif  // defined(ADDRESS_SANITIZER) | 
 |  | 
 | #if HAS_LEAK_SANITIZER | 
 | #include <sanitizer/lsan_interface.h> | 
 | #endif  // HAS_LEAK_SANITIZER | 
 |  | 
 | #include "starboard/once.h" | 
 | #include "starboard/shared/starboard/application.h" | 
 |  | 
 | namespace starboard { | 
 | namespace shared { | 
 | namespace speechd { | 
 | namespace { | 
 | SbOnceControl init_once = SB_ONCE_INITIALIZER; | 
 | }  // namespace | 
 |  | 
 | SpeechDispatcher* SpeechDispatcher::instance = NULL; | 
 |  | 
 | // static | 
 | SpeechDispatcher* SpeechDispatcher::Get() { | 
 |   bool result = SbOnce(&init_once, &SpeechDispatcher::Initialize); | 
 |   SB_DCHECK(result); | 
 |   SB_DCHECK(instance); | 
 |   return instance; | 
 | } | 
 |  | 
 | SpeechDispatcher::SpeechDispatcher() { | 
 |   const char* client_name = "starboard_application"; | 
 |  | 
 | #if HAS_LEAK_SANITIZER | 
 |   // spd_open leaks memory even though spd_close is eventually called. | 
 |   // Chromium's text-to-speech system for linux ran into the same issue: | 
 |   // http://crbug.com/317360 | 
 |   __lsan_disable(); | 
 | #endif  // HAS_LEAK_SANITIZER | 
 |   connection_ = spd_open(client_name, NULL, NULL, SPD_MODE_THREADED); | 
 | #if HAS_LEAK_SANITIZER | 
 |   __lsan_enable(); | 
 | #endif  // HAS_LEAK_SANITIZER | 
 |  | 
 |   if (!connection_) { | 
 |     SB_DLOG(ERROR) << "Failed to initialize SpeechDispatcher."; | 
 |   } | 
 |   if (!SetLanguage(SbSystemGetLocaleId())) { | 
 |     SB_DLOG(ERROR) << "Unable to set language to current locale."; | 
 |   } | 
 | } | 
 |  | 
 | SpeechDispatcher::~SpeechDispatcher() { | 
 |   SB_DLOG(INFO) << "Closing Speech Dispatcher."; | 
 |   if (connection_) { | 
 |     spd_close(connection_); | 
 |   } | 
 | } | 
 |  | 
 | bool SpeechDispatcher::SetLanguage(const char* language) { | 
 |   ScopedLock lock(lock_); | 
 |   if (connection_) { | 
 |     int result = spd_set_language(connection_, language); | 
 |     return result == 0; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | void SpeechDispatcher::Speak(const char* text) { | 
 |   ScopedLock lock(lock_); | 
 |   if (connection_ && text && *text) { | 
 |     // Priority SPD_MESSAGE will be queued with other text of same priority. | 
 |     int result = spd_say(connection_, SPD_MESSAGE, text); | 
 |     if (result < 0) { | 
 |       SB_DLOG(ERROR) << "Failed to speak: " << text; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void SpeechDispatcher::Cancel() { | 
 |   ScopedLock lock(lock_); | 
 |   if (connection_) { | 
 |     int result = spd_cancel(connection_); | 
 |     if (result != 0) { | 
 |       SB_DLOG(ERROR) << "Failed to cancel speech."; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | // static | 
 | void SpeechDispatcher::Initialize() { | 
 |   starboard::Application* application = starboard::Application::Get(); | 
 |   if (application) { | 
 |     instance = new SpeechDispatcher(); | 
 |     application->RegisterTeardownCallback(SpeechDispatcher::Destroy); | 
 |   } | 
 | } | 
 |  | 
 | // static | 
 | void SpeechDispatcher::Destroy() { | 
 |   delete instance; | 
 |   instance = NULL; | 
 | } | 
 |  | 
 | }  // namespace speechd | 
 | }  // namespace shared | 
 | }  // namespace starboard |