Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dlfcn.h> | |
| 6 #include <libspeechd.h> | |
| 7 #include <math.h> | |
| 8 | |
| 5 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" |
| 6 #include "chrome/browser/speech/extension_api/tts_extension_api_platform.h" | 10 #include "chrome/browser/speech/extension_api/tts_extension_api_platform.h" |
| 7 | 11 |
| 8 namespace { | 12 namespace { |
| 9 const char kNotSupportedError[] = | 13 const char kNotSupportedError[] = |
| 10 "Native speech synthesis not supported on this platform."; | 14 "Native speech synthesis not supported on this platform."; |
| 15 | |
| 16 // Speech dispatcher exports. | |
| 17 typedef SPDConnection* (*spd_open_func)(const char* client_name, | |
|
dmazzoni
2012/09/09 21:40:18
Extra spaces
| |
| 18 const char* connection_name, | |
| 19 const char* user_name, | |
| 20 SPDConnectionMode mode); | |
| 21 typedef int (*spd_say_func)(SPDConnection* connection, | |
| 22 SPDPriority priority, | |
| 23 const char* text); | |
| 24 typedef void (*spd_stop_func)(SPDConnection* connection); | |
| 25 typedef void (*spd_close_func)(SPDConnection* connection); | |
| 26 typedef int (*spd_set_notification_on_func)(SPDConnection* connection, | |
| 27 SPDNotification notification); | |
|
dmazzoni
2012/09/09 21:40:18
Fix indentation
| |
| 28 typedef int (*spd_set_voice_rate_func)(SPDConnection* connection, int rate); | |
| 29 typedef int (*spd_set_voice_pitch_func)(SPDConnection* connection, int pitch); | |
| 11 }; | 30 }; |
| 12 | 31 |
| 32 class SpeechDispatcherWrapper { | |
| 33 public: | |
| 34 static SPDNotificationType current_notification; | |
| 35 | |
| 36 SpeechDispatcherWrapper() : loaded_(false) { | |
|
dmazzoni
2012/09/09 21:40:18
This is long, so move the implementation below rat
| |
| 37 library_ = dlopen("libspeechd.so", RTLD_LAZY); | |
| 38 if (!library_) | |
| 39 return; | |
| 40 | |
| 41 spd_open = reinterpret_cast<spd_open_func>(dlsym(library_, "spd_open")); | |
| 42 if (!spd_open) | |
| 43 return; | |
| 44 | |
| 45 spd_say = reinterpret_cast<spd_say_func>(dlsym(library_, "spd_say")); | |
| 46 if (!spd_say) | |
| 47 return; | |
| 48 | |
| 49 spd_stop = reinterpret_cast<spd_stop_func>(dlsym(library_, "spd_stop")); | |
| 50 if (!spd_stop) | |
| 51 return; | |
| 52 | |
| 53 spd_close = reinterpret_cast<spd_close_func>(dlsym(library_, "spd_close")); | |
| 54 if (!spd_close) | |
| 55 return; | |
| 56 | |
| 57 conn_ = spd_open("chrome", "extension_api", NULL, SPD_MODE_THREADED); | |
| 58 if (!conn_) | |
| 59 return; | |
| 60 | |
| 61 spd_set_notification_on = reinterpret_cast<spd_set_notification_on_func>( | |
| 62 dlsym(library_, "spd_set_notification_on")); | |
| 63 if (!spd_set_notification_on) | |
| 64 return; | |
| 65 | |
| 66 spd_set_voice_rate = reinterpret_cast<spd_set_voice_rate_func>( | |
| 67 dlsym(library_, "spd_set_voice_rate")); | |
| 68 if (!spd_set_voice_rate) | |
| 69 return; | |
| 70 | |
| 71 spd_set_voice_pitch = reinterpret_cast<spd_set_voice_pitch_func>( | |
| 72 dlsym(library_, "spd_set_voice_pitch")); | |
| 73 if (!spd_set_voice_pitch) | |
| 74 return; | |
| 75 | |
| 76 // Register callbacks for all events. | |
| 77 conn_->callback_begin = | |
| 78 conn_->callback_end = | |
| 79 conn_->callback_cancel = | |
| 80 conn_->callback_pause = | |
| 81 conn_->callback_resume = | |
| 82 &SpeechDispatcherWrapper::NotificationCallback; | |
| 83 | |
| 84 spd_set_notification_on(conn_, SPD_BEGIN); | |
| 85 spd_set_notification_on(conn_, SPD_END); | |
| 86 spd_set_notification_on(conn_, SPD_CANCEL); | |
| 87 spd_set_notification_on(conn_, SPD_PAUSE); | |
| 88 spd_set_notification_on(conn_, SPD_RESUME); | |
| 89 | |
| 90 loaded_ = true; | |
| 91 } | |
| 92 | |
| 93 ~SpeechDispatcherWrapper() { | |
| 94 if (conn_) { | |
| 95 spd_close(conn_); | |
| 96 conn_ = NULL; | |
| 97 } | |
| 98 | |
| 99 if (library_) { | |
| 100 dlclose(library_); | |
| 101 library_ = NULL; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 bool Speak(const char* text) { | |
| 106 if (!loaded()) | |
| 107 return false; | |
| 108 | |
| 109 spd_say(conn_, SPD_TEXT, text); | |
| 110 return true; | |
| 111 } | |
| 112 | |
| 113 bool IsSpeaking() { | |
| 114 return SpeechDispatcherWrapper::current_notification == SPD_EVENT_BEGIN; | |
| 115 } | |
| 116 | |
| 117 bool StopSpeaking() { | |
| 118 if (!loaded()) | |
| 119 return false; | |
| 120 spd_stop(conn_); | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 void SetRate(int rate) { | |
| 125 spd_set_voice_rate(conn_, rate); | |
| 126 } | |
| 127 | |
| 128 void SetPitch(int pitch) { | |
| 129 spd_set_voice_pitch(conn_, pitch); | |
| 130 } | |
| 131 | |
| 132 // States whether Speech Dispatcher loaded successfully. | |
| 133 bool loaded() { | |
| 134 return loaded_; | |
| 135 } | |
| 136 | |
| 137 private: | |
| 138 static void NotificationCallback(size_t msg_id, | |
| 139 size_t client_id, | |
| 140 SPDNotificationType type); | |
| 141 | |
| 142 // Interface bindings. | |
| 143 spd_open_func spd_open; | |
| 144 spd_say_func spd_say; | |
| 145 spd_stop_func spd_stop; | |
| 146 spd_close_func spd_close; | |
| 147 spd_set_notification_on_func spd_set_notification_on; | |
| 148 spd_set_voice_rate_func spd_set_voice_rate; | |
| 149 spd_set_voice_pitch_func spd_set_voice_pitch; | |
| 150 | |
| 151 bool loaded_; | |
| 152 void* library_; | |
| 153 SPDConnection* conn_; | |
| 154 DISALLOW_COPY_AND_ASSIGN(SpeechDispatcherWrapper); | |
| 155 }; | |
| 156 SPDNotificationType SpeechDispatcherWrapper::current_notification = | |
|
dmazzoni
2012/09/09 21:40:18
Add a newline before this, and add a comment that
| |
| 157 SPD_EVENT_END; | |
| 158 | |
| 13 class ExtensionTtsPlatformImplLinux : public ExtensionTtsPlatformImpl { | 159 class ExtensionTtsPlatformImplLinux : public ExtensionTtsPlatformImpl { |
| 14 public: | 160 public: |
| 15 virtual bool PlatformImplAvailable() { | 161 virtual bool PlatformImplAvailable() { |
| 16 return false; | 162 return spd_.loaded(); |
| 17 } | 163 } |
| 18 | 164 |
| 19 virtual bool Speak( | 165 virtual bool Speak( |
| 20 int utterance_id, | 166 int utterance_id, |
| 21 const std::string& utterance, | 167 const std::string& utterance, |
| 22 const std::string& lang, | 168 const std::string& lang, |
| 23 const UtteranceContinuousParameters& params) { | 169 const UtteranceContinuousParameters& params) { |
| 24 error_ = kNotSupportedError; | 170 if (!spd_.loaded()) { |
| 25 return false; | 171 error_ = kNotSupportedError; |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 if (params.rate >= 0.0 && params.rate <= 10.0) | |
| 176 spd_.SetRate(100 * log10(params.rate)); | |
|
dmazzoni
2012/09/09 21:40:18
Documentation for how you came up with this mappin
| |
| 177 if (params.pitch >= 0.0 && params.pitch <= 10.0) | |
| 178 spd_.SetPitch(100 * log10(params.pitch)); | |
| 179 | |
| 180 utterance_ = utterance; | |
| 181 utterance_id_ = utterance_id; | |
| 182 | |
| 183 spd_.Speak(utterance.c_str()); | |
| 184 return true; | |
| 26 } | 185 } |
| 27 | 186 |
| 28 virtual bool StopSpeaking() { | 187 virtual bool StopSpeaking() { |
| 29 error_ = kNotSupportedError; | 188 return spd_.StopSpeaking(); |
| 30 return false; | |
| 31 } | 189 } |
| 32 | 190 |
| 33 virtual bool IsSpeaking() { | 191 virtual bool IsSpeaking() { |
| 34 error_ = kNotSupportedError; | 192 return spd_.IsSpeaking(); |
| 35 return false; | |
| 36 } | 193 } |
| 37 | 194 |
| 38 virtual bool SendsEvent(TtsEventType event_type) { | 195 virtual bool SendsEvent(TtsEventType event_type) { |
| 39 return false; | 196 return (event_type == TTS_EVENT_START || event_type == TTS_EVENT_END); |
| 40 } | 197 } |
| 41 | 198 |
| 42 // Get the single instance of this class. | 199 // Get the single instance of this class. |
| 43 static ExtensionTtsPlatformImplLinux* GetInstance() { | 200 static ExtensionTtsPlatformImplLinux* GetInstance() { |
| 44 return Singleton<ExtensionTtsPlatformImplLinux>::get(); | 201 return Singleton<ExtensionTtsPlatformImplLinux>::get(); |
| 45 } | 202 } |
| 46 | 203 |
| 204 void OnSpeechEvent(SPDNotificationType type) { | |
| 205 ExtensionTtsController* controller = ExtensionTtsController::GetInstance(); | |
| 206 switch (type) { | |
| 207 case SPD_EVENT_BEGIN: | |
| 208 controller->OnTtsEvent( | |
| 209 utterance_id_, TTS_EVENT_START, 0, std::string()); | |
| 210 break; | |
| 211 case SPD_EVENT_END: | |
| 212 controller->OnTtsEvent( | |
| 213 utterance_id_, TTS_EVENT_END, utterance_.size(), std::string()); | |
| 214 break; | |
| 215 // TODO(dtseng): Unimplemented. | |
|
dmazzoni
2012/09/09 21:40:18
Can you implement these as part of this CL? They s
| |
| 216 case SPD_EVENT_INDEX_MARK: | |
| 217 case SPD_EVENT_CANCEL: | |
| 218 case SPD_EVENT_PAUSE: | |
| 219 case SPD_EVENT_RESUME: | |
| 220 break; | |
| 221 } | |
| 222 } | |
| 223 | |
| 47 private: | 224 private: |
| 48 ExtensionTtsPlatformImplLinux() {} | 225 ExtensionTtsPlatformImplLinux(): utterance_id_(0) {} |
| 49 virtual ~ExtensionTtsPlatformImplLinux() {} | 226 virtual ~ExtensionTtsPlatformImplLinux() {} |
| 50 | 227 |
| 228 SpeechDispatcherWrapper spd_; | |
| 229 | |
| 230 // These apply to the current utterance only. | |
| 231 std::string utterance_; | |
| 232 int utterance_id_; | |
| 233 | |
| 51 friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplLinux>; | 234 friend struct DefaultSingletonTraits<ExtensionTtsPlatformImplLinux>; |
| 52 | 235 |
| 53 DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplLinux); | 236 DISALLOW_COPY_AND_ASSIGN(ExtensionTtsPlatformImplLinux); |
| 54 }; | 237 }; |
| 55 | 238 |
| 56 // static | 239 // static |
| 57 ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { | 240 ExtensionTtsPlatformImpl* ExtensionTtsPlatformImpl::GetInstance() { |
| 58 return ExtensionTtsPlatformImplLinux::GetInstance(); | 241 return ExtensionTtsPlatformImplLinux::GetInstance(); |
| 59 } | 242 } |
| 243 | |
| 244 // static | |
| 245 void SpeechDispatcherWrapper::NotificationCallback( | |
| 246 size_t msg_id, size_t client_id, SPDNotificationType type) { | |
| 247 SpeechDispatcherWrapper::current_notification = type; | |
| 248 ExtensionTtsPlatformImplLinux::GetInstance()->OnSpeechEvent(type); | |
| 249 } | |
| OLD | NEW |